First set of updates to set model name explicitly

This commit is contained in:
Liam Young
2019-11-25 10:49:50 +00:00
parent de1d0c51a1
commit 748915646a
4 changed files with 148 additions and 65 deletions

View File

@@ -93,7 +93,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
def test_get_full_juju_status(self):
self.assertEqual(juju_utils.get_full_juju_status(), self.juju_status)
self.model.get_status.assert_called_once_with()
self.model.get_status.assert_called_once_with(model_name=None)
def test_get_machines_for_application(self):
self.patch_object(juju_utils, "get_application_status")
@@ -106,7 +106,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
self.get_application_status.assert_called_once()
# Subordinate application has no units
def _get_application_status(application):
def _get_application_status(application, model_name=None):
_apps = {
self.application: self.application_data,
self.subordinate_application:
@@ -155,7 +155,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
self.application)),
self.machine_data.get("instance-id"))
self.get_machines_for_application.assert_called_once_with(
self.application)
self.application, model_name=None)
def test_get_provider_type(self):
self.patch_object(juju_utils, "get_cloud_configs")
@@ -171,12 +171,17 @@ class TestJujuUtils(ut_utils.BaseTestCase):
self.assertEqual(juju_utils.remote_run(self.unit, _cmd),
self.run_output["Stdout"])
self.model.run_on_unit.assert_called_once_with(
self.unit, _cmd, timeout=None)
self.unit, _cmd, timeout=None, model_name=None)
# Non-fatal failure
self.model.run_on_unit.return_value = self.error_run_output
self.assertEqual(juju_utils.remote_run(self.unit, _cmd, fatal=False),
self.error_run_output["Stderr"])
self.assertEqual(
juju_utils.remote_run(
self.unit,
_cmd,
fatal=False,
model_name=None),
self.error_run_output["Stderr"])
# Fatal failure
with self.assertRaises(Exception):
@@ -205,7 +210,8 @@ class TestJujuUtils(ut_utils.BaseTestCase):
'arelation')
self.model.run_on_unit.assert_called_with(
'aunit/0',
'relation-get --format=yaml -r "42" - "otherunit/0"')
'relation-get --format=yaml -r "42" - "otherunit/0"',
model_name=None)
self.yaml.safe_load.assert_called_with(str(data))
def test_get_relation_from_unit_fails(self):
@@ -220,7 +226,8 @@ class TestJujuUtils(ut_utils.BaseTestCase):
'arelation')
self.model.run_on_unit.assert_called_with(
'aunit/0',
'relation-get --format=yaml -r "42" - "otherunit/0"')
'relation-get --format=yaml -r "42" - "otherunit/0"',
model_name=None)
self.assertFalse(self.yaml.safe_load.called)
def test_leader_get(self):
@@ -231,7 +238,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
'Code': 0, 'Stdout': str(data)}
juju_utils.leader_get('application')
self.model.run_on_leader.assert_called_with(
'application', 'leader-get --format=yaml ')
'application', 'leader-get --format=yaml ', model_name=None)
self.yaml.safe_load.assert_called_with(str(data))
def test_leader_get_key(self):
@@ -242,7 +249,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
'Code': 0, 'Stdout': data['foo']}
juju_utils.leader_get('application', 'foo')
self.model.run_on_leader.assert_called_with(
'application', 'leader-get --format=yaml foo')
'application', 'leader-get --format=yaml foo', model_name=None)
self.yaml.safe_load.assert_called_with(data['foo'])
def test_leader_get_fails(self):
@@ -253,7 +260,8 @@ class TestJujuUtils(ut_utils.BaseTestCase):
with self.assertRaises(Exception):
juju_utils.leader_get('application')
self.model.run_on_leader.assert_called_with(
'application', 'leader-get --format=yaml ')
'application', 'leader-get --format=yaml ',
model_name=None)
self.assertFalse(self.yaml.safe_load.called)
def test_get_machine_series(self):
@@ -267,6 +275,7 @@ class TestJujuUtils(ut_utils.BaseTestCase):
actual = juju_utils.get_machine_series('6')
self._get_machine_status.assert_called_with(
machine='6',
key='series'
key='series',
model_name=None
)
self.assertEqual(expected, actual)

View File

@@ -85,21 +85,23 @@ def get_unit_hostnames(units):
return host_names
def get_pkg_version(application, pkg):
def get_pkg_version(application, pkg, model_name=None):
"""Return package version.
:param application: Application name
:type application: string
:param pkg: Package name
:type pkg: string
:param model_name: Name of model to query.
:type model_name: str
:returns: List of package version
:rtype: list
"""
versions = []
units = model.get_units(application)
units = model.get_units(application, model_name=model_name)
for unit in units:
cmd = 'dpkg -l | grep {}'.format(pkg)
out = juju_utils.remote_run(unit.entity_id, cmd)
out = juju_utils.remote_run(unit.entity_id, cmd, model_name=model_name)
versions.append(out.split('\n')[0].split()[2])
if len(set(versions)) != 1:
raise Exception('Unexpected output from pkg version check')

View File

@@ -25,13 +25,15 @@ from zaza import (
from zaza.openstack.utilities import generic as generic_utils
def get_application_status(application=None, unit=None):
def get_application_status(application=None, unit=None, model_name=None):
"""Return the juju status for an application.
:param application: Application name
:type application: string
:param unit: Specific unit
:type unit: string
:param model_name: Name of model to query.
:type model_name: str
:returns: Juju status output for an application
:rtype: dict
"""
@@ -66,95 +68,112 @@ def get_cloud_configs(cloud=None):
return generic_utils.get_yaml_config(cloud_config)
def get_full_juju_status():
def get_full_juju_status(model_name=None):
"""Return the full juju status output.
:param model_name: Name of model to query.
:type model_name: str
:returns: Full juju status output
:rtype: dict
"""
status = model.get_status()
status = model.get_status(model_name=model_name)
return status
def get_machines_for_application(application):
def get_machines_for_application(application, model_name=None):
"""Return machines for a given application.
:param application: Application name
:type application: string
:param model_name: Name of model to query.
:type model_name: str
:returns: machines for an application
:rtype: Iterator[str]
"""
status = get_application_status(application)
status = get_application_status(application, model_name=model_name)
if not status:
raise StopIteration
# libjuju juju status no longer has units for subordinate charms
# Use the application it is subordinate-to to find machines
if status.get("units") is None and status.get("subordinate-to"):
status = get_application_status(status.get("subordinate-to")[0])
status = get_application_status(status.get("subordinate-to")[0],
model_name=model_name)
for unit in status.get("units").keys():
yield status.get("units").get(unit).get("machine")
def get_unit_name_from_host_name(host_name, application):
def get_unit_name_from_host_name(host_name, application, model_name=None):
"""Return the juju unit name corresponding to a hostname.
:param host_name: Host name to map to unit name.
:type host_name: string
:param application: Application name
:type application: string
:param model_name: Name of model to query.
:type model_name: str
"""
# Assume that a juju managed hostname always ends in the machine number.
machine_number = host_name.split('-')[-1]
unit_names = [
u.entity_id
for u in model.get_units(application_name=application)
for u in model.get_units(application_name=application,
model_name=model_name)
if int(u.data['machine-id']) == int(machine_number)]
return unit_names[0]
def get_machine_status(machine, key=None):
def get_machine_status(machine, key=None, model_name=None):
"""Return the juju status for a machine.
:param machine: Machine number
:type machine: string
:param key: Key option requested
:type key: string
:param model_name: Name of model to query.
:type model_name: str
:returns: Juju status output for a machine
:rtype: dict
"""
status = get_full_juju_status()
status = get_full_juju_status(model_name=model_name)
status = status.machines.get(machine)
if key:
status = status.get(key)
return status
def get_machine_series(machine):
def get_machine_series(machine, model_name=None):
"""Return the juju series for a machine.
:param machine: Machine number
:type machine: string
:param model_name: Name of model to query.
:type model_name: str
:returns: Juju series
:rtype: string
"""
return get_machine_status(
machine=machine,
key='series'
key='series',
model_name=model_name
)
def get_machine_uuids_for_application(application):
def get_machine_uuids_for_application(application, model_name=None):
"""Return machine uuids for a given application.
:param application: Application name
:type application: string
:param model_name: Name of model to query.
:type model_name: str
:returns: machine uuuids for an application
:rtype: Iterator[str]
"""
for machine in get_machines_for_application(application):
yield get_machine_status(machine, key="instance-id")
for machine in get_machines_for_application(application,
model_name=model_name):
yield get_machine_status(machine, key="instance-id",
model_name=model_name)
def get_provider_type():
@@ -175,7 +194,7 @@ def get_provider_type():
return "openstack"
def remote_run(unit, remote_cmd, timeout=None, fatal=None):
def remote_run(unit, remote_cmd, timeout=None, fatal=None, model_name=None):
"""Run command on unit and return the output.
NOTE: This function is pre-deprecated. As soon as libjuju unit.run is able
@@ -187,13 +206,19 @@ def remote_run(unit, remote_cmd, timeout=None, fatal=None):
:type arg: int
:param fatal: Command failure condidered fatal or not
:type fatal: boolean
:param model_name: Name of model to query.
:type model_name: str
:returns: Juju run output
:rtype: string
:raises: model.CommandRunFailed
"""
if fatal is None:
fatal = True
result = model.run_on_unit(unit, remote_cmd, timeout=timeout)
result = model.run_on_unit(
unit,
remote_cmd,
timeout=timeout,
model_name=model_name)
if result:
if int(result.get("Code")) == 0:
return result.get("Stdout")
@@ -203,7 +228,7 @@ def remote_run(unit, remote_cmd, timeout=None, fatal=None):
return result.get("Stderr")
def _get_unit_names(names):
def _get_unit_names(names, model_name=None):
"""Resolve given application names to first unit name of said application.
Helper function that resolves application names to first unit name of
@@ -211,6 +236,8 @@ def _get_unit_names(names):
:param names: List of units/applications to translate
:type names: list(str)
:param model_name: Name of model to query.
:type model_name: str
:returns: List of units
:rtype: list(str)
"""
@@ -219,11 +246,14 @@ def _get_unit_names(names):
if '/' in name:
result.append(name)
else:
result.append(model.get_first_unit_name(name))
result.append(model.get_first_unit_name(
name,
model_name=model_name))
return result
def get_relation_from_unit(entity, remote_entity, remote_interface_name):
def get_relation_from_unit(entity, remote_entity, remote_interface_name,
model_name=None):
"""Get relation data passed between two units.
Get relation data for relation with `remote_interface_name` between
@@ -240,6 +270,8 @@ def get_relation_from_unit(entity, remote_entity, remote_interface_name):
:param remote_interface_name: Name of interface to query on remote end of
relation
:type remote_interface_name: str
:param model_name: Name of model to query.
:type model_name: str
:returns: dict with relation data
:rtype: dict
:raises: model.CommandRunFailed
@@ -247,27 +279,34 @@ def get_relation_from_unit(entity, remote_entity, remote_interface_name):
application = entity.split('/')[0]
remote_application = remote_entity.split('/')[0]
rid = model.get_relation_id(application, remote_application,
remote_interface_name=remote_interface_name)
(unit, remote_unit) = _get_unit_names([entity, remote_entity])
remote_interface_name=remote_interface_name,
model_name=model_name)
(unit, remote_unit) = _get_unit_names(
[entity, remote_entity],
model_name=model_name)
cmd = 'relation-get --format=yaml -r "{}" - "{}"' .format(rid, remote_unit)
result = model.run_on_unit(unit, cmd)
result = model.run_on_unit(unit, cmd, model_name=model_name)
if result and int(result.get('Code')) == 0:
return yaml.safe_load(result.get('Stdout'))
else:
raise model.CommandRunFailed(cmd, result)
def leader_get(application, key=''):
def leader_get(application, key='', model_name=None):
"""Get leader settings from leader unit of named application.
:param application: Application to get leader settings from.
:type application: str
:param key: Key option requested
:type key: string
:param model_name: Name of model to query.
:type model_name: str
:returns: dict with leader settings
:rtype: dict
:raises: model.CommandRunFailed
"""
cmd = 'leader-get --format=yaml {}'.format(key)
result = model.run_on_leader(application, cmd)
result = model.run_on_leader(application, cmd, model_name=model_name)
if result and int(result.get('Code')) == 0:
return yaml.safe_load(result.get('Stdout'))
else:

View File

@@ -321,13 +321,16 @@ def get_aodh_session_client(session):
return aodh_client.Client(session=session)
def get_keystone_scope():
def get_keystone_scope(model_name=None):
"""Return Keystone scope based on OpenStack release of the overcloud.
:param model_name: Name of model to query.
:type model_name: str
:returns: String keystone scope
:rtype: string
"""
os_version = get_current_os_versions("keystone")["keystone"]
os_version = get_current_os_versions("keystone",
model_name=model_name)["keystone"]
# Keystone policy.json shipped the charm with liberty requires a domain
# scoped token. Bug #1649106
if os_version == "liberty":
@@ -362,17 +365,20 @@ def get_keystone_session(openrc_creds, scope='PROJECT', verify=None):
return session.Session(auth=auth, verify=verify)
def get_overcloud_keystone_session(verify=None):
def get_overcloud_keystone_session(verify=None, model_name=None):
"""Return Over cloud keystone session.
:param verify: Control TLS certificate verification behaviour
:type verify: any
:param model_name: Name of model to query.
:type model_name: str
:returns keystone_session: keystoneauth1.session.Session object
:rtype: keystoneauth1.session.Session
"""
return get_keystone_session(get_overcloud_auth(),
scope=get_keystone_scope(),
verify=verify)
return get_keystone_session(
get_overcloud_auth(model_name=model_name),
scope=get_keystone_scope(model_name=model_name),
verify=verify)
def get_undercloud_keystone_session(verify=None):
@@ -572,7 +578,6 @@ def add_interface_to_netplan(server_name, mac_address):
unit_name = juju_utils.get_unit_name_from_host_name(
server_name, application_name)
run_cmd_nic = "ip -f link -br -o addr|grep {}".format(mac_address)
interface = model.run_on_unit(unit_name, run_cmd_nic)
interface = interface['Stdout'].split(' ')[0]
@@ -1394,11 +1399,13 @@ def get_os_code_info(package, pkg_version):
return OPENSTACK_CODENAMES[vers]
def get_current_os_versions(deployed_applications):
def get_current_os_versions(deployed_applications, model_name=None):
"""Determine OpenStack codename of deployed applications.
:param deployed_applications: List of deployed applications
:type deployed_applications: list
:param model_name: Name of model to query.
:type model_name: str
:returns: List of aplication to codenames dictionaries
:rtype: list
"""
@@ -1408,7 +1415,8 @@ def get_current_os_versions(deployed_applications):
continue
version = generic_utils.get_pkg_version(application['name'],
application['type']['pkg'])
application['type']['pkg'],
model_name=model_name)
versions[application['name']] = (
get_os_code_info(application['type']['pkg'], version))
return versions
@@ -1473,17 +1481,21 @@ def get_os_release(release_pair=None):
return index
def get_application_config_option(application, option):
def get_application_config_option(application, option, model_name=None):
"""Return application configuration.
:param application: Name of application
:type application: string
:param option: Specific configuration option
:type option: string
:param model_name: Name of model to query.
:type model_name: str
:returns: Value of configuration option
:rtype: Configuration option value type
"""
application_config = model.get_application_config(application)
application_config = model.get_application_config(
application,
model_name=model_name)
try:
return application_config.get(option).get('value')
except AttributeError:
@@ -1557,27 +1569,39 @@ def get_undercloud_auth():
# Openstack Client helpers
def get_keystone_ip():
def get_keystone_ip(model_name=None):
"""Return the IP address to use when communicating with keystone api.
:param model_name: Name of model to query.
:type model_name: str
:returns: IP address
:rtype: str
"""
if get_application_config_option('keystone', 'vip'):
return get_application_config_option('keystone', 'vip')
unit = model.get_units('keystone')[0]
vip_option = get_application_config_option(
'keystone',
'vip',
model_name=model_name)
if vip_option:
return vip_option
unit = model.get_units('keystone', model_name=model_name)[0]
return unit.public_address
def get_keystone_api_version():
def get_keystone_api_version(model_name=None):
"""Return the keystone api version.
:param model_name: Name of model to query.
:type model_name: str
:returns: Keystone's api version
:rtype: int
"""
os_version = get_current_os_versions('keystone')['keystone']
api_version = get_application_config_option('keystone',
'preferred-api-version')
os_version = get_current_os_versions(
'keystone',
model_name=model_name)['keystone']
api_version = get_application_config_option(
'keystone',
'preferred-api-version',
model_name=model_name)
if os_version >= 'queens':
api_version = 3
elif api_version is None:
@@ -1586,15 +1610,21 @@ def get_keystone_api_version():
return int(api_version)
def get_overcloud_auth(address=None):
def get_overcloud_auth(address=None, model_name=None):
"""Get overcloud OpenStack authentication from the environment.
:param model_name: Name of model to query.
:type model_name: str
:returns: Dictionary of authentication settings
:rtype: dict
"""
tls_rid = model.get_relation_id('keystone', 'vault',
model_name=model_name,
remote_interface_name='certificates')
ssl_config = get_application_config_option('keystone', 'ssl_cert')
ssl_config = get_application_config_option(
'keystone',
'ssl_cert',
model_name=model_name)
if tls_rid or ssl_config:
transport = 'https'
port = 35357
@@ -1603,11 +1633,14 @@ def get_overcloud_auth(address=None):
port = 5000
if not address:
address = get_keystone_ip()
address = get_keystone_ip(model_name=model_name)
password = juju_utils.leader_get('keystone', 'admin_passwd')
password = juju_utils.leader_get(
'keystone',
'admin_passwd',
model_name=model_name)
if get_keystone_api_version() == 2:
if get_keystone_api_version(model_name=model_name) == 2:
# V2 Explicitly, or None when charm does not possess the config key
logging.info('Using keystone API V2 for overcloud auth')
auth_settings = {
@@ -1633,7 +1666,7 @@ def get_overcloud_auth(address=None):
'API_VERSION': 3,
}
if tls_rid:
unit = model.get_first_unit_name('keystone')
unit = model.get_first_unit_name('keystone', model_name=model_name)
model.scp_from_unit(
unit,
KEYSTONE_REMOTE_CACERT,