diff --git a/tests/run.yml b/tests/run.yml
index 032262a4421f3d4bf4cde05de19a0ab5dbca7576..dc4eb1665c5c1123f616be2b27f54d4cf5c923da 100644
--- a/tests/run.yml
+++ b/tests/run.yml
@@ -188,6 +188,24 @@
               dest: ironic-agent.kernel
       when: scenario == "ironic"
 
+    - block:
+        - name: ensure octavia config directory exists
+          file:
+            path: /etc/kolla/config/octavia
+            state: directory
+            mode: 0777
+
+        - name: create dummy TLS certificates for octavia
+          file:
+            path: "/etc/kolla/config/octavia/{{ item }}"
+            state: touch
+          with_items:
+            - client.cert-and-key.pem
+            - client_ca.cert.pem
+            - server_ca.cert.pem
+            - server_ca.key.pem
+      when: scenario == 'magnum'
+
     - name: ensure /etc/ansible exists
       file:
         path: /etc/ansible
@@ -405,6 +423,13 @@
             chdir: "{{ kolla_ansible_src_dir }}"
           when: scenario == "ironic"
 
+        - name: Run test-magnum.sh script
+          script:
+            cmd: test-magnum.sh
+            executable: /bin/bash
+            chdir: "{{ kolla_ansible_src_dir }}"
+          when: scenario == "magnum"
+
         - name: Run test-masakari.sh script
           script:
             cmd: test-masakari.sh
diff --git a/tests/setup_gate.sh b/tests/setup_gate.sh
index 5a63b3cd276a8274c8eb398cdf7c496eee0dd171..c1d505fdcf73077645f493c4adff252513ba20b3 100755
--- a/tests/setup_gate.sh
+++ b/tests/setup_gate.sh
@@ -17,6 +17,9 @@ function setup_openstack_clients {
     if [[ $SCENARIO == ironic ]]; then
         packages+=(python-ironicclient python-ironic-inspector-client)
     fi
+    if [[ $SCENARIO == magnum ]]; then
+        packages+=(python-magnumclient python-octaviaclient)
+    fi
     if [[ $SCENARIO == masakari ]]; then
         packages+=(python-masakariclient)
     fi
@@ -59,6 +62,9 @@ function prepare_images {
     if [[ $SCENARIO == "ironic" ]]; then
         GATE_IMAGES+=",^dnsmasq,^ironic,^iscsid"
     fi
+    if [[ $SCENARIO == "magnum" ]]; then
+        GATE_IMAGES+=",^magnum,^octavia"
+    fi
     if [[ $SCENARIO == "masakari" ]]; then
         GATE_IMAGES+=",^masakari"
     fi
diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2
index a7641fdf0057dc4c17cdf56e1a0ea3e8a2fa7d9f..2740ab1ef5ae6287f2e74aa91cb7e3733a55fbf1 100644
--- a/tests/templates/globals-default.j2
+++ b/tests/templates/globals-default.j2
@@ -151,3 +151,8 @@ enable_grafana: "yes"
 enable_prometheus: "yes"
 enable_prometheus_openstack_exporter: "no"
 {% endif %}
+
+{% if scenario == "magnum" %}
+enable_magnum: "yes"
+enable_octavia: "yes"
+{% endif %}
diff --git a/tests/test-magnum.sh b/tests/test-magnum.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9519fba25795c2e4fec7b0ab12048ad015fadb5c
--- /dev/null
+++ b/tests/test-magnum.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Test deployment of magnum and octavia.
+
+set -o xtrace
+set -o errexit
+
+# Enable unbuffered output for Ansible in Jenkins.
+export PYTHONUNBUFFERED=1
+
+
+function test_magnum_clusters {
+    openstack coe cluster list
+    openstack coe cluster template list
+}
+
+function test_octavia {
+    openstack loadbalancer list
+}
+
+function test_magnum_logged {
+    . /etc/kolla/admin-openrc.sh
+    . ~/openstackclient-venv/bin/activate
+    test_magnum_clusters
+    test_octavia
+}
+
+function test_magnum {
+    echo "Testing Magnum and Octavia"
+    test_magnum_logged > /tmp/logs/ansible/test-magnum 2>&1
+    result=$?
+    if [[ $result != 0 ]]; then
+        echo "Testing Magnum and Octavia failed. See ansible/test-magnum for details"
+    else
+        echo "Successfully tested Magnum and Octavia. See ansible/test-magnum for details"
+    fi
+    return $result
+}
+
+test_magnum
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index f6b286ace627538962544d292d0a4dce015d59c3..42dad4884cef7b556f39a7592763998af068c326 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -126,6 +126,17 @@
       - name: github.com/ceph/ceph-ansible
         override-checkout: v5.0.0
 
+- job:
+    name: kolla-ansible-magnum-base
+    parent: kolla-ansible-base
+    voting: false
+    files:
+      - ^ansible/roles/(magnum|octavia)/
+      - ^tests/test-dashboard.sh
+      - ^tests/test-magnum.sh
+    vars:
+      scenario: magnum
+
 - job:
     name: kolla-ansible-masakari-base
     parent: kolla-ansible-base
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 27702f48f7198b060cadefbaab2b6a8f7513e096..edcea29696d0d048430114350d828f37a8306e2a 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -249,6 +249,22 @@
       base_distro: ubuntu
       install_type: binary
 
+- job:
+    name: kolla-ansible-centos8-source-magnum
+    parent: kolla-ansible-magnum-base
+    nodeset: kolla-ansible-centos8
+    vars:
+      base_distro: centos
+      install_type: source
+
+- job:
+    name: kolla-ansible-ubuntu-source-magnum
+    parent: kolla-ansible-magnum-base
+    nodeset: kolla-ansible-focal
+    vars:
+      base_distro: ubuntu
+      install_type: source
+
 - job:
     name: kolla-ansible-ubuntu-source-masakari
     parent: kolla-ansible-masakari-base
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index eca2e15323cbffb9e3e550494a42b71bc2e67fb6..3a56e55d8210ccb23542d99fa9938153314cb0a0 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -23,6 +23,8 @@
         - kolla-ansible-centos8-source-swift
         - kolla-ansible-ubuntu-source-swift
         - kolla-ansible-centos8-source-scenario-nfv
+        - kolla-ansible-centos8-source-magnum
+        - kolla-ansible-ubuntu-source-magnum
         - kolla-ansible-centos8-source-masakari
         - kolla-ansible-ubuntu-source-masakari
         - kolla-ansible-centos8-source-ironic