aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Nasiadka <mnasiadka@gmail.com>2019-12-20 11:35:35 +0100
committerMichal Nasiadka <mnasiadka@gmail.com>2020-04-09 07:40:12 +0200
commit8a0740df977916fa5b23117f993cde7282a303bf (patch)
tree924e6a77be4cc6dc13f3b0d5862e9f56da269a4b
parentfa49143f10c5bb41c142b3bed94d34992d48baed (diff)
downloadkolla-ansible-8a0740df977916fa5b23117f993cde7282a303bf.tar.gz
kolla-ansible-8a0740df977916fa5b23117f993cde7282a303bf.zip
OVN Support
Implement OVN Ansible role. Implements: blueprint ovn-controller-neutron-ansible Depends-On: https://review.opendev.org/713422 Change-Id: Icd425dea85d58db49c838839d8f0b864b4a89a78
-rw-r--r--ansible/group_vars/all.yml15
-rw-r--r--ansible/inventory/all-in-one25
-rw-r--r--ansible/inventory/multinode25
-rw-r--r--ansible/roles/neutron/defaults/main.yml40
-rw-r--r--ansible/roles/neutron/handlers/main.yml16
-rw-r--r--ansible/roles/neutron/tasks/config.yml18
-rw-r--r--ansible/roles/neutron/templates/ml2_conf.ini.j212
-rw-r--r--ansible/roles/neutron/templates/neutron-ovn-metadata-agent.json.j236
-rw-r--r--ansible/roles/neutron/templates/neutron-server.json.j22
-rw-r--r--ansible/roles/neutron/templates/neutron_ovn_metadata_agent.ini.j217
-rw-r--r--ansible/roles/openvswitch/defaults/main.yml6
-rw-r--r--ansible/roles/openvswitch/tasks/deploy.yml2
-rw-r--r--ansible/roles/openvswitch/tasks/post-config.yml (renamed from ansible/roles/openvswitch/tasks/ensure-ovs-bridge.yml)5
-rw-r--r--ansible/roles/openvswitch/tasks/upgrade.yml2
-rw-r--r--ansible/roles/ovn/defaults/main.yml92
-rw-r--r--ansible/roles/ovn/handlers/main.yml84
-rw-r--r--ansible/roles/ovn/meta/main.yml3
-rw-r--r--ansible/roles/ovn/tasks/bootstrap.yml40
-rw-r--r--ansible/roles/ovn/tasks/check-containers.yml16
-rw-r--r--ansible/roles/ovn/tasks/check.yml1
-rw-r--r--ansible/roles/ovn/tasks/config.yml29
-rw-r--r--ansible/roles/ovn/tasks/deploy-containers.yml2
-rw-r--r--ansible/roles/ovn/tasks/deploy.yml7
-rw-r--r--ansible/roles/ovn/tasks/main.yml2
-rw-r--r--ansible/roles/ovn/tasks/precheck.yml30
-rw-r--r--ansible/roles/ovn/tasks/pull.yml11
-rw-r--r--ansible/roles/ovn/tasks/reconfigure.yml2
-rw-r--r--ansible/roles/ovn/tasks/stop.yml6
-rw-r--r--ansible/roles/ovn/tasks/upgrade.yml7
-rw-r--r--ansible/roles/ovn/templates/ovn-controller.json.j210
-rw-r--r--ansible/roles/ovn/templates/ovn-nb-db.json.j212
-rw-r--r--ansible/roles/ovn/templates/ovn-northd.json.j210
-rw-r--r--ansible/roles/ovn/templates/ovn-sb-db.json.j212
-rw-r--r--ansible/site.yml16
-rw-r--r--doc/source/reference/networking/neutron.rst23
-rw-r--r--etc/kolla/globals.yml7
-rw-r--r--releasenotes/notes/implement-ovn-80b3a73e6c8a44e7.yaml9
-rw-r--r--tests/run.yml9
-rw-r--r--tests/templates/globals-default.j24
-rw-r--r--tests/templates/inventory.j225
-rwxr-xr-xtests/test-ovn.sh37
-rwxr-xr-xtools/setup_gate.sh4
-rw-r--r--zuul.d/base.yaml11
-rw-r--r--zuul.d/jobs.yaml16
-rw-r--r--zuul.d/project.yaml2
45 files changed, 746 insertions, 14 deletions
diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 148112835..80ce20345 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -374,6 +374,11 @@ octavia_api_port: "9876"
octavia_api_listen_port: "{{ octavia_api_port }}"
octavia_health_manager_port: "5555"
+ovn_nb_db_port: "6641"
+ovn_sb_db_port: "6642"
+ovn_nb_connection: "{% for host in groups['ovn-nb-db'] %}tcp:{{ 'api' | kolla_address(host) }}:{{ ovn_nb_db_port }}{% if not loop.last %},{% endif %}{% endfor %}"
+ovn_sb_connection: "{% for host in groups['ovn-sb-db'] %}tcp:{{ 'api' | kolla_address(host) }}:{{ ovn_sb_db_port }}{% if not loop.last %},{% endif %}{% endfor %}"
+
outward_rabbitmq_port: "5674"
outward_rabbitmq_management_port: "15674"
outward_rabbitmq_cluster_port: "25674"
@@ -634,6 +639,7 @@ enable_nova_serialconsole_proxy: "no"
enable_nova_ssh: "yes"
enable_octavia: "no"
enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}"
+enable_ovn: "{{ enable_neutron | bool and neutron_plugin_agent == 'ovn' }}"
enable_ovs_dpdk: "no"
enable_osprofiler: "no"
enable_panko: "no"
@@ -882,14 +888,14 @@ designate_coordination_backend: "{{ 'redis' if enable_redis|bool else 'etcd' if
neutron_bgp_router_id: "1.1.1.1"
neutron_bridge_name: "{{ 'br-dvs' if neutron_plugin_agent == 'vmware_dvs' else 'br-ex' }}"
# Comma-separated type of enabled ml2 type drivers
-neutron_type_drivers: "flat,vlan,vxlan"
+neutron_type_drivers: "flat,vlan,vxlan{% if neutron_plugin_agent == 'ovn' %},geneve{% endif %}"
# Comma-separated types of tenant networks (should be listed in 'neutron_type_drivers')
# NOTE: for ironic this list should also contain 'flat'
-neutron_tenant_network_types: "vxlan"
+neutron_tenant_network_types: "{% if neutron_plugin_agent == 'ovn' %}geneve{% else %}vxlan{% endif %}"
# valid values: ["dvr", "dvr_no_external"]
neutron_compute_dvr_mode: "dvr"
-computes_need_external_bridge: "{{ (enable_neutron_dvr | bool and neutron_compute_dvr_mode == 'dvr') or enable_neutron_provider_networks | bool }}"
+computes_need_external_bridge: "{{ (enable_neutron_dvr | bool and neutron_compute_dvr_mode == 'dvr') or enable_neutron_provider_networks | bool or neutron_ovn_distributed_fip | bool }}"
# Default DNS resolvers for virtual networks
neutron_dnsmasq_dns_servers: "1.1.1.1,8.8.8.8,8.8.4.4"
@@ -897,6 +903,9 @@ neutron_dnsmasq_dns_servers: "1.1.1.1,8.8.8.8,8.8.4.4"
# Set legacy iptables to allow kernels not supporting iptables-nft
neutron_legacy_iptables: "no"
+# Enable distributed floating ip for OVN deployments
+neutron_ovn_distributed_fip: "no"
+
#######################
# Nova options
#######################
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index 483bc9449..b8fe61011 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -299,6 +299,9 @@ neutron
[neutron-metadata-agent:children]
neutron
+[neutron-ovn-metadata-agent:children]
+compute
+
[neutron-bgp-dragent:children]
neutron
@@ -756,3 +759,25 @@ control
[masakari-monitors:children]
compute
+
+[ovn-controller:children]
+ovn-controller-compute
+ovn-controller-network
+
+[ovn-controller-compute:children]
+compute
+
+[ovn-controller-network:children]
+network
+
+[ovn-database:children]
+control
+
+[ovn-northd:children]
+ovn-database
+
+[ovn-nb-db:children]
+ovn-database
+
+[ovn-sb-db:children]
+ovn-database
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 98e4f1bb1..b662c90df 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -318,6 +318,9 @@ neutron
[neutron-metadata-agent:children]
neutron
+[neutron-ovn-metadata-agent:children]
+compute
+
[neutron-bgp-dragent:children]
neutron
@@ -775,3 +778,25 @@ control
[masakari-monitors:children]
compute
+
+[ovn-controller:children]
+ovn-controller-compute
+ovn-controller-network
+
+[ovn-controller-compute:children]
+compute
+
+[ovn-controller-network:children]
+network
+
+[ovn-database:children]
+control
+
+[ovn-northd:children]
+ovn-database
+
+[ovn-nb-db:children]
+ovn-database
+
+[ovn-sb-db:children]
+ovn-database
diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index c519892f4..b854ea71b 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -81,7 +81,7 @@ neutron_services:
container_name: "neutron_dhcp_agent"
image: "{{ neutron_dhcp_agent_image_full }}"
privileged: True
- enabled: "{{ neutron_plugin_agent not in [ 'vmware_nsxv', 'vmware_nsxv3' ] }}"
+ enabled: "{{ neutron_plugin_agent not in ['ovn', 'vmware_nsxv', 'vmware_nsxv3'] }}"
group: "neutron-dhcp-agent"
host_in_groups: "{{ inventory_hostname in groups['neutron-dhcp-agent'] }}"
volumes: "{{ neutron_dhcp_agent_default_volumes + neutron_dhcp_agent_extra_volumes }}"
@@ -90,7 +90,7 @@ neutron_services:
container_name: "neutron_l3_agent"
image: "{{ neutron_l3_agent_image_full }}"
privileged: True
- enabled: "{{ neutron_plugin_agent not in ['vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] }}"
+ enabled: "{{ neutron_plugin_agent not in ['ovn', 'vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] }}"
environment:
KOLLA_LEGACY_IPTABLES: "{{ neutron_legacy_iptables | bool | lower }}"
host_in_groups: >-
@@ -112,19 +112,27 @@ neutron_services:
container_name: "neutron_metadata_agent"
image: "{{ neutron_metadata_agent_image_full }}"
privileged: True
- enabled: "{{ neutron_plugin_agent not in [ 'vmware_nsxv', 'vmware_nsxv3' ] }}"
+ enabled: "{{ neutron_plugin_agent not in [ 'ovn', 'vmware_nsxv', 'vmware_nsxv3' ] }}"
host_in_groups: >-
{{
inventory_hostname in groups['neutron-metadata-agent']
- or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool)
+ or (inventory_hostname in groups['compute'] and neutron_plugin_agent == 'openvswitch' and enable_neutron_dvr | bool)
}}
volumes: "{{ neutron_metadata_agent_default_volumes + neutron_metadata_agent_extra_volumes }}"
dimensions: "{{ neutron_metadata_agent_dimensions }}"
+ neutron-ovn-metadata-agent:
+ container_name: "neutron_ovn_metadata_agent"
+ image: "{{ neutron_ovn_metadata_agent_image_full }}"
+ privileged: True
+ enabled: "{{ neutron_plugin_agent == 'ovn' }}"
+ host_in_groups: "{{ inventory_hostname in groups['neutron-ovn-metadata-agent'] }}"
+ volumes: "{{ neutron_ovn_metadata_agent_default_volumes + neutron_ovn_metadata_agent_extra_volumes }}"
+ dimensions: "{{ neutron_ovn_metadata_agent_dimensions }}"
neutron-bgp-dragent:
container_name: "neutron_bgp_dragent"
image: "{{ neutron_bgp_dragent_image_full }}"
privileged: True
- enabled: "{{ enable_neutron_bgp_dragent | bool and neutron_plugin_agent not in ['vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] }}"
+ enabled: "{{ enable_neutron_bgp_dragent | bool and neutron_plugin_agent not in ['ovn', 'vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] }}"
group: "neutron-bgp-dragent"
host_in_groups: "{{ inventory_hostname in groups['neutron-bgp-dragent'] }}"
volumes: "{{ neutron_bgp_dragent_default_volumes + neutron_bgp_dragent_extra_volumes }}"
@@ -191,6 +199,10 @@ neutron_metadata_agent_image: "{{ docker_registry ~ '/' if docker_registry else
neutron_metadata_agent_tag: "{{ neutron_tag }}"
neutron_metadata_agent_image_full: "{{ neutron_metadata_agent_image }}:{{ neutron_metadata_agent_tag }}"
+neutron_ovn_metadata_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ neutron_install_type }}-neutron-metadata-agent"
+neutron_ovn_metadata_agent_tag: "{{ neutron_tag }}"
+neutron_ovn_metadata_agent_image_full: "{{ neutron_ovn_metadata_agent_image }}:{{ neutron_ovn_metadata_agent_tag }}"
+
neutron_openvswitch_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ neutron_install_type }}-neutron-openvswitch-agent"
neutron_openvswitch_agent_tag: "{{ neutron_tag }}"
neutron_openvswitch_agent_image_full: "{{ neutron_openvswitch_agent_image }}:{{ neutron_openvswitch_agent_tag }}"
@@ -232,6 +244,7 @@ neutron_l3_agent_dimensions: "{{ neutron_agent_dimensions }}"
neutron_sriov_agent_dimensions: "{{ neutron_agent_dimensions }}"
neutron_linuxbridge_agent_dimensions: "{{ neutron_agent_dimensions }}"
neutron_metadata_agent_dimensions: "{{ neutron_agent_dimensions }}"
+neutron_ovn_metadata_agent_dimensions: "{{ neutron_agent_dimensions }}"
neutron_openvswitch_agent_dimensions: "{{ neutron_agent_dimensions }}"
neutron_server_dimensions: "{{ default_container_dimensions }}"
neutron_bgp_dragent_dimensions: "{{ default_container_dimensions }}"
@@ -273,6 +286,14 @@ neutron_metadata_agent_default_volumes:
- "neutron_metadata_socket:/var/lib/neutron/kolla/"
- "kolla_logs:/var/log/kolla/"
- "{{ kolla_dev_repos_directory ~ '/neutron/neutron:/var/lib/kolla/venv/lib/python' ~ distro_python_version ~ '/site-packages/neutron' if neutron_dev_mode | bool else '' }}"
+neutron_ovn_metadata_agent_default_volumes:
+ - "{{ node_config_directory }}/neutron-ovn-metadata-agent/:{{ container_config_directory }}/:ro"
+ - "/etc/localtime:/etc/localtime:ro"
+ - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+ - "/run/openvswitch:/run/openvswitch:shared"
+ - "/run/netns:/run/netns:shared"
+ - "kolla_logs:/var/log/kolla/"
+ - "{{ kolla_dev_repos_directory ~ '/neutron/neutron:/var/lib/kolla/venv/lib/python' ~ distro_python_version ~ '/site-packages/neutron' if neutron_dev_mode | bool else '' }}"
neutron_openvswitch_agent_default_volumes:
- "{{ node_config_directory }}/neutron-openvswitch-agent/:{{ container_config_directory }}/:ro"
- "/etc/localtime:/etc/localtime:ro"
@@ -316,6 +337,7 @@ neutron_l3_agent_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_sriov_agent_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_linuxbridge_agent_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_metadata_agent_extra_volumes: "{{ neutron_extra_volumes }}"
+neutron_ovn_metadata_agent_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_openvswitch_agent_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_server_extra_volumes: "{{ neutron_extra_volumes }}"
neutron_bgp_dragent_extra_volumes: "{{ neutron_extra_volumes }}"
@@ -359,7 +381,9 @@ mechanism_drivers:
- name: "baremetal"
enabled: "{{ enable_ironic_neutron_agent | bool }}"
- name: "l2population"
- enabled: "{{ not enable_hyperv | bool }}"
+ enabled: "{{ not enable_hyperv | bool or neutron_plugin_agent != 'ovn' }}"
+ - name: "ovn"
+ enabled: "{{ neutron_plugin_agent == 'ovn' }}"
neutron_mechanism_drivers: "{{ mechanism_drivers | selectattr('enabled', 'equalto', true) | list }}"
@@ -399,7 +423,7 @@ service_plugins:
- name: "qos"
enabled: "{{ enable_neutron_qos | bool }}"
- name: "router"
- enabled: true
+ enabled: "{{ neutron_plugin_agent != 'ovn' }}"
- name: "segments"
enabled: "{{ enable_neutron_segments | bool }}"
- name: "sfc"
@@ -408,6 +432,8 @@ service_plugins:
enabled: "{{ enable_neutron_vpnaas | bool }}"
- name: "port_forwarding"
enabled: "{{ enable_neutron_port_forwarding | bool }}"
+ - name: "ovn-router"
+ enabled: "{{ neutron_plugin_agent == 'ovn' }}"
neutron_service_plugins: "{{ service_plugins | selectattr('enabled', 'equalto', true) | list }}"
diff --git a/ansible/roles/neutron/handlers/main.yml b/ansible/roles/neutron/handlers/main.yml
index fcde34507..af364f994 100644
--- a/ansible/roles/neutron/handlers/main.yml
+++ b/ansible/roles/neutron/handlers/main.yml
@@ -147,6 +147,22 @@
when:
- kolla_action != "config"
+- name: Restart neutron-ovn-metadata-agent container
+ vars:
+ service_name: "neutron-ovn-metadata-agent"
+ service: "{{ neutron_services[service_name] }}"
+ become: true
+ kolla_docker:
+ action: "recreate_or_restart_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ service.container_name }}"
+ image: "{{ service.image }}"
+ volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ service.dimensions }}"
+ privileged: "{{ service.privileged | default(False) }}"
+ when:
+ - kolla_action != "config"
+
- name: Restart neutron-bgp-dragent container
vars:
service_name: "neutron-bgp-dragent"
diff --git a/ansible/roles/neutron/tasks/config.yml b/ansible/roles/neutron/tasks/config.yml
index bf8b3bcb4..889ff779b 100644
--- a/ansible/roles/neutron/tasks/config.yml
+++ b/ansible/roles/neutron/tasks/config.yml
@@ -57,6 +57,7 @@
- "neutron-l3-agent"
- "neutron-linuxbridge-agent"
- "neutron-metadata-agent"
+ - "neutron-ovn-metadata-agent"
- "neutron-metering-agent"
- "neutron-openvswitch-agent"
- "neutron-openvswitch-agent-xenapi"
@@ -300,6 +301,23 @@
notify:
- "Restart {{ service_name }} container"
+- name: Copying over neutron_ovn_metadata_agent.ini
+ become: true
+ vars:
+ service_name: "neutron-ovn-metadata-agent"
+ neutron_ovn_metadata_agent: "{{ neutron_services[service_name] }}"
+ merge_configs:
+ sources:
+ - "{{ role_path }}/templates/neutron_ovn_metadata_agent.ini.j2"
+ - "{{ node_custom_config }}/neutron/neutron_ovn_metadata_agent.ini"
+ dest: "{{ node_config_directory }}/{{ service_name }}/neutron_ovn_metadata_agent.ini"
+ mode: "0660"
+ when:
+ - neutron_ovn_metadata_agent.enabled | bool
+ - neutron_ovn_metadata_agent.host_in_groups | bool
+ notify:
+ - "Restart {{ service_name }} container"
+
- name: Copying over metering_agent.ini
become: true
vars:
diff --git a/ansible/roles/neutron/templates/ml2_conf.ini.j2 b/ansible/roles/neutron/templates/ml2_conf.ini.j2
index 2ea2195c3..2e1cb8096 100644
--- a/ansible/roles/neutron/templates/ml2_conf.ini.j2
+++ b/ansible/roles/neutron/templates/ml2_conf.ini.j2
@@ -29,3 +29,15 @@ flat_networks = {% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop
[ml2_type_vxlan]
vni_ranges = 1:1000
+
+{% if neutron_plugin_agent == 'ovn' %}
+[ml2_type_geneve]
+vni_ranges = 1001:2000
+max_header_size = 38
+
+[ovn]
+ovn_nb_connection = {{ ovn_nb_connection }}
+ovn_sb_connection = {{ ovn_sb_connection }}
+ovn_metadata_enabled = True
+enable_distributed_floating_ip = {{ neutron_ovn_distributed_fip | bool }}
+{% endif %}
diff --git a/ansible/roles/neutron/templates/neutron-ovn-metadata-agent.json.j2 b/ansible/roles/neutron/templates/neutron-ovn-metadata-agent.json.j2
new file mode 100644
index 000000000..f88e66494
--- /dev/null
+++ b/ansible/roles/neutron/templates/neutron-ovn-metadata-agent.json.j2
@@ -0,0 +1,36 @@
+{
+ "command": "neutron-ovn-metadata-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/neutron_ovn_metadata_agent.ini",
+ "config_files": [
+ {
+ "source": "{{ container_config_directory }}/neutron.conf",
+ "dest": "/etc/neutron/neutron.conf",
+ "owner": "neutron",
+ "perm": "0600"
+ },
+ {
+ "source": "{{ container_config_directory }}/neutron_ovn_metadata_agent.ini",
+ "dest": "/etc/neutron/neutron_ovn_metadata_agent.ini",
+ "owner": "neutron",
+ "perm": "0600"
+ },
+ {
+ "source": "{{ container_config_directory }}/policy.json",
+ "dest": "/etc/neutron/policy.json",
+ "owner": "neutron",
+ "perm": "0600",
+ "optional": true
+ }
+ ],
+ "permissions": [
+ {
+ "path": "/var/log/kolla/neutron",
+ "owner": "neutron:neutron",
+ "recurse": true
+ },
+ {
+ "path": "/var/lib/neutron/kolla",
+ "owner": "neutron:neutron",
+ "recurse": true
+ }
+ ]
+}
diff --git a/ansible/roles/neutron/templates/neutron-server.json.j2 b/ansible/roles/neutron/templates/neutron-server.json.j2
index 77ea2f2dd..3a71ed123 100644
--- a/ansible/roles/neutron/templates/neutron-server.json.j2
+++ b/ansible/roles/neutron/templates/neutron-server.json.j2
@@ -1,5 +1,5 @@
{
- "command": "neutron-server --config-file /etc/neutron/neutron.conf {% if neutron_plugin_agent in ['openvswitch', 'linuxbridge'] %} --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_vpnaas.conf {% elif neutron_plugin_agent in ['vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] %} --config-file /etc/neutron/plugins/vmware/nsx.ini {% endif %} --config-file /etc/neutron/fwaas_driver.ini",
+ "command": "neutron-server --config-file /etc/neutron/neutron.conf {% if neutron_plugin_agent in ['openvswitch', 'linuxbridge', 'ovn'] %} --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_vpnaas.conf {% elif neutron_plugin_agent in ['vmware_nsxv', 'vmware_nsxv3', 'vmware_dvs'] %} --config-file /etc/neutron/plugins/vmware/nsx.ini {% endif %} --config-file /etc/neutron/fwaas_driver.ini",
"config_files": [
{
"source": "{{ container_config_directory }}/neutron.conf",
diff --git a/ansible/roles/neutron/templates/neutron_ovn_metadata_agent.ini.j2 b/ansible/roles/neutron/templates/neutron_ovn_metadata_agent.ini.j2
new file mode 100644
index 000000000..591e8cde1
--- /dev/null
+++ b/ansible/roles/neutron/templates/neutron_ovn_metadata_agent.ini.j2
@@ -0,0 +1,17 @@
+[DEFAULT]
+auth_ca_cert = {{ openstack_cacert }}
+nova_metadata_protocol = {{ internal_protocol }}
+metadata_proxy_socket = /var/lib/neutron/kolla/metadata_proxy
+nova_metadata_host = {{ nova_internal_fqdn }}
+nova_metadata_port = {{ nova_metadata_port }}
+metadata_proxy_shared_secret = {{ metadata_secret }}
+log_file = neutron-ovn-metadata-agent.log
+log_dir = /var/log/kolla/neutron
+
+[ovs]
+ovsdb_connection = tcp:127.0.0.1:6640
+
+[ovn]
+ovn_nb_connection = {{ ovn_nb_connection }}
+ovn_sb_connection = {{ ovn_sb_connection }}
+ovn_metadata_enabled = true
diff --git a/ansible/roles/openvswitch/defaults/main.yml b/ansible/roles/openvswitch/defaults/main.yml
index fe2867ab5..425a86667 100644
--- a/ansible/roles/openvswitch/defaults/main.yml
+++ b/ansible/roles/openvswitch/defaults/main.yml
@@ -68,3 +68,9 @@ openvswitch_vswitchd_default_volumes:
openvswitch_extra_volumes: "{{ default_extra_volumes }}"
openvswitch_db_extra_volumes: "{{ openvswitch_extra_volumes }}"
openvswitch_vswitchd_extra_volumes: "{{ openvswitch_extra_volumes }}"
+
+#############
+# OpenvSwitch
+#############
+
+openvswitch_system_id: "{{ inventory_hostname_short }}"
diff --git a/ansible/roles/openvswitch/tasks/deploy.yml b/ansible/roles/openvswitch/tasks/deploy.yml
index 60c9a9902..f135d8a29 100644
--- a/ansible/roles/openvswitch/tasks/deploy.yml
+++ b/ansible/roles/openvswitch/tasks/deploy.yml
@@ -6,4 +6,4 @@
- name: Flush Handlers
meta: flush_handlers
-- include_tasks: ensure-ovs-bridge.yml
+- include_tasks: post-config.yml
diff --git a/ansible/roles/openvswitch/tasks/ensure-ovs-bridge.yml b/ansible/roles/openvswitch/tasks/post-config.yml
index 55ea2e9ac..ce412b884 100644
--- a/ansible/roles/openvswitch/tasks/ensure-ovs-bridge.yml
+++ b/ansible/roles/openvswitch/tasks/post-config.yml
@@ -1,4 +1,9 @@
---
+# NOTE(mnasiadka): external_ids:system-id uniquely identifies a physical system, used by OVN and other controllers
+- name: Set system-id
+ become: true
+ command: docker exec openvswitch_vswitchd ovs-vsctl set Open_vSwitch . external_ids:system-id={{ openvswitch_system_id }}
+
- name: Ensuring OVS bridge is properly setup
become: true
command: docker exec openvswitch_db /usr/local/bin/kolla_ensure_openvswitch_configured {{ item.0 }} {{ item.1 }}
diff --git a/ansible/roles/openvswitch/tasks/upgrade.yml b/ansible/roles/openvswitch/tasks/upgrade.yml
index 110210a16..92824f43d 100644
--- a/ansible/roles/openvswitch/tasks/upgrade.yml
+++ b/ansible/roles/openvswitch/tasks/upgrade.yml
@@ -4,4 +4,4 @@
- name: Flush Handlers
meta: flush_handlers
-- include_tasks: ensure-ovs-bridge.yml
+- include_tasks: post-config.yml
diff --git a/ansible/roles/ovn/defaults/main.yml b/ansible/roles/ovn/defaults/main.yml
new file mode 100644
index 000000000..58c26bb6f
--- /dev/null
+++ b/ansible/roles/ovn/defaults/main.yml
@@ -0,0 +1,92 @@
+---
+project_name: "ovn"
+
+ovn_services:
+ ovn-controller:
+ container_name: ovn_controller
+ group: ovn-controller
+ enabled: true
+ image: "{{ ovn_controller_image_full }}"
+ volumes: "{{ ovn_controller_default_volumes + ovn_controller_extra_volumes }}"
+ dimensions: "{{ ovn_controller_dimensions }}"
+ ovn-northd:
+ container_name: ovn_northd
+ group: ovn-northd
+ enabled: true
+ image: "{{ ovn_northd_image_full }}"
+ volumes: "{{ ovn_northd_default_volumes + ovn_northd_extra_volumes }}"
+ dimensions: "{{ ovn_northd_dimensions }}"
+ ovn-nb-db:
+ container_name: ovn_nb_db
+ group: ovn-nb-db
+ enabled: true
+ image: "{{ ovn_nb_db_image_full }}"
+ volumes: "{{ ovn_nb_db_default_volumes + ovn_nb_db_extra_volumes }}"
+ dimensions: "{{ ovn_nb_db_dimensions }}"
+ ovn-sb-db:
+ container_name: ovn_sb_db
+ group: ovn-sb-db
+ enabled: true
+ image: "{{ ovn_sb_db_image_full }}"
+ volumes: "{{ ovn_sb_db_default_volumes + ovn_sb_db_extra_volumes }}"
+ dimensions: "{{ ovn_sb_db_dimensions }}"
+
+
+####################
+# Docker
+####################
+ovn_install_type: "{{ kolla_install_type }}"
+ovn_tag: "{{ openstack_tag }}"
+
+ovn_controller_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ ovn_install_type }}-ovn-controller"
+ovn_controller_tag: "{{ ovn_tag }}"
+ovn_controller_image_full: "{{ ovn_controller_image }}:{{ ovn_controller_tag }}"
+
+ovn_northd_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ ovn_install_type }}-ovn-northd"
+ovn_northd_tag: "{{ ovn_tag }}"
+ovn_northd_image_full: "{{ ovn_northd_image }}:{{ ovn_northd_tag }}"
+
+ovn_nb_db_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ ovn_install_type }}-ovn-nb-db-server"
+ovn_nb_db_tag: "{{ ovn_tag }}"
+ovn_nb_db_image_full: "{{ ovn_nb_db_image }}:{{ ovn_nb_db_tag }}"
+
+ovn_sb_db_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ ovn_install_type }}-ovn-sb-db-server"
+ovn_sb_db_tag: "{{ ovn_tag }}"
+ovn_sb_db_image_full: "{{ ovn_sb_db_image }}:{{ ovn_sb_db_tag }}"
+
+ovn_controller_dimensions: "{{ default_container_dimensions }}"
+ovn_northd_dimensions: "{{ default_container_dimensions }}"
+ovn_nb_db_dimensions: "{{ default_container_dimensions }}"
+ovn_sb_db_dimensions: "{{ default_container_dimensions }}"
+
+ovn_controller_default_volumes:
+ - "{{ node_config_directory }}/ovn-controller/:{{ container_config_directory }}/:ro"
+ - "/run/openvswitch:/run/openvswitch:shared"
+ - "/etc/localtime:/etc/localtime:ro"
+ - "kolla_logs:/var/log/kolla/"
+ovn_northd_default_volumes:
+ - "{{ node_config_directory }}/ovn-northd/:{{ container_config_directory }}/:ro"
+ - "/etc/localtime:/etc/localtime:ro"
+ - "kolla_logs:/var/log/kolla/"
+ovn_nb_db_default_volumes:
+ - "{{ node_config_directory }}/ovn-nb-db/:{{ container_config_directory }}/:ro"
+ - "/etc/localtime:/etc/localtime:ro"
+ - "ovn_nb_db:/var/lib/openvswitch/ovn-nb/"
+ - "kolla_logs:/var/log/kolla/"
+ovn_sb_db_default_volumes:
+ - "{{ node_config_directory }}/ovn-sb-db/:{{ container_config_directory }}/:ro"
+ - "/etc/localtime:/etc/localtime:ro"
+ - "ovn_sb_db:/var/lib/openvswitch/ovn-sb/"
+ - "kolla_logs:/var/log/kolla/"
+
+ovn_extra_volumes: "{{ default_extra_volumes }}"
+ovn_controller_extra_volumes: "{{ ovn_extra_volumes }}"
+ovn_northd_extra_volumes: "{{ ovn_extra_volumes }}"
+ovn_nb_db_extra_volumes: "{{ ovn_extra_volumes }}"
+ovn_sb_db_extra_volumes: "{{ ovn_extra_volumes }}"
+
+#####
+# OVN
+#####
+# Configure OVN remote probe interval time in ms
+ovn_remote_probe_interval: "60000"
diff --git a/ansible/roles/ovn/handlers/main.yml b/ansible/roles/ovn/handlers/main.yml
new file mode 100644
index 000000000..42263f16c
--- /dev/null
+++ b/ansible/roles/ovn/handlers/main.yml
@@ -0,0 +1,84 @@
+---
+- name: Restart ovn-nb-db container
+ vars:
+ service_name: "ovn-nb-db"
+ service: "{{ ovn_services[service_name] }}"
+ become: true
+ kolla_docker:
+ action: "recreate_or_restart_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ service.container_name }}"
+ image: "{{ service.image }}"
+ volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ service.dimensions }}"
+ when:
+ - kolla_action != "config"
+
+- name: Restart ovn-sb-db container
+ vars:
+ service_name: "ovn-sb-db"
+ service: "{{ ovn_services[service_name] }}"
+ become: true
+ kolla_docker:
+ action: "recreate_or_restart_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ service.container_name }}"
+ image: "{{ service.image }}"
+ volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ service.dimensions }}"
+ when:
+ - kolla_action != "config"
+
+- name: Wait for ovn-nb-db
+ wait_for:
+ host: "{{ api_interface_address }}"
+ port: "{{ ovn_nb_db_port }}"
+ connect_timeout: 1
+ timeout: 60
+ register: check_ovn_nb_db_port
+ until: check_ovn_nb_db_port is success
+ retries: 10
+ delay: 6
+ listen: "Restart ovn-nb-db container"
+
+- name: Wait for ovn-sb-db
+ wait_for:
+ host: "{{ api_interface_address }}"
+ port: "{{ ovn_sb_db_port }}"
+ connect_timeout: 1
+ timeout: 60
+ register: check_ovn_sb_db_port
+ until: check_ovn_sb_db_port is success
+ retries: 10
+ delay: 6
+ listen: "Restart ovn-sb-db container"
+
+- name: Restart ovn-northd container
+ vars:
+ service_name: "ovn-northd"
+ service: "{{ ovn_services[service_name] }}"
+ become: true
+ kolla_docker:
+ action: "recreate_or_restart_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ service.container_name }}"
+ image: "{{ service.image }}"
+ volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ service.dimensions }}"
+ when:
+ - kolla_action != "config"
+
+- name: Restart ovn-controller container
+ vars:
+ service_name: "ovn-controller"
+ service: "{{ ovn_services[service_name] }}"
+ become: true
+ kolla_docker:
+ action: "recreate_or_restart_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ service.container_name }}"
+ image: "{{ service.image }}"
+ volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ service.dimensions }}"
+ when:
+ - kolla_action != "config"
diff --git a/ansible/roles/ovn/meta/main.yml b/ansible/roles/ovn/meta/main.yml
new file mode 100644
index 000000000..6b4fff8fe
--- /dev/null
+++ b/ansible/roles/ovn/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - { role: common }
diff --git a/ansible/roles/ovn/tasks/bootstrap.yml b/ansible/roles/ovn/tasks/bootstrap.yml
new file mode 100644
index 000000000..3b01f19ff
--- /dev/null
+++ b/ansible/roles/ovn/tasks/bootstrap.yml
@@ -0,0 +1,40 @@
+---
+- name: Create br-int bridge on OpenvSwitch
+ become: true
+ command: >
+ docker exec openvswitch_vswitchd ovs-vsctl --may-exist
+ add-br br-int -- set Bridge br-int fail-mode=secure
+ when: inventory_hostname in groups['ovn-controller']
+
+- name: Set OVN encapsulation settings
+ become: true
+ command: >
+ docker exec openvswitch_vswitchd ovs-vsctl set Open_vSwitch .
+ external_ids:ovn-encap-ip={{ tunnel_interface_address }}
+ external_ids:ovn-encap-type=geneve
+ external_ids:ovn-remote={{ ovn_sb_connection }}
+ when: inventory_hostname in groups['ovn-controller']
+
+- name: Set OVN bridge mappings
+ vars:
+ ovn_mappings: "{% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %}"
+ become: true
+ command: docker exec openvswitch_vswitchd ovs-vsctl set Open_vSwitch . external_ids:ovn-bridge-mappings={{ ovn_mappings }}
+ when:
+ - inventory_hostname in groups["ovn-controller-network"]
+ or (inventory_hostname in groups["ovn-controller-compute"] and computes_need_external_bridge | bool)
+
+- name: Enable chassis as gateway
+ become: true
+ command: docker exec openvswitch_vswitchd ovs-vsctl set Open_vSwitch . external-ids:ovn-cms-options="enable-chassis-as-gw"
+ when:
+ - inventory_hostname in groups["ovn-controller-network"]
+ or (inventory_hostname in groups["ovn-controller-compute"] and neutron_ovn_distributed_fip | bool)
+
+- name: Set OVN remote probe interval
+ become: true
+ command: >
+ docker exec openvswitch_vswitchd ovs-vsctl set Open_vSwitch .
+ external_ids:ovn-remote-probe-interval={{ ovn_remote_probe_interval }}
+ when:
+ - inventory_hostname in groups["ovn-controller"]
diff --git a/ansible/roles/ovn/tasks/check-containers.yml b/ansible/roles/ovn/tasks/check-containers.yml
new file mode 100644
index 000000000..fe5ac530e
--- /dev/null
+++ b/ansible/roles/ovn/tasks/check-containers.yml
@@ -0,0 +1,16 @@
+---
+- name: Check ovn containers
+ become: true
+ kolla_docker:
+ action: "compare_container"
+ common_options: "{{ docker_common_options }}"
+ name: "{{ item.value.container_name }}"
+ image: "{{ item.value.image }}"
+ volumes: "{{ item.value.volumes|reject('equalto', '')|list }}"
+ dimensions: "{{ item.value.dimensions }}"
+ when:
+ - inventory_hostname in groups[item.value.group]
+ - item.value.enabled | bool
+ with_dict: "{{ ovn_services }}"
+ notify:
+ - Restart {{ item.key }} container
diff --git a/ansible/roles/ovn/tasks/check.yml b/ansible/roles/ovn/tasks/check.yml
new file mode 100644
index 000000000..ed97d539c
--- /dev/null
+++ b/ansible/roles/ovn/tasks/check.yml
@@ -0,0 +1 @@
+---
diff --git a/ansible/roles/ovn/tasks/config.yml b/ansible/roles/ovn/tasks/config.yml
new file mode 100644
index 000000000..06216fc21
--- /dev/null
+++ b/ansible/roles/ovn/tasks/config.yml
@@ -0,0 +1,29 @@
+---
+- name: Ensuring config directories exist
+ file:
+ path: "{{ node_config_directory }}/{{ item.key }}"
+ state: "directory"
+ owner: "{{ config_owner_user }}"
+ group: "{{ config_owner_group }}"
+ mode: "0770"
+ become: true
+ when:
+ - inventory_hostname in groups[item.value.group]
+ - item.value.enabled | bool
+ with_dict: "{{ ovn_services }}"
+
+- name: Copying over config.json files for services
+ template:
+ src: "{{ item.key }}.json.j2"
+ dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
+ mode: "0660"
+ become: true
+ when:
+ - inventory_hostname in groups[item.value.group]
+ - item.value.enabled | bool
+ with_dict: "{{ ovn_services }}"
+ notify:
+ - Restart {{ item.key }} container
+
+- include_tasks: check-containers.yml
+ when: kolla_action != "config"
diff --git a/ansible/roles/ovn/tasks/deploy-containers.yml b/ansible/roles/ovn/tasks/deploy-containers.yml
new file mode 100644
index 000000000..eb24ab5c7
--- /dev/null
+++ b/ansible/roles/ovn/tasks/deploy-containers.yml
@@ -0,0 +1,2 @@
+---
+- import_tasks: check-containers.yml
diff --git a/ansible/roles/ovn/tasks/deploy.yml b/ansible/roles/ovn/tasks/deploy.yml
new file mode 100644
index 000000000..6f6feecec
--- /dev/null
+++ b/ansible/roles/ovn/tasks/deploy.yml
@@ -0,0 +1,7 @@
+---
+- include_tasks: config.yml
+
+- include_tasks: bootstrap.yml
+
+- name: Flush handlers
+ meta: flush_handlers
diff --git a/ansible/roles/ovn/tasks/main.yml b/ansible/roles/ovn/tasks/main.yml
new file mode 100644
index 000000000..bc5d1e625
--- /dev/null
+++ b/ansible/roles/ovn/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+- include_tasks: "{{ kolla_action }}.yml"
diff --git a/ansible/roles/ovn/tasks/precheck.yml b/ansible/roles/ovn/tasks/precheck.yml
new file mode 100644
index 000000000..77bf88281
--- /dev/null
+++ b/ansible/roles/ovn/tasks/precheck.yml
@@ -0,0 +1,30 @@
+---
+- name: Get container facts
+ become: true
+ kolla_container_facts:
+ name:
+ - ovn_nb_db
+ - ovn_sb_db
+ register: container_facts
+
+- name: Checking free port for OVN northbound db
+ wait_for:
+ host: "{{ api_interface_address }}"
+ port: "{{ ovn_nb_db_port }}"
+ connect_timeout: 1
+ timeout: 1
+ state: stopped
+ when:
+ - container_facts['ovn_nb_db'] is not defined
+ - inventory_hostname in groups['ovn-nb-db']
+
+- name: Checking free port for OVN southbound db
+ wait_for:
+ host: "{{ api_interface_address }}"
+ port: "{{ ovn_sb_db_port }}"
+ connect_timeout: 1
+ timeout: 1
+ state: stopped
+ when:
+ - container_facts['ovn_sb_db'] is not defined
+ - inventory_hostname in groups['ovn-sb-db']
diff --git a/ansible/roles/ovn/tasks/pull.yml b/ansible/roles/ovn/tasks/pull.yml
new file mode 100644
index 000000000..79ae0b297
--- /dev/null
+++ b/ansible/roles/ovn/tasks/pull.yml
@@ -0,0 +1,11 @@
+---
+- name: Pulling OVN images
+ become: true
+ kolla_docker:
+ action: "pull_image"
+ common_options: "{{ docker_common_options }}"
+ image: "{{ item.value.image }}"
+ when:
+ - inventory_hostname in groups[item.value.group]
+ - item.value.enabled | bool
+ with_dict: "{{ ovn_services }}"
diff --git a/ansible/roles/ovn/tasks/reconfigure.yml b/ansible/roles/ovn/tasks/reconfigure.yml
new file mode 100644
index 000000000..f670a5b78
--- /dev/null
+++ b/ansible/roles/ovn/tasks/reconfigure.yml
@@ -0,0 +1,2 @@
+---
+- include_tasks: deploy.yml
diff --git a/ansible/roles/ovn/tasks/stop.yml b/ansible/roles/ovn/tasks/stop.yml
new file mode 100644
index 000000000..885576f7d
--- /dev/null
+++ b/ansible/roles/ovn/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+ role: service-stop
+ vars:
+ project_services: "{{ ovn_services }}"
+ service_name: "{{ project_name }}"
diff --git a/ansible/roles/ovn/tasks/upgrade.yml b/ansible/roles/ovn/tasks/upgrade.yml
new file mode 100644
index 000000000..6f6feecec
--- /dev/null
+++ b/ansible/roles/ovn/tasks/upgrade.yml
@@ -0,0 +1,7 @@
+---
+- include_tasks: config.yml
+
+- include_tasks: bootstrap.yml
+
+- name: Flush handlers
+ meta: flush_handlers
diff --git a/ansible/roles/ovn/templates/ovn-controller.json.j2 b/ansible/roles/ovn/templates/ovn-controller.json.j2
new file mode 100644
index 000000000..b2db22197
--- /dev/null
+++ b/ansible/roles/ovn/templates/ovn-controller.json.j2
@@ -0,0 +1,10 @@
+{
+ "command": "/usr/bin/ovn-controller --pidfile=/run/ovn/ovn-controller.pid --log-file=/var/log/kolla/openvswitch/ovn-controller.log tcp:127.0.0.1:{{ ovsdb_port }}",
+ "permissions": [
+ {
+ "path": "/var/log/kolla/openvswitch",
+ "owner": "root:root",
+ "recurse": true
+ }
+ ]
+}
diff --git a/ansible/roles/ovn/templates/ovn-nb-db.json.j2 b/ansible/roles/ovn/templates/ovn-nb-db.json.j2
new file mode 100644
index 000000000..525556651
--- /dev/null
+++ b/ansible/roles/ovn/templates/ovn-nb-db.json.j2
@@ -0,0 +1,12 @@
+{% set ovnctl_cmd = '/usr/share/ovn/scripts/ovn-ctl' %}
+
+{
+ "command": "{{ ovnctl_cmd }} run_nb_ovsdb --db-nb-create-insecure-remote=yes --db-nb-addr={{ api_interface_address }} --db-nb-cluster-local-addr={{ api_interface_address }} {% if groups['ovn-nb-db'] | length > 1 and inventory_hostname != groups['ovn-nb-db'][0] %} --db-nb-cluster-remote-addr={{ 'api' | kolla_address(groups['ovn-nb-db'][0]) }} {% endif %} --db-sock=/run/ovn/ovnnb_db.sock --db-nb-pid=/run/ovn/ovnnb_db.pid --db-nb-file=/var/lib/openvswitch/ovn-nb/ovnnb.db --ovn-nb-logfile=/var/log/kolla/openvswitch/ovn-nb-db.log",
+ "permissions": [
+ {
+ "path": "/var/log/kolla/openvswitch",
+ "owner": "root:root",
+ "recurse": true
+ }
+ ]
+}
diff --git a/ansible/roles/ovn/templates/ovn-northd.json.j2 b/ansible/roles/ovn/templates/ovn-northd.json.j2
new file mode 100644
index 000000000..35abdbe49
--- /dev/null
+++ b/ansible/roles/ovn/templates/ovn-northd.json.j2
@@ -0,0 +1,10 @@
+{
+ "command": "/usr/bin/ovn-northd -vconsole:emer -vsyslog:err -vfile:info --ovnnb-db={{ ovn_nb_connection }} --ovnsb-db={{ ovn_sb_connection }} --log-file=/var/log/kolla/openvswitch/ovn-northd.log --pidfile=/run/ovn/ovn-northd.pid --unixctl=/run/ovn/ovn-northd.ctl",
+ "permissions": [
+ {
+ "path": "/var/log/kolla/openvswitch",
+ "owner": "root:root",
+ "recurse": true
+ }
+ ]
+}
diff --git a/ansible/roles/ovn/templates/ovn-sb-db.json.j2 b/ansible/roles/ovn/templates/ovn-sb-db.json.j2
new file mode 100644
index 000000000..5777b1f5a
--- /dev/null
+++ b/ansible/roles/ovn/templates/ovn-sb-db.json.j2
@@ -0,0 +1,12 @@
+{% set ovnctl_cmd = '/usr/share/ovn/scripts/ovn-ctl' %}
+
+{
+ "command": "{{ ovnctl_cmd }} run_sb_ovsdb --db-sb-create-insecure-remote=yes --db-sb-addr={{ api_interface_address }} --db-sb-cluster-local-addr={{ api_interface_address }} {% if groups['ovn-sb-db'] | length > 1 and inventory_hostname != groups['ovn-sb-db'][0] %} --db-sb-cluster-remote-addr={{ 'api' | kolla_address(groups['ovn-sb-db'][0]) }} {% endif %} --db-sock=/run/ovn/ovnsb_db.sock --db-sb-pid=/run/ovn/ovnsb_db.pid --db-sb-file=/var/lib/openvswitch/ovn-sb/ovnsb.db --ovn-sb-logfile=/var/log/kolla/openvswitch/ovn-sb-db.log",
+ "permissions": [
+ {
+ "path": "/var/log/kolla/openvswitch",
+ "owner": "root:root",
+ "recurse": true
+ }
+ ]
+}
diff --git a/ansible/site.yml b/ansible/site.yml
index 01e443dc2..1e425f7a4 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -60,6 +60,7 @@
- enable_octavia_{{ enable_octavia | bool }}
- enable_openvswitch_{{ enable_openvswitch | bool }}_enable_ovs_dpdk_{{ enable_ovs_dpdk | bool }}
- enable_outward_rabbitmq_{{ enable_outward_rabbitmq | bool }}
+ - enable_ovn_{{ enable_ovn | bool }}
- enable_panko_{{ enable_panko | bool }}
- enable_placement_{{ enable_placement | bool }}
- enable_prometheus_{{ enable_prometheus | bool }}
@@ -707,6 +708,20 @@
tags: ovs-dpdk,
when: "(enable_openvswitch | bool) and (enable_ovs_dpdk | bool)"}
+- name: Apply role ovn
+ gather_facts: false
+ hosts:
+ - ovn-controller
+ - ovn-nb-db
+ - ovn-northd
+ - ovn-sb-db
+ - '&enable_ovn_True'
+ serial: '{{ kolla_serial|default("0") }}'
+ roles:
+ - { role: ovn,
+ tags: ovn,
+ when: enable_ovn | bool }
+
- name: Apply role nova-hyperv
gather_facts: false
hosts:
@@ -728,6 +743,7 @@
- neutron-l3-agent
- ironic-neutron-agent
- neutron-metadata-agent
+ - neutron-ovn-metadata-agent
- neutron-metering-agent
- compute
- manila-share
diff --git a/doc/source/reference/networking/neutron.rst b/doc/source/reference/networking/neutron.rst
index 20af193ec..1760f349c 100644
--- a/doc/source/reference/networking/neutron.rst
+++ b/doc/source/reference/networking/neutron.rst
@@ -38,6 +38,9 @@ To use provider networks in instances you also need to set the following in
``enable_neutron_provider_networks`` ensures ``neutron_external_interface``
is used on hosts in the ``compute`` group.
+OpenvSwitch (ml2/ovs)
+~~~~~~~~~~~~~~~~~~~~~
+
By default ``kolla-ansible`` uses ``openvswitch`` as its underlying network
mechanism, you can change that using the ``neutron_plugin_agent`` variable in
``/etc/kolla/globals.yml``:
@@ -57,3 +60,23 @@ to using the native OVS firewall driver by employing a configuration override
[security_group]
firewall_driver = openvswitch
+OVN (ml2/ovn)
+~~~~~~~~~~~~~
+
+In order to use ``OVN`` as mechanism driver for ``neutron``, you need to set
+the following:
+
+.. path /etc/kolla/globals.yml
+.. code-block:: yaml
+
+ neutron_plugin_agent: "ovn"
+
+When using OVN - Kolla-Ansible will not enable distributed floating ip
+functionality (not enable external bridges on computes) by default.
+To change this behaviour you need to set the following:
+
+.. path /etc/kolla/globals.yml
+.. code-block:: yaml
+
+ neutron_ovn_distributed_fip: "yes"
+
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index 1d1eb4db9..663fd9d0a 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -325,6 +325,7 @@
#enable_nova_ssh: "yes"
#enable_octavia: "no"
#enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}"
+#enable_ovn: "{{ enable_neutron | bool and neutron_plugin_agent == 'ovn' }}"
#enable_ovs_dpdk: "no"
#enable_osprofiler: "no"
#enable_panko: "no"
@@ -518,6 +519,12 @@
# Valid options are [ none, novnc, spice, rdp ]
#nova_console: "novnc"
+##############################
+# Neutron - networking options
+##############################
+# Enable distributed floating ip for OVN deployments
+#neutron_ovn_distributed_fip: "no"
+
#################
# Hyper-V options
#################
diff --git a/releasenotes/notes/implement-ovn-80b3a73e6c8a44e7.yaml b/releasenotes/notes/implement-ovn-80b3a73e6c8a44e7.yaml
new file mode 100644
index 000000000..2fd23d6d8
--- /dev/null
+++ b/releasenotes/notes/implement-ovn-80b3a73e6c8a44e7.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ Implement OVN and integration with Neutron. This includes deployment of:
+
+ * OVN databases (``ovn-sb-db`` and ``ovn-nb-db``)
+ * Southbound and Northbound databases connector (``ovn-northd``)
+ * Hypervisor components ``ovn-controller`` and
+ ``neutron-ovn-metadata-agent``
diff --git a/tests/run.yml b/tests/run.yml
index 78eca7713..66251ca28 100644
--- a/tests/run.yml
+++ b/tests/run.yml
@@ -23,7 +23,7 @@
need_build_image: false
build_image_tag: "change_{{ zuul.change | default('none') }}"
openstack_core_enabled: "{{ openstack_core_enabled }}"
- openstack_core_tested: "{{ scenario in ['core', 'ceph-ansible', 'zun', 'cells', 'swift', 'linuxbridge'] }}"
+ openstack_core_tested: "{{ scenario in ['core', 'ceph-ansible', 'zun', 'cells', 'swift', 'linuxbridge', 'ovn'] }}"
dashboard_enabled: "{{ openstack_core_enabled }}"
# TODO(mgoddard): Remove when previous_release is ussuri.
playbook_python_version: "{{ '2' if is_upgrade and previous_release == 'train' and not is_centos8 else '3' }}"
@@ -423,6 +423,13 @@
chdir: "{{ kolla_ansible_src_dir }}"
when: scenario == "masakari"
+ - name: Run test-ovn.sh script
+ script:
+ cmd: test-ovn.sh
+ executable: /bin/bash
+ chdir: "{{ kolla_ansible_src_dir }}"
+ when: scenario == "ovn"
+
- name: Run test-mariadb.sh script
script:
cmd: test-mariadb.sh
diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2
index e1217ba4b..ff9c42881 100644
--- a/tests/templates/globals-default.j2
+++ b/tests/templates/globals-default.j2
@@ -130,3 +130,7 @@ openstack_cacert: "/etc/pki/ca-trust/source/anchors/kolla-customca-haproxy-inter
{% if scenario == 'linuxbridge' %}
neutron_plugin_agent: "linuxbridge"
{% endif %}
+
+{% if scenario == "ovn" %}
+neutron_plugin_agent: "ovn"
+{% endif %}
diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2
index 6b0c01e8c..adfaa3b7c 100644
--- a/tests/templates/inventory.j2
+++ b/tests/templates/inventory.j2
@@ -338,6 +338,9 @@ neutron
[neutron-metadata-agent:children]
neutron
+[neutron-ovn-metadata-agent:children]
+compute
+
[neutron-bgp-dragent:children]
neutron
@@ -818,3 +821,25 @@ control
[masakari-monitors:children]
compute
+
+[ovn-controller:children]
+ovn-controller-compute
+ovn-controller-network
+
+[ovn-controller-compute:children]
+compute
+
+[ovn-controller-network:children]
+network
+
+[ovn-database:children]
+control
+
+[ovn-northd:children]
+ovn-database
+
+[ovn-nb-db:children]
+ovn-database
+
+[ovn-sb-db:children]
+ovn-database
diff --git a/tests/test-ovn.sh b/tests/test-ovn.sh
new file mode 100755
index 000000000..bfb2dd99a
--- /dev/null
+++ b/tests/test-ovn.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+set -o xtrace
+set -o errexit
+set -o pipefail
+
+# Enable unbuffered output for Ansible in Jenkins.
+export PYTHONUNBUFFERED=1
+
+function test_ovn_logged {
+ # Test OVSDB cluster state
+ if [[ $BASE_DISTRO =~ ^(debian|ubuntu)$ ]]; then
+ sudo docker exec ovn_nb_db ovs-appctl -t /var/run/openvswitch/ovnnb_db.ctl cluster/status OVN_Northbound
+ sudo docker exec ovn_sb_db ovs-appctl -t /var/run/openvswitch/ovnsb_db.ctl cluster/status OVN_Southbound
+ else
+ sudo docker exec ovn_nb_db ovs-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status OVN_Northbound
+ sudo docker exec ovn_sb_db ovs-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status OVN_Southbound
+ fi
+
+ # List OVN NB/SB entries
+ sudo docker exec ovn_northd ovn-nbctl --db "tcp:192.0.2.1:6641,tcp:192.0.2.2:6641,tcp:192.0.2.3:6641" show
+ sudo docker exec ovn_northd ovn-sbctl --db "tcp:192.0.2.1:6642,tcp:192.0.2.2:6642,tcp:192.0.2.3:6642" show
+}
+
+function test_ovn {
+ echo "Testing OVN"
+ test_ovn_logged > /tmp/logs/ansible/test-ovn 2>&1
+ result=$?
+ if [[ $result != 0 ]]; then
+ echo "Testing OVN failed. See ansible/test-ovn for details"
+ else
+ echo "Successfully tested OVN. See ansible/test-ovn for details"
+ fi
+ return $result
+}
+
+test_ovn
diff --git a/tools/setup_gate.sh b/tools/setup_gate.sh
index 7dfae456c..7db77d431 100755
--- a/tools/setup_gate.sh
+++ b/tools/setup_gate.sh
@@ -64,6 +64,10 @@ function prepare_images {
GATE_IMAGES+=",^swift"
fi
+ if [[ $SCENARIO == "ovn" ]]; then
+ GATE_IMAGES+=",^ovn"
+ fi
+
if [[ $SCENARIO == "mariadb" ]]; then
GATE_IMAGES="^cron,^fluentd,^haproxy,^keepalived,^kolla-toolbox,^mariadb"
fi
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index 868f12743..225a60f00 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -158,3 +158,14 @@
- ^tests/test-core-openstack.sh
vars:
scenario: linuxbridge
+
+- job:
+ name: kolla-ansible-ovn-base
+ parent: kolla-ansible-base
+ voting: false
+ files:
+ - ^ansible/roles/(ovn|neutron)/
+ - ^tests/test-ovn.sh
+ - ^tests/test-core-openstack.sh
+ vars:
+ scenario: ovn
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 24bba6cb7..4340d094b 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -259,3 +259,19 @@
vars:
base_distro: ubuntu
install_type: source
+
+- job:
+ name: kolla-ansible-centos8-source-ovn
+ parent: kolla-ansible-ovn-base
+ nodeset: kolla-ansible-centos8-multi
+ vars:
+ base_distro: centos
+ install_type: source
+
+- job:
+ name: kolla-ansible-ubuntu-source-ovn
+ parent: kolla-ansible-ovn-base
+ nodeset: kolla-ansible-bionic-multi
+ vars:
+ base_distro: ubuntu
+ install_type: source
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index a06e55ea3..bfa83de8b 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -38,6 +38,8 @@
- kolla-ansible-centos8-source-upgrade-ceph-ansible
- kolla-ansible-ubuntu-source-upgrade-ceph-ansible
- kolla-ansible-ubuntu-source-linuxbridge
+ - kolla-ansible-centos8-source-ovn
+ - kolla-ansible-ubuntu-source-ovn
check-arm64:
jobs:
- kolla-ansible-debian-source-aarch64