Docstrings and renames
Removed unused functions Docstrings for all functions Renamed test_utils to _local_utils to indicate use only by zaza
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# The purpose of this file is for general use utilities internally and directly
|
||||
# consumed by zaza. No guarantees are made for consuming these utilities
|
||||
# outside of zaza. These utilities may be deprecated, removed or transformed up
|
||||
# to and including parameters and return values changing without warning.
|
||||
|
||||
# You have been warned.
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import six
|
||||
@@ -10,12 +18,18 @@ from zaza import model
|
||||
from zaza.charm_lifecycle import utils as lifecycle_utils
|
||||
|
||||
|
||||
# XXX Tech Debt Begins Here
|
||||
|
||||
def get_network_env_vars():
|
||||
"""Get environment variables with names which are consistent with
|
||||
network.yaml keys; Also get network environment variables as commonly
|
||||
used by openstack-charm-testing and ubuntu-openstack-ci automation.
|
||||
Return a dictionary compatible with openstack-mojo-specs network.yaml
|
||||
key structure."""
|
||||
key structure.
|
||||
|
||||
:returns: Network environment variables
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
# Example o-c-t & uosci environment variables:
|
||||
# NET_ID="a705dd0f-5571-4818-8c30-4132cc494668"
|
||||
@@ -71,10 +85,26 @@ def get_network_env_vars():
|
||||
|
||||
|
||||
def dict_to_yaml(dict_data):
|
||||
"""Return YAML from dictionary
|
||||
|
||||
:param dict_data: Dictionary data
|
||||
:type dict_data: dict
|
||||
:returns: YAML dump
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
return yaml.dump(dict_data, default_flow_style=False)
|
||||
|
||||
|
||||
def get_yaml_config(config_file):
|
||||
"""Return configuration from YAML file
|
||||
|
||||
:param config_file: Configuration file name
|
||||
:type config_file: string
|
||||
:returns: Dictionary of configuration
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
# Note in its original form get_mojo_config it would do a search pattern
|
||||
# through mojo stage directories. This version assumes the yaml file is in
|
||||
# the pwd.
|
||||
@@ -84,7 +114,16 @@ def get_yaml_config(config_file):
|
||||
|
||||
def get_net_info(net_topology, ignore_env_vars=False):
|
||||
"""Get network info from network.yaml, override the values if specific
|
||||
environment variables are set."""
|
||||
environment variables are set.
|
||||
|
||||
:param net_topology: Network topology name from network.yaml
|
||||
:type net_topology: string
|
||||
:param ignore_env_vars: Ignore enviroment variables or not
|
||||
:type ignore_env_vars: boolean
|
||||
:returns: Dictionary of network configuration
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
net_info = get_yaml_config('network.yaml')[net_topology]
|
||||
|
||||
if not ignore_env_vars:
|
||||
@@ -96,6 +135,18 @@ def get_net_info(net_topology, ignore_env_vars=False):
|
||||
|
||||
|
||||
def parse_arg(options, arg, multiargs=False):
|
||||
"""Parse argparse argments
|
||||
|
||||
:param options: Argparse options
|
||||
:type options: argparse object
|
||||
:param arg: Argument attribute key
|
||||
:type arg: string
|
||||
:param multiargs: More than one arugment or not
|
||||
:type multiargs: boolean
|
||||
:returns: Argparse atrribute value
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
if arg.upper() in os.environ:
|
||||
if multiargs:
|
||||
return os.environ[arg.upper()].split()
|
||||
@@ -106,7 +157,22 @@ def parse_arg(options, arg, multiargs=False):
|
||||
|
||||
|
||||
def remote_run(unit, remote_cmd=None, timeout=None, fatal=None):
|
||||
logging.warn("Deprecate as soons as possible. Use model.run_on_unit() as "
|
||||
"""Run command on unit and return the output
|
||||
|
||||
NOTE: This function is pre-deprecated. As soon as libjuju unit.run is able
|
||||
to return output this functionality should move to model.run_on_unit.
|
||||
|
||||
:param remote_cmd: Command to execute on unit
|
||||
:type remote_cmd: string
|
||||
:param timeout: Timeout value for the command
|
||||
:type arg: string
|
||||
:param fatal: Command failure condidered fatal or not
|
||||
:type fatal: boolean
|
||||
:returns: Juju run output
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
logging.warn("Deprecate as soon as possible. Use model.run_on_unit() as "
|
||||
"soon as libjuju unit.run returns output.")
|
||||
if fatal is None:
|
||||
fatal = True
|
||||
@@ -127,6 +193,16 @@ def remote_run(unit, remote_cmd=None, timeout=None, fatal=None):
|
||||
|
||||
|
||||
def get_pkg_version(application, pkg):
|
||||
"""Return package version
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:param pkg: Package name
|
||||
:type pkg: string
|
||||
:returns: List of package version
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
versions = []
|
||||
units = model.get_units(
|
||||
lifecycle_utils.get_juju_model(), application)
|
||||
@@ -140,10 +216,12 @@ def get_pkg_version(application, pkg):
|
||||
|
||||
|
||||
def get_cloud_from_controller():
|
||||
""" Get the cloud name from the Juju 2.x controller
|
||||
"""Get the cloud name from the Juju controller
|
||||
|
||||
@returns String name of the cloud for the current Juju 2.x controller
|
||||
:returns: Name of the cloud for the current controller
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
cmd = ['juju', 'show-controller', '--format=yaml']
|
||||
output = subprocess.check_output(cmd)
|
||||
if six.PY3:
|
||||
@@ -159,10 +237,12 @@ def get_cloud_from_controller():
|
||||
|
||||
|
||||
def get_provider_type():
|
||||
""" Get the type of the undercloud
|
||||
"""Get the type of the undercloud
|
||||
|
||||
@returns String name of the undercloud type
|
||||
:returns: Name of the undercloud type
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
juju_env = subprocess.check_output(['juju', 'switch'])
|
||||
if six.PY3:
|
||||
juju_env = juju_env.decode('utf-8')
|
||||
@@ -185,11 +265,27 @@ def get_provider_type():
|
||||
|
||||
|
||||
def get_full_juju_status():
|
||||
"""Return the full juju status output
|
||||
|
||||
:returns: Full juju status output
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
status = model.get_status(lifecycle_utils.get_juju_model())
|
||||
return status
|
||||
|
||||
|
||||
def get_application_status(application=None, unit=None):
|
||||
"""Return the juju status for an application
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:param unit: Specific unit
|
||||
:type unit: string
|
||||
:returns: Juju status output for an application
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
status = get_full_juju_status()
|
||||
if application:
|
||||
status = status.applications.get(application)
|
||||
@@ -199,6 +295,16 @@ def get_application_status(application=None, unit=None):
|
||||
|
||||
|
||||
def get_machine_status(machine, key=None):
|
||||
"""Return the juju status for a machine
|
||||
|
||||
:param machine: Machine number
|
||||
:type machine: string
|
||||
:param key: Key option requested
|
||||
:type key: string
|
||||
:returns: Juju status output for a machine
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
status = get_full_juju_status()
|
||||
status = status.machines.get(machine)
|
||||
if key:
|
||||
@@ -207,6 +313,14 @@ def get_machine_status(machine, key=None):
|
||||
|
||||
|
||||
def get_machines_for_application(application):
|
||||
"""Return machines for a given application
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:returns: List of machines for an application
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
status = get_application_status(application)
|
||||
machines = []
|
||||
for unit in status.get('units').keys():
|
||||
@@ -216,6 +330,14 @@ def get_machines_for_application(application):
|
||||
|
||||
|
||||
def get_machine_uuids_for_application(application):
|
||||
"""Return machine uuids for a given application
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:returns: List of machine uuuids for an application
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
uuids = []
|
||||
for machine in get_machines_for_application(application):
|
||||
uuids.append(get_machine_status(machine, key='instance-id'))
|
||||
@@ -223,6 +345,12 @@ def get_machine_uuids_for_application(application):
|
||||
|
||||
|
||||
def setup_logging():
|
||||
"""Setup zaza logging
|
||||
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
logFormatter = logging.Formatter(
|
||||
fmt="%(asctime)s [%(levelname)s] %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S")
|
||||
+469
-114
@@ -6,7 +6,6 @@ from .os_versions import (
|
||||
PACKAGE_CODENAMES,
|
||||
)
|
||||
|
||||
from keystoneclient.v2_0 import client as keystoneclient_v2
|
||||
from keystoneclient.v3 import client as keystoneclient_v3
|
||||
from keystoneauth1 import session
|
||||
from keystoneauth1.identity import (
|
||||
@@ -28,7 +27,7 @@ from zaza import model
|
||||
from zaza.charm_lifecycle import utils as lifecycle_utils
|
||||
from zaza.utilities import (
|
||||
exceptions,
|
||||
test_utils,
|
||||
_local_utils,
|
||||
)
|
||||
|
||||
CHARM_TYPES = {
|
||||
@@ -76,14 +75,17 @@ UPGRADE_SERVICES = [
|
||||
|
||||
|
||||
# Openstack Client helpers
|
||||
def get_nova_creds(cloud_creds):
|
||||
auth = get_ks_creds(cloud_creds)
|
||||
if cloud_creds.get('OS_PROJECT_ID'):
|
||||
auth['project_id'] = cloud_creds.get('OS_PROJECT_ID')
|
||||
return auth
|
||||
|
||||
|
||||
def get_ks_creds(cloud_creds, scope='PROJECT'):
|
||||
"""Return the credentials for authenticating against keystone
|
||||
|
||||
:param cloud_creds: Openstack RC environment credentials
|
||||
:type cloud_creds: dict
|
||||
:param scope: Authentication scope: PROJECT or DOMAIN
|
||||
:type scope: string
|
||||
:returns: Credentials dictionary
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
if cloud_creds.get('API_VERSION', 2) == 2:
|
||||
auth = {
|
||||
'username': cloud_creds['OS_USERNAME'],
|
||||
@@ -113,30 +115,45 @@ def get_ks_creds(cloud_creds, scope='PROJECT'):
|
||||
return auth
|
||||
|
||||
|
||||
def get_nova_client(novarc_creds, insecure=True):
|
||||
nova_creds = get_nova_creds(novarc_creds)
|
||||
nova_creds['insecure'] = insecure
|
||||
nova_creds['version'] = 2
|
||||
return novaclient_client.Client(**nova_creds)
|
||||
|
||||
|
||||
def get_nova_session_client(session):
|
||||
"""Return novaclient authenticated by keystone session
|
||||
|
||||
:param session: Keystone session object
|
||||
:type session: keystoneauth1.session.Session object
|
||||
:returns: Authenticated novaclient
|
||||
:rtype: novaclient.Client object
|
||||
"""
|
||||
|
||||
return novaclient_client.Client(2, session=session)
|
||||
|
||||
|
||||
def get_neutron_client(novarc_creds, insecure=True):
|
||||
neutron_creds = get_ks_creds(novarc_creds)
|
||||
neutron_creds['insecure'] = insecure
|
||||
return neutronclient.Client(**neutron_creds)
|
||||
|
||||
|
||||
def get_neutron_session_client(session):
|
||||
"""Return neutronclient authenticated by keystone session
|
||||
|
||||
:param session: Keystone session object
|
||||
:type session: keystoneauth1.session.Session object
|
||||
:returns: Authenticated neutronclient
|
||||
:rtype: neutronclient.Client object
|
||||
"""
|
||||
|
||||
return neutronclient.Client(session=session)
|
||||
|
||||
|
||||
def get_keystone_session(novarc_creds, insecure=True, scope='PROJECT'):
|
||||
keystone_creds = get_ks_creds(novarc_creds, scope=scope)
|
||||
if novarc_creds.get('API_VERSION', 2) == 2:
|
||||
def get_keystone_session(opentackrc_creds, insecure=True, scope='PROJECT'):
|
||||
"""Return keystone session
|
||||
|
||||
:param openstackrc_creds: Openstack RC credentials
|
||||
:type openstackrc_creds: dict
|
||||
:param insecure: Allow insecure HTTPS connections
|
||||
:type insecure: boolean
|
||||
:param scope: Authentication scope: PROJECT or DOMAIN
|
||||
:type scope: string
|
||||
:returns: Keystone session object
|
||||
:rtype: keystoneauth1.session.Session object
|
||||
"""
|
||||
|
||||
keystone_creds = get_ks_creds(opentackrc_creds, scope=scope)
|
||||
if opentackrc_creds.get('API_VERSION', 2) == 2:
|
||||
auth = v2.Password(**keystone_creds)
|
||||
else:
|
||||
auth = v3.Password(**keystone_creds)
|
||||
@@ -144,42 +161,85 @@ def get_keystone_session(novarc_creds, insecure=True, scope='PROJECT'):
|
||||
|
||||
|
||||
def get_keystone_session_client(session):
|
||||
"""Return keystoneclient authenticated by keystone session
|
||||
|
||||
:param session: Keystone session object
|
||||
:type session: keystoneauth1.session.Session object
|
||||
:returns: Authenticated keystoneclient
|
||||
:rtype: keystoneclient.v3.Client object
|
||||
"""
|
||||
|
||||
return keystoneclient_v3.Client(session=session)
|
||||
|
||||
|
||||
def get_keystone_client(novarc_creds, insecure=True):
|
||||
keystone_creds = get_ks_creds(novarc_creds)
|
||||
if novarc_creds.get('API_VERSION', 2) == 2:
|
||||
def get_keystone_client(opentackrc_creds, insecure=True):
|
||||
"""Return authenticated keystoneclient and set auth_ref for service_catalog
|
||||
|
||||
:param openstackrc_creds: Openstack RC credentials
|
||||
:type openstackrc_creds: dict
|
||||
:param insecure: Allow insecure HTTPS connections
|
||||
:type insecure: boolean
|
||||
:returns: Authenticated keystoneclient
|
||||
:rtype: keystoneclient.v3.Client object
|
||||
"""
|
||||
|
||||
session = get_keystone_session(opentackrc_creds, insecure)
|
||||
client = get_keystone_session_client(session)
|
||||
keystone_creds = get_ks_creds(opentackrc_creds)
|
||||
if opentackrc_creds.get('API_VERSION', 2) == 2:
|
||||
auth = v2.Password(**keystone_creds)
|
||||
sess = session.Session(auth=auth, verify=True)
|
||||
client = keystoneclient_v2.Client(session=sess)
|
||||
else:
|
||||
auth = v3.Password(**keystone_creds)
|
||||
sess = get_keystone_session(novarc_creds, insecure)
|
||||
client = keystoneclient_v3.Client(session=sess)
|
||||
# This populates the client.service_catalog
|
||||
client.auth_ref = auth.get_access(sess)
|
||||
client.auth_ref = auth.get_access(session)
|
||||
return client
|
||||
|
||||
|
||||
def get_project_id(ks_client, project_name, api_version=2, domain_name=None):
|
||||
"""Return project ID
|
||||
|
||||
:param ks_client: Authenticated keystoneclient
|
||||
:type ks_client: keystoneclient.v3.Client object
|
||||
:param project_name: Name of the project
|
||||
:type project_name: string
|
||||
:param api_version: API version number
|
||||
:type api_version: int
|
||||
:param domain_name: Name of the domain
|
||||
:type domain_name: string or None
|
||||
:returns: Project ID
|
||||
:rtype: string or None
|
||||
"""
|
||||
|
||||
domain_id = None
|
||||
if domain_name:
|
||||
domain_id = ks_client.domains.list(name=domain_name)[0].id
|
||||
all_projects = ks_client.projects.list(domain=domain_id)
|
||||
for t in all_projects:
|
||||
if t._info['name'] == project_name:
|
||||
return t._info['id']
|
||||
for p in all_projects:
|
||||
if p._info['name'] == project_name:
|
||||
return p._info['id']
|
||||
return None
|
||||
|
||||
|
||||
# Neutron Helpers
|
||||
def get_gateway_uuids():
|
||||
return test_utils.get_machine_uuids_for_application('neutron-gateway')
|
||||
"""Return machine uuids for neutron-gateway(s)
|
||||
|
||||
:returns: List of uuids
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
return _local_utils.get_machine_uuids_for_application('neutron-gateway')
|
||||
|
||||
|
||||
def get_ovs_uuids():
|
||||
return test_utils.get_machine_uuids_for_application('neutron-openvswitch')
|
||||
"""Return machine uuids for neutron-openvswitch(s)
|
||||
|
||||
:returns: List of uuids
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
return (_local_utils
|
||||
.get_machine_uuids_for_application('neutron-openvswitch'))
|
||||
|
||||
|
||||
BRIDGE_MAPPINGS = 'bridge-mappings'
|
||||
@@ -187,14 +247,21 @@ NEW_STYLE_NETWORKING = 'physnet1:br-ex'
|
||||
|
||||
|
||||
def deprecated_external_networking(dvr_mode=False):
|
||||
'''Determine whether deprecated external network mode is in use'''
|
||||
"""Determine whether deprecated external network mode is in use
|
||||
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:returns: True or False
|
||||
:rtype: boolean
|
||||
"""
|
||||
|
||||
bridge_mappings = None
|
||||
if dvr_mode:
|
||||
bridge_mappings = juju_get('neutron-openvswitch',
|
||||
BRIDGE_MAPPINGS)
|
||||
bridge_mappings = get_application_config_option('neutron-openvswitch',
|
||||
BRIDGE_MAPPINGS)
|
||||
else:
|
||||
bridge_mappings = juju_get('neutron-gateway',
|
||||
BRIDGE_MAPPINGS)
|
||||
bridge_mappings = get_application_config_option('neutron-gateway',
|
||||
BRIDGE_MAPPINGS)
|
||||
|
||||
if bridge_mappings == NEW_STYLE_NETWORKING:
|
||||
return False
|
||||
@@ -202,11 +269,29 @@ def deprecated_external_networking(dvr_mode=False):
|
||||
|
||||
|
||||
def get_net_uuid(neutron_client, net_name):
|
||||
"""Determine whether deprecated external network mode is in use
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param net_name: Network name
|
||||
:type net_name: string
|
||||
:returns: Network ID
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
network = neutron_client.list_networks(name=net_name)['networks'][0]
|
||||
return network['id']
|
||||
|
||||
|
||||
def get_admin_net(neutron_client):
|
||||
"""Return admin netowrk
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:returns: Admin network object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
for net in neutron_client.list_networks()['networks']:
|
||||
if net['name'].endswith('_admin_net'):
|
||||
return net
|
||||
@@ -214,6 +299,20 @@ def get_admin_net(neutron_client):
|
||||
|
||||
def configure_gateway_ext_port(novaclient, neutronclient,
|
||||
dvr_mode=None, net_id=None):
|
||||
"""Configure the neturong-gateway external port
|
||||
|
||||
:param novaclient: Authenticated novaclient
|
||||
:type novaclient: novaclient.Client object
|
||||
:param neutronclient: Authenticated neutronclient
|
||||
:type neutronclient: neutronclient.Client object
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:param net_id: Network ID
|
||||
:type net_id: string
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
if dvr_mode:
|
||||
uuids = get_ovs_uuids()
|
||||
else:
|
||||
@@ -270,7 +369,8 @@ def configure_gateway_ext_port(novaclient, neutronclient,
|
||||
if ext_br_macs:
|
||||
logging.info('Setting {} on {} external port to {}'.format(
|
||||
config_key, application_name, ext_br_macs_str))
|
||||
current_data_port = juju_get(application_name, config_key)
|
||||
current_data_port = get_application_config_option(application_name,
|
||||
config_key)
|
||||
if current_data_port == ext_br_macs_str:
|
||||
logging.info('Config already set to value')
|
||||
return
|
||||
@@ -282,6 +382,24 @@ def configure_gateway_ext_port(novaclient, neutronclient,
|
||||
|
||||
def create_project_network(neutron_client, project_id, net_name='private',
|
||||
shared=False, network_type='gre', domain=None):
|
||||
"""Create the project network
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param net_name: Network name
|
||||
:type net_name: string
|
||||
:param shared: The network should be shared between projects
|
||||
:type shared: boolean
|
||||
:param net_type: Network type: GRE, VXLAN, local, VLAN
|
||||
:type net_type: string
|
||||
:param domain_name: Name of the domain
|
||||
:type domain_name: string or None
|
||||
:returns: Network object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
networks = neutron_client.list_networks(name=net_name)
|
||||
if len(networks['networks']) == 0:
|
||||
logging.info('Creating network: %s',
|
||||
@@ -305,6 +423,20 @@ def create_project_network(neutron_client, project_id, net_name='private',
|
||||
|
||||
def create_external_network(neutron_client, project_id, dvr_mode,
|
||||
net_name='ext_net'):
|
||||
"""Create the external network
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:param net_name: Network name
|
||||
:type net_name: string
|
||||
:returns: Network object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
networks = neutron_client.list_networks(name=net_name)
|
||||
if len(networks['networks']) == 0:
|
||||
logging.info('Configuring external network')
|
||||
@@ -331,6 +463,32 @@ def create_external_network(neutron_client, project_id, dvr_mode,
|
||||
def create_project_subnet(neutron_client, project_id, network, cidr, dhcp=True,
|
||||
subnet_name='private_subnet', domain=None,
|
||||
subnetpool=None, ip_version=4, prefix_len=24):
|
||||
"""Create the project subnet
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param network: Network object
|
||||
:type network: dict
|
||||
:param cidr: Network CIDR
|
||||
:type cidr: string
|
||||
:param dhcp: Run DHCP on this subnet
|
||||
:type dhcp: boolean
|
||||
:param subnet_name: Subnet name
|
||||
:type subnet_name: string
|
||||
:param domain_name: Name of the domain
|
||||
:type domain_name: string or None
|
||||
:param subnet_pool: Subnetpool object
|
||||
:type subnet_pool: dict or None
|
||||
:param ip_version: IP version: 4 or 6
|
||||
:type ip_version: int
|
||||
:param prefix_len: Prefix lenghths of subnets derived from subnet pools
|
||||
:type prefix_len: int
|
||||
:returns: Subnet object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
# Create subnet
|
||||
subnets = neutron_client.list_subnets(name=subnet_name)
|
||||
if len(subnets['subnets']) == 0:
|
||||
@@ -356,10 +514,32 @@ def create_project_subnet(neutron_client, project_id, network, cidr, dhcp=True,
|
||||
return subnet
|
||||
|
||||
|
||||
def create_external_subnet(neutron_client, tenant_id, network,
|
||||
def create_external_subnet(neutron_client, project_id, network,
|
||||
default_gateway=None, cidr=None,
|
||||
start_floating_ip=None, end_floating_ip=None,
|
||||
subnet_name='ext_net_subnet'):
|
||||
"""Create the external subnet
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param network: Network object
|
||||
:type network: dict
|
||||
:param default_gateway: Deafault gateway IP address
|
||||
:type default_gateway: string
|
||||
:param cidr: Network CIDR
|
||||
:type cidr: string
|
||||
:param start_floating_ip: Start of floating IP range: IP address
|
||||
:type start_floating_ip: string or None
|
||||
:param end_floating_ip: End of floating IP range: IP address
|
||||
:type end_floating_ip: string or None
|
||||
:param subnet_name: Subnet name
|
||||
:type subnet_name: string
|
||||
:returns: Subnet object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
subnets = neutron_client.list_subnets(name=subnet_name)
|
||||
if len(subnets['subnets']) == 0:
|
||||
subnet_msg = {
|
||||
@@ -367,7 +547,7 @@ def create_external_subnet(neutron_client, tenant_id, network,
|
||||
'network_id': network['id'],
|
||||
'enable_dhcp': False,
|
||||
'ip_version': 4,
|
||||
'tenant_id': tenant_id
|
||||
'tenant_id': project_id
|
||||
}
|
||||
|
||||
if default_gateway:
|
||||
@@ -391,6 +571,18 @@ def create_external_subnet(neutron_client, tenant_id, network,
|
||||
|
||||
|
||||
def update_subnet_dns(neutron_client, subnet, dns_servers):
|
||||
"""Update subnet DNS servers
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param subnet: Subnet object
|
||||
:type subnet: dict
|
||||
:param dns_servers: Comma separted list of IP addresses
|
||||
:type project_id: string
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
msg = {
|
||||
'subnet': {
|
||||
'dns_nameservers': dns_servers.split(',')
|
||||
@@ -401,14 +593,24 @@ def update_subnet_dns(neutron_client, subnet, dns_servers):
|
||||
neutron_client.update_subnet(subnet['id'], msg)
|
||||
|
||||
|
||||
def create_provider_router(neutron_client, tenant_id):
|
||||
def create_provider_router(neutron_client, project_id):
|
||||
"""Create the provider router
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:returns: Router object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
routers = neutron_client.list_routers(name='provider-router')
|
||||
if len(routers['routers']) == 0:
|
||||
logging.info('Creating provider router for external network access')
|
||||
router_info = {
|
||||
'router': {
|
||||
'name': 'provider-router',
|
||||
'tenant_id': tenant_id
|
||||
'tenant_id': project_id
|
||||
}
|
||||
}
|
||||
router = neutron_client.create_router(router_info)['router']
|
||||
@@ -420,6 +622,18 @@ def create_provider_router(neutron_client, tenant_id):
|
||||
|
||||
|
||||
def plug_extnet_into_router(neutron_client, router, network):
|
||||
"""Add external interface to virtual router
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param router: Router object
|
||||
:type router: dict
|
||||
:param network: Network object
|
||||
:type network: dict
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
ports = neutron_client.list_ports(device_owner='network:router_gateway',
|
||||
network_id=network['id'])
|
||||
if len(ports['ports']) == 0:
|
||||
@@ -433,6 +647,20 @@ def plug_extnet_into_router(neutron_client, router, network):
|
||||
|
||||
|
||||
def plug_subnet_into_router(neutron_client, router, network, subnet):
|
||||
"""Add subnet interface to virtual router
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param router: Router object
|
||||
:type router: dict
|
||||
:param network: Network object
|
||||
:type network: dict
|
||||
:param subnet: Subnet object
|
||||
:type subnet: dict
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
routers = neutron_client.list_routers(name=router)
|
||||
if len(routers['routers']) == 0:
|
||||
logging.error('Unable to locate provider router %s', router)
|
||||
@@ -454,9 +682,18 @@ def plug_subnet_into_router(neutron_client, router, network, subnet):
|
||||
def create_address_scope(neutron_client, project_id, name, ip_version=4):
|
||||
"""Create address scope
|
||||
|
||||
:param ip_version: integer 4 or 6
|
||||
:param name: strint name for the address scope
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param name: Address scope name
|
||||
:type name: string
|
||||
:param ip_version: IP version: 4 or 6
|
||||
:type ip_version: int
|
||||
:returns: Address scope object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
address_scopes = neutron_client.list_address_scopes(name=name)
|
||||
if len(address_scopes['address_scopes']) == 0:
|
||||
logging.info('Creating {} address scope'.format(name))
|
||||
@@ -478,7 +715,25 @@ def create_address_scope(neutron_client, project_id, name, ip_version=4):
|
||||
|
||||
|
||||
def create_subnetpool(neutron_client, project_id, name, subnetpool_prefix,
|
||||
address_scope, shared=True, domain=None):
|
||||
address_scope, shared=True):
|
||||
"""Create subnet pool
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param name: Subnet pool name
|
||||
:type name: string
|
||||
:param subnetpool_prefix: CIDR network
|
||||
:type subnetpool_prefix: string
|
||||
:param address_scope: Address scope object
|
||||
:type address_scope: dict
|
||||
:param shared: The subnet pool should be shared between projects
|
||||
:type shared: boolean
|
||||
:returns: Subnetpool object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
subnetpools = neutron_client.list_subnetpools(name=name)
|
||||
if len(subnetpools['subnetpools']) == 0:
|
||||
logging.info('Creating subnetpool: %s',
|
||||
@@ -502,12 +757,20 @@ def create_subnetpool(neutron_client, project_id, name, subnetpool_prefix,
|
||||
|
||||
def create_bgp_speaker(neutron_client, local_as=12345, ip_version=4,
|
||||
name='bgp-speaker'):
|
||||
"""Create BGP Speaker
|
||||
"""Create BGP speaker
|
||||
|
||||
@param neutron_client: Instance of neutronclient.v2.Client
|
||||
@param local_as: int Local Autonomous System Number
|
||||
@returns dict BGP Speaker object
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param local_as: Autonomous system number of the OpenStack cloud
|
||||
:type local_as: int
|
||||
:param remote_as: Autonomous system number of the BGP peer
|
||||
:type local_as: int
|
||||
:param name: BGP speaker name
|
||||
:type name: string
|
||||
:returns: BGP speaker object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
bgp_speakers = neutron_client.list_bgp_speakers(name=name)
|
||||
if len(bgp_speakers['bgp_speakers']) == 0:
|
||||
logging.info('Creating BGP Speaker')
|
||||
@@ -529,11 +792,16 @@ def create_bgp_speaker(neutron_client, local_as=12345, ip_version=4,
|
||||
def add_network_to_bgp_speaker(neutron_client, bgp_speaker, network_name):
|
||||
"""Advertise network on BGP Speaker
|
||||
|
||||
@param neutron_client: Instance of neutronclient.v2.Client
|
||||
@param bgp_speaker: dict BGP Speaker object
|
||||
@param network_name: str Name of network to advertise
|
||||
@returns None
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param bpg_speaker: BGP speaker object
|
||||
:type bgp_speaker: dict
|
||||
:param network_name: Name of network to advertise
|
||||
:type network_name: string
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
network_id = get_net_uuid(neutron_client, network_name)
|
||||
# There is no direct way to determine which networks have already
|
||||
# been advertised. For example list_route_advertised_from_bgp_speaker shows
|
||||
@@ -550,16 +818,20 @@ def add_network_to_bgp_speaker(neutron_client, bgp_speaker, network_name):
|
||||
|
||||
def create_bgp_peer(neutron_client, peer_application_name='quagga',
|
||||
remote_as=10000, auth_type='none'):
|
||||
"""Create BGP Peer
|
||||
"""Create BGP peer
|
||||
|
||||
@param neutron_client: Instance of neutronclient.v2.Client
|
||||
@param peer_application_name: str Name of juju application to find peer IP
|
||||
Default: 'quagga'
|
||||
@param remote_as: int Remote Autonomous System Number
|
||||
@param auth_type: str BGP authentication type.
|
||||
Default: 'none'
|
||||
@returns dict BGP Peer object
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param peer_application_name: Application name of the BGP peer
|
||||
:type peer_application_name: string
|
||||
:param remote_as: Autonomous system number of the BGP peer
|
||||
:type local_as: int
|
||||
:param auth_type: BGP authentication type
|
||||
:type auth_type: string or None
|
||||
:returns: BGP peer object
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
peer_unit = model.get_units(
|
||||
lifecycle_utils.get_juju_model(), peer_application_name)[0]
|
||||
peer_ip = peer_unit.public_address
|
||||
@@ -582,13 +854,18 @@ def create_bgp_peer(neutron_client, peer_application_name='quagga',
|
||||
|
||||
|
||||
def add_peer_to_bgp_speaker(neutron_client, bgp_speaker, bgp_peer):
|
||||
"""Setup BGP peering relationship with BGP Peer and BGP Speaker
|
||||
"""Add BGP peer relationship to BGP speaker
|
||||
|
||||
@param neutron_client: Instance of neutronclient.v2.Client
|
||||
@param bgp_speaker: dict BGP Speaker object
|
||||
@param bgp_peer: dict BGP Peer object
|
||||
@returns None
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param bpg_speaker: BGP speaker object
|
||||
:type bgp_speaker: dict
|
||||
:param bpg_peer: BGP peer object
|
||||
:type bgp_peer: dict
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
# Handle the expected exception if the peer is already on the
|
||||
# speaker
|
||||
try:
|
||||
@@ -601,13 +878,83 @@ def add_peer_to_bgp_speaker(neutron_client, bgp_speaker, bgp_peer):
|
||||
.format(bgp_peer['name']))
|
||||
|
||||
|
||||
def add_neutron_secgroup_rules(neutron_client, project_id):
|
||||
"""Add neutron security group rules
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:returns: Nothing: This fucntion is executed for its sideffect
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
secgroup = None
|
||||
for group in neutron_client.list_security_groups().get('security_groups'):
|
||||
if (group.get('name') == 'default' and
|
||||
(group.get('project_id') == project_id or
|
||||
(group.get('tenant_id') == project_id))):
|
||||
secgroup = group
|
||||
if not secgroup:
|
||||
raise Exception("Failed to find default security group")
|
||||
# Using presence of a 22 rule to indicate whether secgroup rules
|
||||
# have been added
|
||||
port_rules = [rule['port_range_min'] for rule in
|
||||
secgroup.get('security_group_rules')]
|
||||
protocol_rules = [rule['protocol'] for rule in
|
||||
secgroup.get('security_group_rules')]
|
||||
if 22 in port_rules:
|
||||
logging.warn('Security group rules for ssh already added')
|
||||
else:
|
||||
logging.info('Adding ssh security group rule')
|
||||
neutron_client.create_security_group_rule(
|
||||
{'security_group_rule':
|
||||
{'security_group_id': secgroup.get('id'),
|
||||
'protocol': 'tcp',
|
||||
'port_range_min': 22,
|
||||
'port_range_max': 22,
|
||||
'direction': 'ingress',
|
||||
}
|
||||
})
|
||||
|
||||
if 'icmp' in protocol_rules:
|
||||
logging.warn('Security group rules for ping already added')
|
||||
else:
|
||||
logging.info('Adding ping security group rule')
|
||||
neutron_client.create_security_group_rule(
|
||||
{'security_group_rule':
|
||||
{'security_group_id': secgroup.get('id'),
|
||||
'protocol': 'icmp',
|
||||
'direction': 'ingress',
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
# Codename and package versions
|
||||
def get_swift_codename(version):
|
||||
'''Determine OpenStack codename that corresponds to swift version.'''
|
||||
"""Determine OpenStack codename that corresponds to swift version
|
||||
|
||||
:param version: Version of Swift
|
||||
:type version: string
|
||||
:returns: Codename for swift
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
codenames = [k for k, v in six.iteritems(SWIFT_CODENAMES) if version in v]
|
||||
return codenames[0]
|
||||
|
||||
|
||||
def get_os_code_info(package, pkg_version):
|
||||
"""Determine OpenStack codename that corresponds to package version
|
||||
|
||||
:param package: Package name
|
||||
:type package: string
|
||||
:param pkg_version: Package version
|
||||
:type pkg_version: string
|
||||
:returns: Codename for package
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
# {'code_num': entry, 'code_name': OPENSTACK_CODENAMES[entry]}
|
||||
# Remove epoch if it exists
|
||||
if ':' in pkg_version:
|
||||
@@ -636,46 +983,52 @@ def get_os_code_info(package, pkg_version):
|
||||
return OPENSTACK_CODENAMES[vers]
|
||||
|
||||
|
||||
def get_current_os_versions(deployed_services):
|
||||
def get_current_os_versions(deployed_applications):
|
||||
"""Determine OpenStack codename of deployed applications
|
||||
|
||||
:param deployed_applications: List of deployed applications
|
||||
:type deployed_applications: list
|
||||
:returns: List of aplication to codenames dictionaries
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
versions = {}
|
||||
for service in UPGRADE_SERVICES:
|
||||
if service['name'] not in deployed_services:
|
||||
for application in UPGRADE_SERVICES:
|
||||
if application['name'] not in deployed_applications:
|
||||
continue
|
||||
|
||||
version = test_utils.get_pkg_version(service['name'],
|
||||
service['type']['pkg'])
|
||||
versions[service['name']] = get_os_code_info(service['type']['pkg'],
|
||||
version)
|
||||
version = _local_utils.get_pkg_version(application['name'],
|
||||
application['type']['pkg'])
|
||||
versions[application['name']] = (
|
||||
get_os_code_info(application['type']['pkg'], version))
|
||||
return versions
|
||||
|
||||
|
||||
def get_lowest_os_version(current_versions):
|
||||
lowest_version = 'zebra'
|
||||
for svc in current_versions.keys():
|
||||
if current_versions[svc] < lowest_version:
|
||||
lowest_version = current_versions[svc]
|
||||
return lowest_version
|
||||
|
||||
|
||||
def juju_get_config_keys(application):
|
||||
logging.warn("Deprecated function: juju_get_config_keys. Use "
|
||||
"get_application_config_keys")
|
||||
return get_application_config_keys(application)
|
||||
|
||||
|
||||
def get_application_config_keys(application):
|
||||
"""Return application configuration keys
|
||||
|
||||
:param application: Name of application
|
||||
:type application: string
|
||||
:returns: List of aplication configuration keys
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
application_config = model.get_application_config(
|
||||
lifecycle_utils.get_juju_model(), application)
|
||||
return list(application_config.keys())
|
||||
|
||||
|
||||
def juju_get(application, option):
|
||||
logging.warn("Deprecated function: juju_get. Use "
|
||||
"get_application_config_option")
|
||||
return get_application_config_option(application, option)
|
||||
|
||||
|
||||
def get_application_config_option(application, option):
|
||||
"""Return application configuration
|
||||
|
||||
:param application: Name of application
|
||||
:type application: string
|
||||
:param option: Specific configuration option
|
||||
:type option: string
|
||||
:returns: Value of configuration option
|
||||
:rtype: Configuration option value type
|
||||
"""
|
||||
|
||||
application_config = model.get_application_config(
|
||||
lifecycle_utils.get_juju_model(), application)
|
||||
try:
|
||||
@@ -685,12 +1038,11 @@ def get_application_config_option(application, option):
|
||||
|
||||
|
||||
def get_undercloud_auth():
|
||||
""" Get the undercloud OpenStack authentication settings from the
|
||||
"""Get the undercloud OpenStack authentication settings from the
|
||||
environment.
|
||||
|
||||
@raises MissingOSAthenticationException if one or more settings are
|
||||
missing.
|
||||
@returns Dictionary of authentication settings
|
||||
:returns: Dictionary of authentication settings
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
os_auth_url = os.environ.get('OS_AUTH_URL')
|
||||
@@ -755,30 +1107,33 @@ def get_undercloud_auth():
|
||||
|
||||
# Openstack Client helpers
|
||||
def get_keystone_ip():
|
||||
if juju_get('keystone', 'vip'):
|
||||
return juju_get('keystone', 'vip')
|
||||
if get_application_config_option('keystone', 'vip'):
|
||||
return get_application_config_option('keystone', 'vip')
|
||||
unit = model.get_units(
|
||||
lifecycle_utils.get_juju_model(), 'keystone')[0]
|
||||
return unit.public_address
|
||||
|
||||
|
||||
def get_auth_url():
|
||||
logging.warn("Deprecated function: get_auth_url. Use get_keystone_ip")
|
||||
return get_keystone_ip()
|
||||
|
||||
|
||||
def get_overcloud_auth():
|
||||
if juju_get('keystone', 'use-https').lower() == 'yes':
|
||||
"""Get the overcloud OpenStack authentication settings from the
|
||||
environment.
|
||||
|
||||
:returns: Dictionary of authentication settings
|
||||
:rtype: dict
|
||||
"""
|
||||
|
||||
if get_application_config_option('keystone', 'use-https').lower() == 'yes':
|
||||
transport = 'https'
|
||||
port = 35357
|
||||
else:
|
||||
transport = 'http'
|
||||
port = 5000
|
||||
address = get_auth_url()
|
||||
address = get_keystone_ip()
|
||||
|
||||
os_version = get_current_os_versions('keystone')['keystone']
|
||||
|
||||
api_version = juju_get('keystone', 'preferred-api-version')
|
||||
api_version = get_application_config_option('keystone',
|
||||
'preferred-api-version')
|
||||
if os_version >= 'queens':
|
||||
api_version = 3
|
||||
elif api_version is None:
|
||||
|
||||
Reference in New Issue
Block a user