From 7a066f715467db56a637dd69de3e86419a0e58de Mon Sep 17 00:00:00 2001 From: Michal Nasiadka Date: Mon, 9 Nov 2020 10:17:10 +0100 Subject: [PATCH] Add missing octavia-driver-agent For using 3rd party Octavia providers (such as OVN provider) an octavia-driver-agent container must be running to expose those providers to use. OVN CI job has been extended with deploying Octavia and testing OVN Load Balancer. Closes-Bug: #1903506 Depends-On: https://review.opendev.org/c/openstack/kolla/+/771191 Change-Id: Ibafa8b7307981f2a51e630cc113d18af6162171c --- ansible/group_vars/all.yml | 1 + ansible/inventory/all-in-one | 3 + ansible/inventory/multinode | 3 + ansible/roles/octavia/defaults/main.yml | 25 ++++++ ansible/roles/octavia/handlers/main.yml | 15 ++++ .../octavia/templates/octavia-api.json.j2 | 6 ++ .../templates/octavia-driver-agent.json.j2 | 23 +++++ .../roles/octavia/templates/octavia.conf.j2 | 11 +++ etc/kolla/globals.yml | 1 + .../notes/bug-1903506-12ae72c114bede72.yaml | 8 ++ tests/run.yml | 2 +- tests/setup_gate.sh | 5 +- tests/templates/globals-default.j2 | 2 + tests/templates/inventory.j2 | 3 + tests/test-ovn.sh | 90 +++++++++++++++++-- zuul.d/base.yaml | 2 +- 16 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 ansible/roles/octavia/templates/octavia-driver-agent.json.j2 create mode 100644 releasenotes/notes/bug-1903506-12ae72c114bede72.yaml diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index fac4d01907..c41e691d12 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -660,6 +660,7 @@ enable_neutron_port_forwarding: "no" enable_nova_serialconsole_proxy: "no" enable_nova_ssh: "yes" enable_octavia: "no" +enable_octavia_driver_agent: "{{ enable_octavia | bool and neutron_plugin_agent == 'ovn' }}" enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}" enable_ovn: "{{ enable_neutron | bool and neutron_plugin_agent == 'ovn' }}" enable_ovs_dpdk: "no" diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one index ef29a05595..cc827a42e1 100644 --- a/ansible/inventory/all-in-one +++ b/ansible/inventory/all-in-one @@ -598,6 +598,9 @@ senlin [octavia-api:children] octavia +[octavia-driver-agent:children] +octavia + [octavia-health-manager:children] octavia diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode index 36731ca9f4..e843bb7592 100644 --- a/ansible/inventory/multinode +++ b/ansible/inventory/multinode @@ -616,6 +616,9 @@ senlin [octavia-api:children] octavia +[octavia-driver-agent:children] +octavia + [octavia-health-manager:children] octavia diff --git a/ansible/roles/octavia/defaults/main.yml b/ansible/roles/octavia/defaults/main.yml index c349a93946..9876bf62bd 100644 --- a/ansible/roles/octavia/defaults/main.yml +++ b/ansible/roles/octavia/defaults/main.yml @@ -21,6 +21,13 @@ octavia_services: mode: "http" external: true port: "{{ octavia_api_port }}" + octavia-driver-agent: + container_name: octavia_driver_agent + group: octavia-driver-agent + enabled: "{{ enable_octavia_driver_agent }}" + image: "{{ octavia_driver_agent_image_full }}" + volumes: "{{ octavia_driver_agent_default_volumes + octavia_driver_agent_extra_volumes }}" + dimensions: "{{ octavia_driver_agent_dimensions }}" octavia-health-manager: container_name: octavia_health_manager group: octavia-health-manager @@ -72,6 +79,10 @@ octavia_api_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ doc octavia_api_tag: "{{ octavia_tag }}" octavia_api_image_full: "{{ octavia_api_image }}:{{ octavia_api_tag }}" +octavia_driver_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ octavia_install_type }}-octavia-driver-agent" +octavia_driver_agent_tag: "{{ octavia_tag }}" +octavia_driver_agent_image_full: "{{ octavia_driver_agent_image }}:{{ octavia_driver_agent_tag }}" + octavia_health_manager_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ octavia_install_type }}-octavia-health-manager" octavia_health_manager_tag: "{{ octavia_tag }}" octavia_health_manager_image_full: "{{ octavia_health_manager_image }}:{{ octavia_health_manager_tag }}" @@ -85,6 +96,7 @@ octavia_worker_tag: "{{ octavia_tag }}" octavia_worker_image_full: "{{ octavia_worker_image }}:{{ octavia_worker_tag }}" octavia_api_dimensions: "{{ default_container_dimensions }}" +octavia_driver_agent_dimensions: "{{ default_container_dimensions }}" octavia_health_manager_dimensions: "{{ default_container_dimensions }}" octavia_housekeeping_dimensions: "{{ default_container_dimensions }}" octavia_worker_dimensions: "{{ default_container_dimensions }}" @@ -147,12 +159,20 @@ octavia_api_default_volumes: - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_os_family == 'Debian' else '' }}" - "kolla_logs:/var/log/kolla/" - "{{ kolla_dev_repos_directory ~ '/octavia/octavia:/var/lib/kolla/venv/lib/python' ~ distro_python_version ~ '/site-packages/octavia' if octavia_dev_mode | bool else '' }}" + - "octavia_driver_agent:/var/run/octavia/" octavia_health_manager_default_volumes: - "{{ node_config_directory }}/octavia-health-manager/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_os_family == 'Debian' else '' }}" - "kolla_logs:/var/log/kolla/" - "{{ kolla_dev_repos_directory ~ '/octavia/octavia:/var/lib/kolla/venv/lib/python' ~ distro_python_version ~ '/site-packages/octavia' if octavia_dev_mode | bool else '' }}" +octavia_driver_agent_default_volumes: + - "{{ node_config_directory }}/octavia-driver-agent/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_os_family == 'Debian' else '' }}" + - "kolla_logs:/var/log/kolla/" + - "{{ kolla_dev_repos_directory ~ '/octavia/octavia:/var/lib/kolla/venv/lib/python' ~ distro_python_version ~ '/site-packages/octavia' if octavia_dev_mode | bool else '' }}" + - "octavia_driver_agent:/var/run/octavia/" octavia_housekeeping_default_volumes: - "{{ node_config_directory }}/octavia-housekeeping/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" @@ -168,6 +188,7 @@ octavia_worker_default_volumes: octavia_extra_volumes: "{{ default_extra_volumes }}" octavia_api_extra_volumes: "{{ octavia_extra_volumes }}" +octavia_driver_agent_extra_volumes: "{{ octavia_extra_volumes }}" octavia_health_manager_extra_volumes: "{{ octavia_extra_volumes }}" octavia_housekeeping_extra_volumes: "{{ octavia_extra_volumes }}" octavia_worker_extra_volumes: "{{ octavia_extra_volumes }}" @@ -302,3 +323,7 @@ octavia_amp_network: # Octavia management network subnet CIDR. octavia_amp_network_cidr: 10.1.0.0/24 + +# Octavia provider drivers +octavia_provider_drivers: "amphora:Amphora provider{% if neutron_plugin_agent == 'ovn'%}, ovn:OVN provider{% endif %}" +octavia_provider_agents: "amphora_agent{% if neutron_plugin_agent == 'ovn'%}, ovn{% endif %}" diff --git a/ansible/roles/octavia/handlers/main.yml b/ansible/roles/octavia/handlers/main.yml index a8791b2e8b..139538ea91 100644 --- a/ansible/roles/octavia/handlers/main.yml +++ b/ansible/roles/octavia/handlers/main.yml @@ -15,6 +15,21 @@ when: - kolla_action != "config" +- name: Restart octavia-driver-agent container + vars: + service_name: "octavia-driver-agent" + service: "{{ octavia_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 octavia-health-manager container vars: service_name: "octavia-health-manager" diff --git a/ansible/roles/octavia/templates/octavia-api.json.j2 b/ansible/roles/octavia/templates/octavia-api.json.j2 index 0e315bebc8..e62a7dc68e 100644 --- a/ansible/roles/octavia/templates/octavia-api.json.j2 +++ b/ansible/roles/octavia/templates/octavia-api.json.j2 @@ -13,5 +13,11 @@ "owner": "octavia", "perm": "0600" }{% endif %} + ], + "permissions": [ + { + "path": "/var/run/octavia", + "owner": "octavia:octavia" + } ] } diff --git a/ansible/roles/octavia/templates/octavia-driver-agent.json.j2 b/ansible/roles/octavia/templates/octavia-driver-agent.json.j2 new file mode 100644 index 0000000000..cde7b33607 --- /dev/null +++ b/ansible/roles/octavia/templates/octavia-driver-agent.json.j2 @@ -0,0 +1,23 @@ +{ + "command": "octavia-driver-agent --config-file /etc/octavia/octavia.conf", + "config_files": [ + { + "source": "{{ container_config_directory }}/octavia.conf", + "dest": "/etc/octavia/octavia.conf", + "owner": "octavia", + "perm": "0600" + }{% if octavia_policy_file is defined %}, + { + "source": "{{ container_config_directory }}/{{ octavia_policy_file }}", + "dest": "/etc/octavia/{{ octavia_policy_file }}", + "owner": "octavia", + "perm": "0600" + }{% endif %} + ], + "permissions": [ + { + "path": "/var/run/octavia", + "owner": "octavia:octavia" + } + ] +} diff --git a/ansible/roles/octavia/templates/octavia.conf.j2 b/ansible/roles/octavia/templates/octavia.conf.j2 index d09e3cdc4f..190dcc75d7 100644 --- a/ansible/roles/octavia/templates/octavia.conf.j2 +++ b/ansible/roles/octavia/templates/octavia.conf.j2 @@ -19,6 +19,17 @@ endpoint_type = internal ca_certificates_file = {{ openstack_cacert }} {% endif %} +[api_settings] +enabled_provider_drivers = '{{ octavia_provider_drivers }}' + +[driver_agent] +enabled_provider_agents = {{ octavia_provider_agents }} + +{% if neutron_plugin_agent == 'ovn' %} +[ovn] +ovn_nb_connection = {{ ovn_nb_connection }} +{% endif %} + [haproxy_amphora] server_ca = /etc/octavia/certs/server_ca.cert.pem client_cert = /etc/octavia/certs/client.cert-and-key.pem diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml index 2b10d29f3f..069c967010 100644 --- a/etc/kolla/globals.yml +++ b/etc/kolla/globals.yml @@ -358,6 +358,7 @@ #enable_nova_serialconsole_proxy: "no" #enable_nova_ssh: "yes" #enable_octavia: "no" +#enable_octavia_driver_agent: "{{ enable_octavia | bool and neutron_plugin_agent == 'ovn' }}" #enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}" #enable_ovn: "{{ enable_neutron | bool and neutron_plugin_agent == 'ovn' }}" #enable_ovs_dpdk: "no" diff --git a/releasenotes/notes/bug-1903506-12ae72c114bede72.yaml b/releasenotes/notes/bug-1903506-12ae72c114bede72.yaml new file mode 100644 index 0000000000..23e9a5f50a --- /dev/null +++ b/releasenotes/notes/bug-1903506-12ae72c114bede72.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add ``octavia-driver-agent`` to ``Octavia`` deployments to allow for + additional providers, e.g. ``ovn-octavia-provider``. It is automatically + deployed when ``Octavia`` is enabled and ``neutron_plugin_agent`` is set + to ``ovn``. It can be also enabled by setting + ``enable_octavia_driver_agent`` to ``yes``. diff --git a/tests/run.yml b/tests/run.yml index 143f2f4060..2e51fa97d3 100644 --- a/tests/run.yml +++ b/tests/run.yml @@ -269,7 +269,7 @@ # same host being used by both) - name: create TLS certificates for octavia command: kolla-ansible octavia-certificates - when: scenario == 'octavia' + when: scenario in ['octavia', 'ovn'] # NOTE(mgoddard): We are using the script module here and later to ensure # we use the local copy of these scripts, rather than the one on the remote diff --git a/tests/setup_gate.sh b/tests/setup_gate.sh index f362adaef5..3ec24be67c 100755 --- a/tests/setup_gate.sh +++ b/tests/setup_gate.sh @@ -32,6 +32,9 @@ function setup_openstack_clients { if [[ $SCENARIO == monasca ]]; then packages+=(python-monascaclient) fi + if [[ $SCENARIO == ovn ]]; then + packages+=(python-octaviaclient) + fi if [[ "debian" == $BASE_DISTRO ]]; then sudo apt -y install python3-venv fi @@ -83,7 +86,7 @@ function prepare_images { fi if [[ $SCENARIO == "ovn" ]]; then - GATE_IMAGES+=",^ovn" + GATE_IMAGES+=",^octavia,^ovn" fi if [[ $SCENARIO == "mariadb" ]]; then diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2 index 7298c462f6..91e8aed195 100644 --- a/tests/templates/globals-default.j2 +++ b/tests/templates/globals-default.j2 @@ -149,6 +149,8 @@ neutron_plugin_agent: "linuxbridge" {% if scenario == "ovn" %} neutron_plugin_agent: "ovn" +neutron_ovn_distributed_fip: "yes" +enable_octavia: "yes" {% endif %} {% if scenario == "prometheus-efk" %} diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2 index f8156ba341..27797ae990 100644 --- a/tests/templates/inventory.j2 +++ b/tests/templates/inventory.j2 @@ -648,6 +648,9 @@ senlin [octavia-api:children] octavia +[octavia-driver-agent:children] +octavia + [octavia-health-manager:children] octavia diff --git a/tests/test-ovn.sh b/tests/test-ovn.sh index bf47f3de50..9ed1906195 100755 --- a/tests/test-ovn.sh +++ b/tests/test-ovn.sh @@ -7,7 +7,7 @@ set -o pipefail # Enable unbuffered output export PYTHONUNBUFFERED=1 -function test_ovn_logged { +function test_ovn { # NOTE(yoctozepto): could use real ini parsing but this is fine for now local neutron_ml2_conf_path=/etc/kolla/neutron-server/ml2_conf.ini ovn_nb_connection=$(sudo grep -P -o -e "(?<=^ovn_nb_connection = ).*" "$neutron_ml2_conf_path") @@ -42,9 +42,87 @@ function test_ovn_logged { fi } -function test_ovn { - echo "Testing OVN" - test_ovn_logged > /tmp/logs/ansible/test-ovn 2>&1 +function test_octavia { + . /etc/kolla/admin-openrc.sh + . ~/openstackclient-venv/bin/activate + echo "Testing OVN Octavia provider" + echo "Smoke test" + openstack loadbalancer list + + # Create a server to act as a backend + openstack server create --wait --image cirros --flavor m1.tiny --key-name mykey --network demo-net lb_member --wait + member_fip=$(openstack floating ip create public1 -f value -c floating_ip_address) + openstack server add floating ip lb_member ${member_fip} + member_ip=$(openstack floating ip show ${member_fip} -f value -c fixed_ip_address) + + # Dummy HTTP server. + attempts=12 + for i in $(seq 1 ${attempts}); do + if ssh -v -o BatchMode=yes -o StrictHostKeyChecking=no cirros@${member_fip} 'nohup sh -c "while true; do echo -e \"HTTP/1.1 200 OK\n\n $(date)\" | sudo nc -l -p 8000; done &"'; then + break + elif [[ $i -eq ${attempts} ]]; then + echo "Failed to access server via SSH after ${attempts} attempts" + echo "Console log:" + openstack console log show lb_member + return 1 + else + echo "Cannot access server - retrying" + fi + sleep 10 + done + + echo "Creating Octavia OVN LB:" + openstack loadbalancer create --vip-network-id demo-net --provider ovn --name test_ovn_lb --wait + openstack loadbalancer listener create --protocol TCP --protocol-port 8000 --name test_ovn_lb_listener --wait test_ovn_lb + openstack loadbalancer pool create --protocol TCP --lb-algorithm SOURCE_IP_PORT --listener test_ovn_lb_listener --name test_ovn_lb_pool --wait + subnet_id=$(openstack subnet list -c ID -f value --name demo-subnet) + openstack loadbalancer member create --address ${member_ip} --subnet-id ${subnet_id} --protocol-port 8000 --wait test_ovn_lb_pool + echo "Add a floating IP to the load balancer." + lb_fip=$(openstack floating ip create public1 -f value -c name) + lb_vip=$(openstack loadbalancer show test_ovn_lb -f value -c vip_address) + lb_port_id=$(openstack port list --fixed-ip ip-address=$lb_vip -f value -c ID) + openstack floating ip set $lb_fip --port $lb_port_id + + echo "OVN NB entries for LB:" + sudo docker exec ovn_northd ovn-nbctl --db "$ovn_nb_connection" list load_balancer + echo "OVN NB entries for NAT:" + sudo docker exec ovn_northd ovn-nbctl --db "$ovn_nb_connection" list nat + + echo "Attempt to access the load balanced HTTP server." + attempts=12 + curl_args=( + --include + --location + --fail + ) + for i in $(seq 1 ${attempts}); do + if curl "${curl_args[@]}" $lb_fip:8000; then + break + elif [[ $i -eq ${attempts} ]]; then + echo "Failed to access load balanced service after ${attempts} attempts" + return 1 + else + echo "Cannot access load balancer - retrying" + fi + sleep 10 + done + + echo "Cleaning up" + openstack loadbalancer delete test_ovn_lb --cascade --wait + openstack floating ip delete ${lb_fip} + openstack server remove floating ip lb_member ${member_fip} + openstack floating ip delete ${member_fip} + openstack server delete --wait lb_member +} + +function test_ovn_logged { + test_ovn + test_octavia +} + +function test_ovn_setup { + echo "Testing OVN and Octavia OVN provider" + test_ovn_logged &> /tmp/logs/ansible/test-ovn result=$? if [[ $result != 0 ]]; then echo "Testing OVN failed. See ansible/test-ovn for details" @@ -54,4 +132,6 @@ function test_ovn { return $result } -test_ovn + + +test_ovn_setup diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index f315d25afc..a580da819b 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -209,7 +209,7 @@ parent: kolla-ansible-base voting: false files: - - ^ansible/roles/(neutron|openvswitch|ovn)/ + - ^ansible/roles/(neutron|octavia|openvswitch|ovn)/ - ^tests/test-ovn.sh - ^tests/test-core-openstack.sh vars: