Enable use of OVN for plumbing to octavia units
Depends-On: Ia304cd25dbdd130338837f149a79efe59681f794 Change-Id: I9ef24e5256ad32e7593a601fb9b79a04747d0a2e
This commit is contained in:
parent
a7c57aa732
commit
c1e86dcb4a
|
@ -44,7 +44,7 @@ def configure_resources(*args):
|
|||
'unit.')
|
||||
if not reactive.all_flags_set('identity-service.available',
|
||||
'neutron-api.available',
|
||||
'neutron-openvswitch.connected',
|
||||
'sdn-subordinate.available',
|
||||
'amqp.available'):
|
||||
return ch_core.hookenv.action_fail('all required relations not '
|
||||
'available, please defer action'
|
||||
|
|
|
@ -6,6 +6,7 @@ includes:
|
|||
- interface:keystone
|
||||
- interface:neutron-load-balancer
|
||||
- interface:neutron-plugin
|
||||
- interface:ovsdb-subordinate
|
||||
options:
|
||||
basic:
|
||||
use_venv: True
|
||||
|
|
|
@ -125,6 +125,20 @@ def init_neutron_client(keystone_session):
|
|||
)
|
||||
|
||||
|
||||
def is_extension_enabled(neutron_client, ext_alias):
|
||||
"""Check for presence of Neutron extension
|
||||
|
||||
:param neutron_client:
|
||||
:type neutron_client:
|
||||
:returns: True if Neutron lists extension, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
for extension in neutron_client.list_extensions().get('extensions', []):
|
||||
if extension.get('alias') == ext_alias:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_nova_flavor(identity_service):
|
||||
"""Get or create private Nova flavor for use with Octavia.
|
||||
|
||||
|
@ -192,7 +206,7 @@ def create_nova_keypair(identity_service, amp_key_name):
|
|||
|
||||
|
||||
def get_hm_port(identity_service, local_unit_name, local_unit_address,
|
||||
ovs_hostname=None):
|
||||
host_id=None):
|
||||
"""Get or create a per unit Neutron port for Octavia Health Manager.
|
||||
|
||||
A side effect of calling this function is that a port is created if one
|
||||
|
@ -205,8 +219,8 @@ def get_hm_port(identity_service, local_unit_name, local_unit_address,
|
|||
:param local_unit_address: DNS resolvable IP address of unit, used to
|
||||
build Neutron port ``binding:host_id``
|
||||
:type local_unit_address: str
|
||||
:param ovs_hostname: Hostname used by neutron-openvswitch
|
||||
:type ovs_hostname: Option[None,str]
|
||||
:param host_id: Identifier used by SDN for binding the port
|
||||
:type host_id: Option[None,str]
|
||||
:returns: Port details extracted from result of call to
|
||||
neutron_client.list_ports or neutron_client.create_port
|
||||
:rtype: dict
|
||||
|
@ -261,8 +275,7 @@ def get_hm_port(identity_service, local_unit_name, local_unit_address,
|
|||
# avoid race with OVS agent attempting to bind port
|
||||
# before it is created in the local units OVSDB
|
||||
'admin_state_up': False,
|
||||
'binding:host_id': (ovs_hostname or
|
||||
socket.gethostname()),
|
||||
'binding:host_id': host_id or socket.gethostname(),
|
||||
# NOTE(fnordahl): device_owner has special meaning
|
||||
# for Neutron [0], and things may break if set to
|
||||
# an arbritary value. Using a value known by Neutron
|
||||
|
@ -350,7 +363,7 @@ def toggle_hm_port(identity_service, local_unit_name, enabled=True):
|
|||
nc.update_port(port['id'], {'port': {'admin_state_up': enabled}})
|
||||
|
||||
|
||||
def setup_hm_port(identity_service, octavia_charm, ovs_hostname=None):
|
||||
def setup_hm_port(identity_service, octavia_charm, host_id=None):
|
||||
"""Create a per unit Neutron and OVS port for Octavia Health Manager.
|
||||
|
||||
This is used to plug the unit into the overlay network for direct
|
||||
|
@ -361,8 +374,8 @@ def setup_hm_port(identity_service, octavia_charm, ovs_hostname=None):
|
|||
:type identity_service: RelationBase class
|
||||
:param ocataiva_charm: charm instance
|
||||
:type octavia_charm: OctaviaCharm class instance
|
||||
:param ovs_hostname: Hostname used by neutron-openvswitch
|
||||
:type ovs_hostname: Option[None,str]
|
||||
:param host_id: Identifier used by SDN for binding the port
|
||||
:type host_id: Option[None,str]
|
||||
:retruns: True on change to local unit, False otherwise
|
||||
:rtype: bool
|
||||
:raises: api_crud.APIUnavailable, api_crud.DuplicateResource
|
||||
|
@ -372,7 +385,7 @@ def setup_hm_port(identity_service, octavia_charm, ovs_hostname=None):
|
|||
identity_service,
|
||||
octavia_charm.local_unit_name,
|
||||
octavia_charm.local_address,
|
||||
ovs_hostname=ovs_hostname)
|
||||
host_id=host_id)
|
||||
if not hm_port:
|
||||
ch_core.hookenv.log('No network tagged with `charm-octavia` '
|
||||
'exists, deferring port setup awaiting '
|
||||
|
@ -546,14 +559,19 @@ def get_mgmt_network(identity_service, create=True):
|
|||
router = None
|
||||
if n_resp < 1 and create:
|
||||
try:
|
||||
resp = nc.create_router(
|
||||
{
|
||||
'router': {
|
||||
'name': octavia.OCTAVIA_MGMT_NAME_PREFIX,
|
||||
'distributed': False,
|
||||
|
||||
}
|
||||
})
|
||||
body = {
|
||||
'router': {
|
||||
'name': octavia.OCTAVIA_MGMT_NAME_PREFIX,
|
||||
},
|
||||
}
|
||||
# NOTE(fnordahl): Using the ``distributed`` key in a request to
|
||||
# Neutron is an error when the DVR extension is not enabled.
|
||||
if is_extension_enabled(nc, 'dvr'):
|
||||
# NOTE(fnordahl): When DVR is enabled we want to use a
|
||||
# centralized router to support assigning addresses with IPv6
|
||||
# RA. LP: #1843557
|
||||
body['router'].update({'distributed': False})
|
||||
resp = nc.create_router(body)
|
||||
router = resp['router']
|
||||
nc.add_tag('routers', router['id'], 'charm-octavia')
|
||||
ch_core.hookenv.log('Created router {}'.format(router['id']),
|
||||
|
|
|
@ -326,7 +326,7 @@ class OctaviaCharm(ch_plugins.PolicydOverridePlugin,
|
|||
services = ['apache2', 'octavia-health-manager', 'octavia-housekeeping',
|
||||
'octavia-worker']
|
||||
required_relations = ['shared-db', 'amqp', 'identity-service',
|
||||
'neutron-openvswitch']
|
||||
'sdn-subordinate']
|
||||
restart_map = {
|
||||
OCTAVIA_MGMT_INTF_CONF: services + ['systemd-networkd'],
|
||||
OCTAVIA_CONF: services,
|
||||
|
@ -371,12 +371,6 @@ class OctaviaCharm(ch_plugins.PolicydOverridePlugin,
|
|||
workload status.
|
||||
"""
|
||||
states_to_check = super().states_to_check(required_relations)
|
||||
override_relation = 'neutron-openvswitch'
|
||||
if override_relation in states_to_check:
|
||||
states_to_check[override_relation] = [
|
||||
("{}.connected".format(override_relation),
|
||||
"blocked",
|
||||
"'{}' missing".format(override_relation))]
|
||||
if not leadership.leader_get('amp-boot-network-list'):
|
||||
if not reactive.is_flag_set('config.default.create-mgmt-network'):
|
||||
# we are configured to not create required resources and they
|
||||
|
|
|
@ -28,6 +28,9 @@ requires:
|
|||
neutron-openvswitch:
|
||||
interface: neutron-plugin
|
||||
scope: container
|
||||
ovsdb-subordinate:
|
||||
interface: ovsdb-subordinate
|
||||
scope: container
|
||||
resources:
|
||||
policyd-override:
|
||||
type: file
|
||||
|
|
|
@ -41,6 +41,20 @@ charm.use_defaults(
|
|||
)
|
||||
|
||||
|
||||
@reactive.when_any('neutron-openvswitch.connected',
|
||||
'ovsdb-subordinate.available')
|
||||
def sdn_joined():
|
||||
reactive.set_flag('sdn-subordinate.connected')
|
||||
reactive.set_flag('sdn-subordinate.available')
|
||||
|
||||
|
||||
@reactive.when_none('neutron-openvswitch.connected',
|
||||
'ovsdb-subordinate.available')
|
||||
def sdn_broken():
|
||||
reactive.clear_flag('sdn-subordinate.available')
|
||||
reactive.clear_flag('sdn-subordinate.connected')
|
||||
|
||||
|
||||
@reactive.when('identity-service.connected')
|
||||
def setup_endpoint_connection(keystone):
|
||||
"""Custom register endpoint function for Octavia.
|
||||
|
@ -90,7 +104,7 @@ def setup_neutron_lbaas_proxy():
|
|||
|
||||
@reactive.when('identity-service.available')
|
||||
@reactive.when('neutron-api.available')
|
||||
@reactive.when('neutron-openvswitch.connected')
|
||||
@reactive.when('sdn-subordinate.available')
|
||||
# Neutron API calls will consistently fail as long as AMQP is unavailable
|
||||
@reactive.when('amqp.available')
|
||||
def setup_hm_port():
|
||||
|
@ -100,7 +114,9 @@ def setup_hm_port():
|
|||
communication with the octavia managed load balancer instances running
|
||||
within the deployed cloud.
|
||||
"""
|
||||
ovs = reactive.endpoint_from_flag('neutron-openvswitch.connected')
|
||||
neutron_ovs = reactive.endpoint_from_flag('neutron-openvswitch.connected')
|
||||
ovsdb = reactive.endpoint_from_flag('ovsdb-subordinate.available')
|
||||
host_id = neutron_ovs.host() if neutron_ovs else ovsdb.chassis_name
|
||||
with charm.provide_charm_instance() as octavia_charm:
|
||||
identity_service = reactive.endpoint_from_flag(
|
||||
'identity-service.available')
|
||||
|
@ -108,7 +124,7 @@ def setup_hm_port():
|
|||
if api_crud.setup_hm_port(
|
||||
identity_service,
|
||||
octavia_charm,
|
||||
ovs_hostname=ovs.host()):
|
||||
host_id=host_id):
|
||||
# trigger config render to make systemd-networkd bring up
|
||||
# automatic IP configuration of the new port right now.
|
||||
reactive.set_flag('config.changed')
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
series: bionic
|
||||
relations:
|
||||
- - glance:image-service
|
||||
- nova-cloud-controller:image-service
|
||||
- - glance:image-service
|
||||
- nova-compute:image-service
|
||||
- - mysql:shared-db
|
||||
- glance:shared-db
|
||||
- - mysql:shared-db
|
||||
- keystone:shared-db
|
||||
- - mysql:shared-db
|
||||
- neutron-api:shared-db
|
||||
- - mysql:shared-db
|
||||
- nova-cloud-controller:shared-db
|
||||
- - mysql:shared-db
|
||||
- octavia:shared-db
|
||||
- - keystone:identity-service
|
||||
- glance:identity-service
|
||||
- - keystone:identity-service
|
||||
- nova-cloud-controller:identity-service
|
||||
- - keystone:identity-service
|
||||
- neutron-api:identity-service
|
||||
- - keystone:identity-service
|
||||
- octavia:identity-service
|
||||
- - nova-compute:cloud-compute
|
||||
- nova-cloud-controller:cloud-compute
|
||||
- - rabbitmq-server:amqp
|
||||
- neutron-api:amqp
|
||||
- - rabbitmq-server:amqp
|
||||
- glance:amqp
|
||||
- - rabbitmq-server:amqp
|
||||
- nova-cloud-controller:amqp
|
||||
- - rabbitmq-server:amqp
|
||||
- nova-compute:amqp
|
||||
- - rabbitmq-server:amqp
|
||||
- octavia:amqp
|
||||
- - neutron-api:neutron-api
|
||||
- nova-cloud-controller:neutron-api
|
||||
- - neutron-api:neutron-load-balancer
|
||||
- octavia:neutron-api
|
||||
- - glance-simplestreams-sync:juju-info
|
||||
- octavia-diskimage-retrofit:juju-info
|
||||
- - keystone:identity-service
|
||||
- glance-simplestreams-sync:identity-service
|
||||
- - rabbitmq-server:amqp
|
||||
- glance-simplestreams-sync:amqp
|
||||
- - keystone:identity-credentials
|
||||
- octavia-diskimage-retrofit:identity-credentials
|
||||
- [ placement, mysql ]
|
||||
- [ placement, keystone ]
|
||||
- [ placement, nova-cloud-controller ]
|
||||
- - neutron-api-plugin-ovn:neutron-plugin
|
||||
- neutron-api:neutron-plugin-api-subordinate
|
||||
- - vault:shared-db
|
||||
- mysql:shared-db
|
||||
- - ovn-central:certificates
|
||||
- vault:certificates
|
||||
- - ovn-central:ovsdb-cms
|
||||
- neutron-api-plugin-ovn:ovsdb-cms
|
||||
- - neutron-api:certificates
|
||||
- vault:certificates
|
||||
- - ovn-chassis:nova-compute
|
||||
- nova-compute:neutron-plugin
|
||||
- - ovn-chassis:ovsdb-subordinate
|
||||
- octavia:ovsdb-subordinate
|
||||
- - ovn-chassis:certificates
|
||||
- vault:certificates
|
||||
- - ovn-chassis:ovsdb
|
||||
- ovn-central:ovsdb
|
||||
- - vault:certificates
|
||||
- neutron-api-plugin-ovn:certificates
|
||||
- - vault:certificates
|
||||
- glance:certificates
|
||||
- - vault:certificates
|
||||
- keystone:certificates
|
||||
- - vault:certificates
|
||||
- nova-cloud-controller:certificates
|
||||
- - vault:certificates
|
||||
- placement:certificates
|
||||
- - vault:certificates
|
||||
- octavia:certificates
|
||||
- - vault:certificates
|
||||
- glance-simplestreams-sync:certificates
|
||||
- - hacluster-octavia:ha
|
||||
- octavia:ha
|
||||
applications:
|
||||
glance:
|
||||
charm: cs:~openstack-charmers-next/glance
|
||||
num_units: 1
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
keystone:
|
||||
charm: cs:~openstack-charmers-next/keystone
|
||||
num_units: 1
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
mysql:
|
||||
constraints: mem=3072M
|
||||
charm: cs:~openstack-charmers-next/percona-cluster
|
||||
num_units: 1
|
||||
neutron-api:
|
||||
constraints: cores=4
|
||||
charm: cs:~openstack-charmers-next/neutron-api
|
||||
num_units: 1
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
debug: True
|
||||
flat-network-providers: physnet1
|
||||
neutron-security-groups: True
|
||||
manage-neutron-plugin-legacy-mode: False
|
||||
nova-cloud-controller:
|
||||
constraints: mem=3072M
|
||||
charm: cs:~openstack-charmers-next/nova-cloud-controller
|
||||
num_units: 1
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
debug: True
|
||||
network-manager: Neutron
|
||||
nova-compute:
|
||||
constraints: mem=10240M
|
||||
charm: cs:~openstack-charmers-next/nova-compute
|
||||
num_units: 2
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
debug: True
|
||||
hacluster-octavia:
|
||||
series: bionic
|
||||
charm: cs:~openstack-charmers-next/hacluster
|
||||
octavia:
|
||||
series: bionic
|
||||
charm: ../../../octavia
|
||||
num_units: 3
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
debug: True
|
||||
spare-pool-size: 2
|
||||
loadbalancer-topology: 'ACTIVE_STANDBY'
|
||||
rabbitmq-server:
|
||||
charm: cs:~openstack-charmers-next/rabbitmq-server
|
||||
num_units: 1
|
||||
glance-simplestreams-sync:
|
||||
charm: cs:~openstack-charmers-next/glance-simplestreams-sync
|
||||
num_units: 1
|
||||
options:
|
||||
source: ppa:simplestreams-dev/trunk
|
||||
use_swift: False
|
||||
octavia-diskimage-retrofit:
|
||||
charm: cs:~openstack-charmers-next/octavia-diskimage-retrofit
|
||||
options:
|
||||
amp-image-tag: 'octavia-amphora'
|
||||
retrofit-uca-pocket: train
|
||||
placement:
|
||||
charm: cs:~openstack-charmers-next/placement
|
||||
num_units: 1
|
||||
constraints: mem=1G
|
||||
options:
|
||||
openstack-origin: cloud:bionic-train
|
||||
debug: true
|
||||
neutron-api-plugin-ovn:
|
||||
charm: cs:~openstack-charmers-next/neutron-api-plugin-ovn
|
||||
ovn-central:
|
||||
constraints: mem=3072M
|
||||
charm: cs:~openstack-charmers-next/ovn-central
|
||||
num_units: 3
|
||||
options:
|
||||
source: cloud:bionic-train
|
||||
ovn-chassis:
|
||||
charm: cs:~openstack-charmers-next/ovn-chassis
|
||||
vault:
|
||||
charm: cs:~openstack-charmers-next/vault
|
||||
num_units: 1
|
|
@ -0,0 +1 @@
|
|||
ha.j2
|
|
@ -1,9 +1,11 @@
|
|||
charm_name: octavia
|
||||
gate_bundles:
|
||||
- bionic-train-ha-ovn
|
||||
- bionic-train-ha
|
||||
- bionic-stein-ha
|
||||
- bionic-rocky-ha
|
||||
smoke_bundles:
|
||||
- bionic-train-ha-ovn
|
||||
- bionic-train-ha
|
||||
comment: |
|
||||
Move `disco-stein` backup to dev pending LP: #1841599
|
||||
|
@ -22,6 +24,15 @@ target_deploy_status:
|
|||
vault:
|
||||
workload-status: blocked
|
||||
workload-status-message: Vault needs to be initialized
|
||||
neutron-api-plugin-ovn:
|
||||
workload-status: waiting
|
||||
workload-status-message: "'ovsdb-cms' incomplete"
|
||||
ovn-central:
|
||||
workload-status: blocked
|
||||
workload-status-message: "'certificates' missing"
|
||||
ovn-chassis:
|
||||
workload-status: blocked
|
||||
workload-status-message: "'certificates' missing"
|
||||
configure:
|
||||
- zaza.openstack.charm_tests.vault.setup.auto_initialize
|
||||
- zaza.openstack.charm_tests.glance.setup.add_lts_image
|
||||
|
@ -37,7 +48,6 @@ comment: |
|
|||
The repetition of ``prepare_payload_instance`` is intentional and gives the
|
||||
test multiple backends to feed Octavia.
|
||||
tests:
|
||||
- zaza.openstack.charm_tests.neutron_openvswitch.tests.NeutronOpenvSwitchOverlayTest
|
||||
- zaza.openstack.charm_tests.octavia.tests.LBAASv2Test
|
||||
- zaza.openstack.charm_tests.octavia.tests.CharmOperationTest
|
||||
- zaza.openstack.charm_tests.policyd.tests.OctaviaTests
|
||||
|
|
|
@ -185,7 +185,7 @@ class TestAPICrud(test_utils.PatchHelper):
|
|||
result = api_crud.get_hm_port(identity_service,
|
||||
'fake-unit-name',
|
||||
'192.0.2.42',
|
||||
ovs_hostname='fake-unit-name.fqdn')
|
||||
host_id='fake-unit-name.fqdn')
|
||||
nc.create_port.assert_called_once_with(
|
||||
{
|
||||
'port': {
|
||||
|
@ -239,7 +239,7 @@ class TestAPICrud(test_utils.PatchHelper):
|
|||
identity_service,
|
||||
octavia_charm.local_unit_name,
|
||||
octavia_charm.local_address,
|
||||
ovs_hostname=None)
|
||||
host_id=None)
|
||||
self.check_output.assert_called_with(
|
||||
['ip', 'link', 'show', api_crud.octavia.OCTAVIA_MGMT_INTF],
|
||||
stderr=-2, universal_newlines=True)
|
||||
|
@ -300,6 +300,8 @@ class TestAPICrud(test_utils.PatchHelper):
|
|||
{'security_group': {'id': self.secgrp_uuid}},
|
||||
{'security_group': {'id': self.health_secgrp_uuid}},
|
||||
]
|
||||
self.patch_object(api_crud, 'is_extension_enabled')
|
||||
self.is_extension_enabled.return_value = True
|
||||
result = api_crud.get_mgmt_network(identity_service)
|
||||
nc.list_networks.assert_called_once_with(tags=resource_tag)
|
||||
nc.create_network.assert_called_once_with({
|
||||
|
|
|
@ -51,7 +51,7 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
|||
'setup_hm_port': (
|
||||
'identity-service.available',
|
||||
'neutron-api.available',
|
||||
'neutron-openvswitch.connected',
|
||||
'sdn-subordinate.available',
|
||||
'amqp.available',),
|
||||
'update_controller_ip_port_list': (
|
||||
'leadership.is_leader',
|
||||
|
@ -61,6 +61,14 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
|||
'setup_endpoint_connection': (
|
||||
'identity-service.connected',),
|
||||
},
|
||||
'when_any': {
|
||||
'sdn_joined': ('neutron-openvswitch.connected',
|
||||
'ovsdb-subordinate.available'),
|
||||
},
|
||||
'when_none': {
|
||||
'sdn_broken': ('neutron-openvswitch.connected',
|
||||
'ovsdb-subordinate.available'),
|
||||
},
|
||||
'when_not': {
|
||||
'init_db': ('db.synced',),
|
||||
'cluster_connected': ('ha.available',),
|
||||
|
@ -125,8 +133,18 @@ class TestOctaviaHandlers(test_utils.PatchHelper):
|
|||
self.setup_hm_port.assert_called_with(
|
||||
self.endpoint_from_flag(),
|
||||
self.octavia_charm,
|
||||
ovs_hostname=self.endpoint_from_flag().host())
|
||||
host_id=self.endpoint_from_flag().host())
|
||||
self.set_flag.assert_called_once_with('config.changed')
|
||||
self.setup_hm_port.reset_mock()
|
||||
ovsdb_subordinate = mock.MagicMock()
|
||||
identity_service = mock.MagicMock()
|
||||
self.endpoint_from_flag.side_effect = [
|
||||
None, ovsdb_subordinate, identity_service]
|
||||
handlers.setup_hm_port()
|
||||
self.setup_hm_port.assert_called_with(
|
||||
identity_service,
|
||||
self.octavia_charm,
|
||||
host_id=ovsdb_subordinate.chassis_name)
|
||||
|
||||
def test_update_controller_ip_port_list(self):
|
||||
self.patch('charms.reactive.endpoint_from_flag', 'endpoint_from_flag')
|
||||
|
|
Loading…
Reference in New Issue