Infer ASn from deployment for BGP speaker test configuration

This commit is contained in:
Frode Nordahl
2018-05-08 15:38:31 +02:00
parent 3684d199d5
commit 64b2d3de8b
4 changed files with 159 additions and 2 deletions
@@ -155,3 +155,46 @@ class TestJujuUtils(ut_utils.BaseTestCase):
# Fatal failure
with self.assertRaises(Exception):
juju_utils.remote_run(self.unit, _cmd, fatal=True)
def test_get_unit_names(self):
self.patch('zaza.model.get_first_unit_name', new_callable=mock.Mock(),
name='_get_first_unit_name')
juju_utils._get_unit_names(['aunit/0', 'otherunit/0'])
self.assertFalse(self._get_first_unit_name.called)
def test_get_unit_names_called_with_application_name(self):
self.patch_object(juju_utils, 'model')
juju_utils._get_unit_names(['aunit', 'otherunit/0'])
self.model.get_first_unit_name.assert_called()
def test_get_relation_from_unit(self):
self.patch_object(juju_utils, 'lifecycle_utils')
self.patch_object(juju_utils, '_get_unit_names')
self.patch_object(juju_utils, 'yaml')
self.patch_object(juju_utils, 'model')
self._get_unit_names.return_value = ['aunit/0', 'otherunit/0']
data = {'foo': 'bar'}
self.model.get_relation_id.return_value = 42
self.model.run_on_unit.return_value = {'Code': 0, 'Stdout': str(data)}
juju_utils.get_relation_from_unit('aunit/0', 'otherunit/0',
'arelation')
self.model.run_on_unit.assert_called_with(
self.lifecycle_utils.get_juju_model(), 'aunit/0',
'relation-get --format=yaml -r "42" - "otherunit/0"')
self.yaml.load.assert_called_with(str(data))
def test_get_relation_from_unit_fails(self):
self.patch_object(juju_utils, 'lifecycle_utils')
self.patch_object(juju_utils, '_get_unit_names')
self.patch_object(juju_utils, 'yaml')
self.patch_object(juju_utils, 'model')
self._get_unit_names.return_value = ['aunit/0', 'otherunit/0']
self.model.get_relation_id.return_value = 42
self.model.run_on_unit.return_value = {'Code': 1, 'Stderr': 'ERROR'}
with self.assertRaises(Exception):
juju_utils.get_relation_from_unit('aunit/0', 'otherunit/0',
'arelation')
self.model.run_on_unit.assert_called_with(
self.lifecycle_utils.get_juju_model(), 'aunit/0',
'relation-get --format=yaml -r "42" - "otherunit/0"')
self.assertFalse(self.yaml.load.called)
+16 -2
View File
@@ -6,6 +6,7 @@ import sys
from zaza.utilities import (
cli as cli_utils,
openstack as openstack_utils,
juju as juju_utils,
)
@@ -24,6 +25,19 @@ def setup_bgp_speaker(peer_application_name, keystone_session=None):
:returns: None
:rtype: None
"""
# Get ASNs from deployment
dr_relation = juju_utils.get_relation_from_unit(
'neutron-dynamic-routing',
peer_application_name,
'bgpclient')
peer_asn = dr_relation.get('asn')
logging.debug('peer ASn: "{}"'.format(peer_asn))
peer_relation = juju_utils.get_relation_from_unit(
peer_application_name,
'neutron-dynamic-routing',
'bgp-speaker')
dr_asn = peer_relation.get('asn')
logging.debug('our ASn: "{}"'.format(dr_asn))
# If a session has not been provided, acquire one
if not keystone_session:
@@ -36,7 +50,7 @@ def setup_bgp_speaker(peer_application_name, keystone_session=None):
# Create BGP speaker
logging.info("Setting up BGP speaker")
bgp_speaker = openstack_utils.create_bgp_speaker(
neutron_client, local_as=12345)
neutron_client, local_as=dr_asn)
# Add networks to bgp speaker
logging.info("Advertising BGP routes")
@@ -53,7 +67,7 @@ def setup_bgp_speaker(peer_application_name, keystone_session=None):
logging.info("Setting up BGP peer")
bgp_peer = openstack_utils.create_bgp_peer(neutron_client,
peer_application_name,
remote_as=10000)
remote_as=peer_asn)
# Add peer to bgp speaker
logging.info("Adding BGP peer to BGP speaker")
openstack_utils.add_peer_to_bgp_speaker(
+29
View File
@@ -654,6 +654,35 @@ block_until_file_has_contents = sync_wrapper(
async_block_until_file_has_contents)
async def async_get_relation_id(model_name, application_name,
remote_application_name,
remote_interface_name=None):
"""
Get relation id of relation from model
:param model_name: Name of model to operate on
:type model_name: str
:param application_name: Name of application on this side of relation
:type application_name: str
:param remote_application_name: Name of application on other side of
relation
:type remote_application_name: str
:param remote_interface_name: Name of interface on remote end of relation
:type remote_interface_name: Optional(str)
:returns: Relation id of relation if found or None
:rtype: any
"""
async with run_in_model(model_name) as model:
for rel in model.applications[application_name].relations:
spec = '{}'.format(remote_application_name)
if remote_interface_name is not None:
spec += ':{}'.format(remote_interface_name)
if rel.matches(spec):
return(rel.id)
get_relation_id = sync_wrapper(async_get_relation_id)
def main():
# Run the deploy coroutine in an asyncio event loop, using a helper
# that abstracts loop creation and teardown.
+71
View File
@@ -1,7 +1,21 @@
#!/usr/bin/env python3
# Copyright 2018 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from pathlib import Path
import yaml
from zaza import (
model,
@@ -169,3 +183,60 @@ def remote_run(unit, remote_cmd, timeout=None, fatal=None):
raise Exception("Error running remote command: {}"
.format(result.get("Stderr")))
return result.get("Stderr")
def _get_unit_names(names):
"""
Helper function that resolves application names to first unit name of
said application. Any already resolved unit names are returned as-is.
:param units: List of units/applications to translate
:returns: List of units
:rtype: list
"""
result = []
for name in names:
if '/' in name:
result.append(name)
else:
result.append(
model.get_first_unit_name(lifecycle_utils.get_juju_model(),
name))
return result
def get_relation_from_unit(entity, remote_entity, remote_interface_name):
"""
Get relation data for relation with `remote_interface_name` between
`entity` and `remote_entity` from the perspective of `entity`.
`entity` and `remote_entity` may refer to either a application or a
specific unit. If application name is given first unit is found in model.
:param entity: Application or unit to get relation data from
:type entity: str
:param remote_entity: Application or Unit in the other end of the relation
we want to query
:type remote_entity: str
:param remote_interface_name: Name of interface to query on remote end of
relation
:type remote_interface_name: str
:returns: dict with relation data
:rtype: dict
"""
application = entity.split('/')[0]
remote_application = remote_entity.split('/')[0]
rid = model.get_relation_id(lifecycle_utils.get_juju_model(), application,
remote_application,
remote_interface_name=remote_interface_name)
(unit, remote_unit) = _get_unit_names([entity, remote_entity])
result = model.run_on_unit(
lifecycle_utils.get_juju_model(), unit,
'relation-get --format=yaml -r "{}" - "{}"'
.format(rid, remote_unit)
)
if result and int(result.get('Code')) == 0:
return yaml.load(result.get('Stdout'))
else:
raise Exception('Error running remote command: "{}"'
.format(result.get("Stderr")))