Add support for cells v2
This change adds relations necessary for registering a compute cell with the superconductor. For a cell to be registered this charm must have relations with the compute cells conductor, database and message queue. Only when all these relations are complete can the registration happen. Below are major changes included in this PR. * Add nova-cell-api relation for communicating with the nova-cell-conductor * Add shared-db-cell relation for communicating with the a compute cells database. * Add amqp-cell relation for communicating with the a compute cells message queue. * Add methods for registering cells with the superconductors database. * Charm helper sync Change-Id: Ic6ddc29426319b98b147c29031f60485fccc513f
This commit is contained in:
parent
d5c5cccb0a
commit
6695d79c95
1
hooks/amqp-cell-relation-broken
Symbolic link
1
hooks/amqp-cell-relation-broken
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/amqp-cell-relation-changed
Symbolic link
1
hooks/amqp-cell-relation-changed
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/amqp-cell-relation-joined
Symbolic link
1
hooks/amqp-cell-relation-joined
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
@ -14,6 +14,7 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import six
|
||||
import subprocess
|
||||
|
||||
|
||||
@ -95,6 +96,8 @@ class ApacheConfContext(object):
|
||||
ctxt = settings['hardening']
|
||||
|
||||
out = subprocess.check_output(['apache2', '-v'])
|
||||
if six.PY3:
|
||||
out = out.decode('utf-8')
|
||||
ctxt['apache_version'] = re.search(r'.+version: Apache/(.+?)\s.+',
|
||||
out).group(1)
|
||||
ctxt['apache_icondir'] = '/usr/share/apache2/icons/'
|
||||
|
@ -15,7 +15,7 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from six import string_types
|
||||
import six
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
@ -35,7 +35,7 @@ class DisabledModuleAudit(BaseAudit):
|
||||
def __init__(self, modules):
|
||||
if modules is None:
|
||||
self.modules = []
|
||||
elif isinstance(modules, string_types):
|
||||
elif isinstance(modules, six.string_types):
|
||||
self.modules = [modules]
|
||||
else:
|
||||
self.modules = modules
|
||||
@ -69,6 +69,8 @@ class DisabledModuleAudit(BaseAudit):
|
||||
def _get_loaded_modules():
|
||||
"""Returns the modules which are enabled in Apache."""
|
||||
output = subprocess.check_output(['apache2ctl', '-M'])
|
||||
if six.PY3:
|
||||
output = output.decode('utf-8')
|
||||
modules = []
|
||||
for line in output.splitlines():
|
||||
# Each line of the enabled module output looks like:
|
||||
|
1
hooks/nova-cell-api-relation-broken
Symbolic link
1
hooks/nova-cell-api-relation-broken
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/nova-cell-api-relation-changed
Symbolic link
1
hooks/nova-cell-api-relation-changed
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/nova-cell-api-relation-joined
Symbolic link
1
hooks/nova-cell-api-relation-joined
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
@ -105,6 +105,7 @@ from nova_cc_utils import (
|
||||
ssh_compute_remove,
|
||||
ssh_known_hosts_lines,
|
||||
ssh_authorized_keys_lines,
|
||||
update_child_cell,
|
||||
register_configs,
|
||||
restart_map,
|
||||
update_cell_database,
|
||||
@ -192,12 +193,8 @@ def leader_init_db_if_ready(skip_acl_check=False, db_rid=None, unit=None):
|
||||
allowed_units.split()):
|
||||
status_set('maintenance', 'Running nova db migration')
|
||||
migrate_nova_databases()
|
||||
log('Triggering remote cloud-compute restarts.')
|
||||
[compute_joined(rid=rid, remote_restart=True)
|
||||
for rid in relation_ids('cloud-compute')]
|
||||
log('Triggering remote neutron-network-service restarts.')
|
||||
[quantum_joined(rid=rid, remote_restart=True)
|
||||
for rid in relation_ids('quantum-network-service')]
|
||||
log('Triggering remote restarts.')
|
||||
update_nova_relation(remote_restart=True)
|
||||
else:
|
||||
log('allowed_units either not presented, or local unit '
|
||||
'not in acl list: %s' % repr(allowed_units))
|
||||
@ -252,6 +249,12 @@ def update_cell_db_if_ready_allowed_units():
|
||||
update_cell_db_if_ready(db_rid=rid, unit=unit)
|
||||
|
||||
|
||||
def update_child_cell_records():
|
||||
for r_id in relation_ids('nova-cell-api'):
|
||||
for unit in related_units(relid=r_id):
|
||||
nova_cell_api_relation_changed(rid=r_id, unit=unit)
|
||||
|
||||
|
||||
@hooks.hook('install.real')
|
||||
@harden()
|
||||
def install():
|
||||
@ -334,12 +337,10 @@ def config_changed():
|
||||
if filtered:
|
||||
apt_install(filtered, fatal=True)
|
||||
|
||||
for rid in relation_ids('quantum-network-service'):
|
||||
quantum_joined(rid=rid)
|
||||
for r_id in relation_ids('identity-service'):
|
||||
identity_joined(rid=r_id)
|
||||
[cluster_joined(rid) for rid in relation_ids('cluster')]
|
||||
[compute_joined(rid=rid) for rid in relation_ids('cloud-compute')]
|
||||
update_nova_relation()
|
||||
|
||||
update_nrpe_config()
|
||||
|
||||
@ -384,6 +385,8 @@ def amqp_changed():
|
||||
for r_id in relation_ids('nova-api'):
|
||||
nova_api_relation_joined(rid=r_id)
|
||||
|
||||
update_child_cell_records()
|
||||
|
||||
# NOTE: trigger restart on nova-api-metadata on
|
||||
# neutron-gateway units once nova-cc has working
|
||||
# amqp connection (avoiding service down on n-gateway)
|
||||
@ -455,6 +458,7 @@ def db_changed():
|
||||
# be set in nova.conf, so we attempt db init in here as well as the
|
||||
# amqp-relation-changed hook.
|
||||
update_cell_db_if_ready()
|
||||
update_child_cell_records()
|
||||
|
||||
|
||||
@hooks.hook('image-service-relation-changed')
|
||||
@ -498,8 +502,7 @@ def identity_changed():
|
||||
return
|
||||
CONFIGS.write('/etc/nova/api-paste.ini')
|
||||
CONFIGS.write(NOVA_CONF)
|
||||
[compute_joined(rid) for rid in relation_ids('cloud-compute')]
|
||||
[quantum_joined(rid) for rid in relation_ids('quantum-network-service')]
|
||||
update_nova_relation()
|
||||
[nova_vmware_relation_joined(rid) for rid in relation_ids('nova-vmware')]
|
||||
[neutron_api_relation_joined(rid) for rid in relation_ids('neutron-api')]
|
||||
configure_https()
|
||||
@ -637,8 +640,7 @@ def console_settings():
|
||||
return rel_settings
|
||||
|
||||
|
||||
@hooks.hook('cloud-compute-relation-joined')
|
||||
def compute_joined(rid=None, remote_restart=False):
|
||||
def get_compute_config(rid=None, remote_restart=False):
|
||||
cons_settings = console_settings()
|
||||
relation_set(relation_id=rid, **cons_settings)
|
||||
rel_settings = {
|
||||
@ -655,6 +657,21 @@ def compute_joined(rid=None, remote_restart=False):
|
||||
if remote_restart:
|
||||
rel_settings['restart_trigger'] = str(uuid.uuid4())
|
||||
|
||||
return rel_settings
|
||||
|
||||
|
||||
def update_nova_relation(remote_restart=False):
|
||||
for rid in relation_ids('cloud-compute'):
|
||||
compute_joined(rid=rid, remote_restart=remote_restart)
|
||||
for rid in relation_ids('quantum-network-service'):
|
||||
quantum_joined(rid=rid, remote_restart=remote_restart)
|
||||
for rid in relation_ids('nova-cell-api'):
|
||||
nova_cell_api_relation_joined(rid=rid, remote_restart=remote_restart)
|
||||
|
||||
|
||||
@hooks.hook('cloud-compute-relation-joined')
|
||||
def compute_joined(rid=None, remote_restart=False):
|
||||
rel_settings = get_compute_config(rid=rid, remote_restart=remote_restart)
|
||||
rel_settings.update(keystone_compute_settings())
|
||||
relation_set(relation_id=rid, **rel_settings)
|
||||
|
||||
@ -1010,10 +1027,7 @@ def neutron_api_relation_joined(rid=None, remote_restart=False):
|
||||
@restart_on_change(restart_map())
|
||||
def neutron_api_relation_changed():
|
||||
CONFIGS.write(NOVA_CONF)
|
||||
for rid in relation_ids('cloud-compute'):
|
||||
compute_joined(rid=rid)
|
||||
for rid in relation_ids('quantum-network-service'):
|
||||
quantum_joined(rid=rid)
|
||||
update_nova_relation()
|
||||
|
||||
|
||||
@hooks.hook('neutron-api-relation-broken')
|
||||
@ -1022,10 +1036,7 @@ def neutron_api_relation_changed():
|
||||
@restart_on_change(restart_map())
|
||||
def neutron_api_relation_broken():
|
||||
CONFIGS.write_all()
|
||||
for rid in relation_ids('cloud-compute'):
|
||||
compute_joined(rid=rid)
|
||||
for rid in relation_ids('quantum-network-service'):
|
||||
quantum_joined(rid=rid)
|
||||
update_nova_relation()
|
||||
|
||||
|
||||
@hooks.hook('nrpe-external-master-relation-joined',
|
||||
@ -1151,6 +1162,65 @@ def certs_changed(relation_id=None, unit=None):
|
||||
configure_https()
|
||||
|
||||
|
||||
@hooks.hook('amqp-cell-relation-joined')
|
||||
def amqp_cell_joined(relation_id=None):
|
||||
relation_set(relation_id=relation_id,
|
||||
username='nova', vhost='nova')
|
||||
|
||||
|
||||
@hooks.hook('shared-db-cell-relation-joined')
|
||||
def shared_db_cell_joined(relation_id=None):
|
||||
access_network = None
|
||||
for unit in related_units(relid=relation_id):
|
||||
access_network = relation_get(rid=relation_id, unit=unit,
|
||||
attribute='access-network')
|
||||
if access_network:
|
||||
break
|
||||
host = get_relation_ip('shared-db', cidr_network=access_network)
|
||||
cell_db = {
|
||||
'nova_database': 'nova',
|
||||
'nova_username': config('database-user'),
|
||||
'nova_hostname': host}
|
||||
relation_set(relation_id=relation_id, **cell_db)
|
||||
|
||||
|
||||
@hooks.hook('nova-cell-api-relation-joined')
|
||||
def nova_cell_api_relation_joined(rid=None, remote_restart=False):
|
||||
rel_settings = get_compute_config(rid=rid, remote_restart=remote_restart)
|
||||
if network_manager() == 'neutron':
|
||||
rel_settings.update(neutron_settings())
|
||||
relation_set(relation_id=rid, **rel_settings)
|
||||
|
||||
|
||||
@hooks.hook('shared-db-cell-relation-changed')
|
||||
def shared_db_cell_changed(relation_id=None):
|
||||
update_child_cell_records()
|
||||
|
||||
|
||||
@hooks.hook('amqp-cell-relation-changed')
|
||||
def amqp_cell_changed(relation_id=None):
|
||||
update_child_cell_records()
|
||||
|
||||
|
||||
@hooks.hook('nova-cell-api-relation-changed')
|
||||
def nova_cell_api_relation_changed(rid=None, unit=None):
|
||||
data = relation_get(rid=rid, unit=unit)
|
||||
log("Data: {}".format(data, level=DEBUG))
|
||||
if not data.get('cell-name'):
|
||||
return
|
||||
cell_updated = update_child_cell(
|
||||
name=data['cell-name'],
|
||||
db_service=data['db-service'],
|
||||
amqp_service=data['amqp-service'])
|
||||
if cell_updated:
|
||||
log(
|
||||
"Cell registration data changed, triggering a remote restart",
|
||||
level=DEBUG)
|
||||
relation_set(
|
||||
relation_id=rid,
|
||||
restart_trigger=str(uuid.uuid4()))
|
||||
|
||||
|
||||
@hooks.hook('update-status')
|
||||
@harden()
|
||||
def update_status():
|
||||
|
@ -15,6 +15,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import ConfigParser
|
||||
import uuid
|
||||
|
||||
from base64 import b64encode
|
||||
from collections import OrderedDict
|
||||
@ -72,6 +73,7 @@ from charmhelpers.core.hookenv import (
|
||||
leader_get,
|
||||
leader_set,
|
||||
relation_get,
|
||||
relation_id,
|
||||
relation_ids,
|
||||
remote_unit,
|
||||
DEBUG,
|
||||
@ -88,6 +90,7 @@ from charmhelpers.core.host import (
|
||||
service_running,
|
||||
service_start,
|
||||
service_stop,
|
||||
service_restart,
|
||||
lsb_release,
|
||||
CompareHostReleases,
|
||||
)
|
||||
@ -791,23 +794,48 @@ def initialize_cell_databases():
|
||||
'the transport_url/database combination.', level=INFO)
|
||||
|
||||
|
||||
def get_cell_uuid(cell):
|
||||
def get_cell_uuid(cell, fatal=True):
|
||||
'''Get cell uuid
|
||||
:param cell: string cell name i.e. 'cell1'
|
||||
:returns: string cell uuid
|
||||
'''
|
||||
log("Listing cell, '{}'".format(cell), level=INFO)
|
||||
cmd = ['sudo', 'nova-manage', 'cell_v2', 'list_cells']
|
||||
cells = get_cell_details()
|
||||
cell_info = cells.get(cell)
|
||||
if not cell_info:
|
||||
if fatal:
|
||||
raise Exception("Cannot find cell, '{}', in list_cells."
|
||||
"".format(cell))
|
||||
return None
|
||||
return cell_info['uuid']
|
||||
|
||||
|
||||
def get_cell_details():
|
||||
'''Get cell details
|
||||
:returns: string cell uuid
|
||||
'''
|
||||
log("Getting details of cells", level=INFO)
|
||||
cells = {}
|
||||
cmd = ['sudo', 'nova-manage', 'cell_v2', 'list_cells', '--verbose']
|
||||
try:
|
||||
out = subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log('list_cells failed\n{}'.format(e.output), level=ERROR)
|
||||
raise
|
||||
cell_uuid = out.split(cell, 1)[1].split()[1]
|
||||
if not cell_uuid:
|
||||
raise Exception("Cannot find cell, '{}', in list_cells."
|
||||
"".format(cell))
|
||||
return cell_uuid
|
||||
for line in out.split('\n'):
|
||||
columns = line.split('|')
|
||||
if len(columns) < 2:
|
||||
continue
|
||||
columns = [c.strip() for c in columns]
|
||||
try:
|
||||
uuid.UUID(columns[2].strip())
|
||||
cells[columns[1]] = {
|
||||
'uuid': columns[2],
|
||||
'amqp': columns[3],
|
||||
'db': columns[4]}
|
||||
except ValueError:
|
||||
pass
|
||||
return cells
|
||||
|
||||
|
||||
def update_cell_database():
|
||||
@ -1480,4 +1508,110 @@ def write_vendordata(vdata):
|
||||
return False
|
||||
with open(VENDORDATA_FILE, 'w') as vdata_file:
|
||||
vdata_file.write(json.dumps(json_vdata, sort_keys=True, indent=2))
|
||||
|
||||
|
||||
def get_cell_db_context(db_service):
|
||||
"""Return the database context for the given service name"""
|
||||
db_rid = relation_id(
|
||||
relation_name='shared-db-cell',
|
||||
service_or_unit=db_service)
|
||||
return context.SharedDBContext(
|
||||
relation_prefix='nova',
|
||||
ssl_dir=NOVA_CONF_DIR,
|
||||
relation_id=db_rid)()
|
||||
|
||||
|
||||
def get_cell_amqp_context(amqp_service):
|
||||
"""Return the amqp context for the given service name"""
|
||||
amq_rid = relation_id(
|
||||
relation_name='amqp-cell',
|
||||
service_or_unit=amqp_service)
|
||||
return context.AMQPContext(
|
||||
ssl_dir=NOVA_CONF_DIR,
|
||||
relation_id=amq_rid)()
|
||||
|
||||
|
||||
def get_sql_uri(db_ctxt):
|
||||
"""Return the uri for conextind to the database in the supplied context"""
|
||||
uri_template = ("{database_type}://{database_user}:{database_password}"
|
||||
"@{database_host}/{database}")
|
||||
uri = uri_template.format(**db_ctxt)
|
||||
if db_ctxt.get('database_ssl_ca'):
|
||||
uri = uri + '?ssl_ca={database_ssl_ca}'.format(**db_ctxt)
|
||||
if db_ctxt.get('database_ssl_cert'):
|
||||
uri = uri + ('&ssl_cert={database_ssl_cert}'
|
||||
'&ssl_key={database_ssl_key}').format(**db_ctxt)
|
||||
return uri
|
||||
|
||||
|
||||
def update_child_cell(name, db_service, amqp_service, skip_acl_check=True):
|
||||
"""Register cell.
|
||||
|
||||
Registering a cell requires:
|
||||
1) Complete relation with api db service.
|
||||
2) Complete relation with cells db service.
|
||||
3) Complete relation with cells amqp service.
|
||||
"""
|
||||
if not is_db_initialised():
|
||||
log(
|
||||
'Defering registering Cell {}, api db not ready.'.format(name),
|
||||
level=DEBUG)
|
||||
return False
|
||||
|
||||
existing_cells = get_cell_details()
|
||||
if not existing_cells.get('cell1'):
|
||||
log('Defering registering cell {}, api cell setup is not complete.'
|
||||
''.format(name),
|
||||
level=DEBUG)
|
||||
return False
|
||||
|
||||
db_ctxt = get_cell_db_context(db_service)
|
||||
if not db_ctxt:
|
||||
log('Defering registering cell {}, cell db relation not '
|
||||
'ready.'.format(name),
|
||||
level=DEBUG)
|
||||
return False
|
||||
sql_connection = get_sql_uri(db_ctxt)
|
||||
|
||||
amqp_ctxt = get_cell_amqp_context(amqp_service)
|
||||
if not amqp_ctxt:
|
||||
log('Defering registering cell {}, cell amqp relation not '
|
||||
'ready.'.format(name),
|
||||
level=DEBUG)
|
||||
return False
|
||||
|
||||
cmd = [
|
||||
'nova-manage',
|
||||
'cell_v2',
|
||||
]
|
||||
|
||||
if existing_cells.get(name):
|
||||
log('Cell {} already registered, checking if details are correct.'
|
||||
''.format(name), level=DEBUG)
|
||||
if (amqp_ctxt['transport_url'] == existing_cells[name]['amqp'] and
|
||||
sql_connection == existing_cells[name]['db']):
|
||||
log('Cell details are correct no update needed', level=DEBUG)
|
||||
return False
|
||||
else:
|
||||
log('Cell details have changed', level=DEBUG)
|
||||
cmd.extend([
|
||||
'update_cell',
|
||||
'--cell_uuid', existing_cells[name]['uuid']])
|
||||
else:
|
||||
log(
|
||||
'Cell {} is new and needs to be created.'.format(name),
|
||||
level=DEBUG)
|
||||
cmd.extend(['create_cell', '--verbose'])
|
||||
|
||||
cmd.extend([
|
||||
'--name', name,
|
||||
'--transport-url', amqp_ctxt['transport_url'],
|
||||
'--database_connection', sql_connection])
|
||||
try:
|
||||
log('Updating cell {}'.format(name), level=DEBUG)
|
||||
subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log('Register cell failed\n{}'.format(e.output), level=ERROR)
|
||||
raise
|
||||
service_restart('nova-scheduler')
|
||||
return True
|
||||
|
1
hooks/shared-db-cell-relation-broken
Symbolic link
1
hooks/shared-db-cell-relation-broken
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/shared-db-cell-relation-changed
Symbolic link
1
hooks/shared-db-cell-relation-changed
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
1
hooks/shared-db-cell-relation-joined
Symbolic link
1
hooks/shared-db-cell-relation-joined
Symbolic link
@ -0,0 +1 @@
|
||||
nova_cc_hooks.py
|
@ -30,6 +30,8 @@ provides:
|
||||
scope: container
|
||||
cloud-controller:
|
||||
interface: nova
|
||||
nova-cell-api:
|
||||
interface: nova-cell
|
||||
requires:
|
||||
shared-db:
|
||||
interface: mysql-shared
|
||||
@ -57,6 +59,10 @@ requires:
|
||||
interface: memcache
|
||||
certificates:
|
||||
interface: tls-certificates
|
||||
shared-db-cell:
|
||||
interface: mysql-shared
|
||||
amqp-cell:
|
||||
interface: rabbitmq
|
||||
peers:
|
||||
cluster:
|
||||
interface: nova-ha
|
||||
|
@ -693,7 +693,7 @@ class NovaCCHooksTests(CharmTestCase):
|
||||
def _relation_ids(rel):
|
||||
relid = {
|
||||
'cloud-compute': ['nova-compute/0'],
|
||||
'cell': ['nova-cell-api/0'],
|
||||
'nova-cell-api': ['nova-cell-controller/0'],
|
||||
'neutron-api': ['neutron-api/0'],
|
||||
'quantum-network-service': ['neutron-gateway/0']
|
||||
}
|
||||
@ -721,6 +721,7 @@ class NovaCCHooksTests(CharmTestCase):
|
||||
hooks.relation_broken()
|
||||
self.assertTrue(configs.write_all.called)
|
||||
|
||||
@patch.object(hooks, 'update_child_cell_records')
|
||||
@patch.object(hooks, 'leader_init_db_if_ready_allowed_units')
|
||||
@patch.object(hooks, 'update_cell_db_if_ready_allowed_units')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@ -729,7 +730,8 @@ class NovaCCHooksTests(CharmTestCase):
|
||||
@patch.object(hooks, 'CONFIGS')
|
||||
def test_amqp_changed_api_rel(self, configs, api_joined,
|
||||
quantum_joined, mock_is_db_initialised,
|
||||
update_db_allowed, init_db_allowed):
|
||||
update_db_allowed, init_db_allowed,
|
||||
mock_update_child_cell_records):
|
||||
self.relation_ids.side_effect = [
|
||||
['nova-api/0'],
|
||||
['quantum-service/0'],
|
||||
@ -747,6 +749,7 @@ class NovaCCHooksTests(CharmTestCase):
|
||||
quantum_joined.assert_called_with(rid='quantum-service/0',
|
||||
remote_restart=True)
|
||||
|
||||
@patch.object(hooks, 'update_child_cell_records')
|
||||
@patch.object(hooks, 'leader_init_db_if_ready_allowed_units')
|
||||
@patch.object(hooks, 'update_cell_db_if_ready_allowed_units')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@ -755,7 +758,8 @@ class NovaCCHooksTests(CharmTestCase):
|
||||
@patch.object(hooks, 'CONFIGS')
|
||||
def test_amqp_changed_noapi_rel(self, configs, api_joined,
|
||||
quantum_joined, mock_is_db_initialised,
|
||||
update_db_allowed, init_db_allowed):
|
||||
update_db_allowed, init_db_allowed,
|
||||
mock_update_child_cell_records):
|
||||
mock_is_db_initialised.return_value = False
|
||||
configs.complete_contexts = MagicMock()
|
||||
configs.complete_contexts.return_value = ['amqp']
|
||||
|
@ -198,6 +198,15 @@ ubuntu-cloud-archive/liberty-staging/ubuntu trusty main
|
||||
%s
|
||||
""" % GPG_PPA_CLOUD_ARCHIVE
|
||||
|
||||
NM_CELLS_LIST = """
|
||||
+-------+--------------------------------------+--------------+-------------+
|
||||
| Name | UUID | Transport | DB |
|
||||
+-------+--------------------------------------+--------------+-------------+
|
||||
| cell0 | 00000000-0000-0000-0000-000000000000 | none:/// | mysql_cell0 |
|
||||
| cell1 | 7a8a0e58-e127-4056-bb98-99d9579ca08b | rabbit_cell1 | mysql_cell1 |
|
||||
+-------+--------------------------------------+--------------+-------------+
|
||||
"""
|
||||
|
||||
|
||||
class NovaCCUtilsTests(CharmTestCase):
|
||||
|
||||
@ -1123,14 +1132,8 @@ class NovaCCUtilsTests(CharmTestCase):
|
||||
|
||||
@patch('subprocess.check_output')
|
||||
def test_get_cell_uuid(self, mock_check_call):
|
||||
mock_check_call.return_value = ("""
|
||||
+-------+--------------------------------------+
|
||||
| Name | UUID |
|
||||
+-------+--------------------------------------+
|
||||
| cell0 | 00000000-0000-0000-0000-000000000000 |
|
||||
| cell1 | c83121db-f1c7-464a-b657-38c28fac84c6 |
|
||||
+-------+--------------------------------------+""")
|
||||
expected = 'c83121db-f1c7-464a-b657-38c28fac84c6'
|
||||
mock_check_call.return_value = NM_CELLS_LIST
|
||||
expected = '7a8a0e58-e127-4056-bb98-99d9579ca08b'
|
||||
self.assertEqual(expected, utils.get_cell_uuid('cell1'))
|
||||
|
||||
@patch.object(utils, 'get_cell_uuid')
|
||||
@ -1315,3 +1318,147 @@ class NovaCCUtilsTests(CharmTestCase):
|
||||
call().write('{\n "a": "b"\n}')]
|
||||
for c in expected_calls:
|
||||
self.assertTrue(c in m.mock_calls)
|
||||
|
||||
@patch.object(utils.context, 'SharedDBContext')
|
||||
@patch.object(utils, 'relation_id')
|
||||
def test_get_cell_db_context(self, mock_relation_id, mock_SharedDBContext):
|
||||
mock_relation_id.return_value = 'dbid'
|
||||
utils.get_cell_db_context('mysql-cell2')
|
||||
mock_SharedDBContext.assert_called_once_with(
|
||||
relation_id='dbid',
|
||||
relation_prefix='nova',
|
||||
ssl_dir='/etc/nova')
|
||||
mock_relation_id.assert_called_once_with(
|
||||
relation_name='shared-db-cell',
|
||||
service_or_unit='mysql-cell2')
|
||||
|
||||
@patch.object(utils.context, 'AMQPContext')
|
||||
@patch.object(utils, 'relation_id')
|
||||
def test_get_cell_amqp_context(self, mock_relation_id, mock_AMQPContext):
|
||||
mock_relation_id.return_value = 'amqpid'
|
||||
utils.get_cell_amqp_context('rabbitmq-server-cell2')
|
||||
mock_AMQPContext.assert_called_once_with(
|
||||
relation_id='amqpid',
|
||||
ssl_dir='/etc/nova')
|
||||
mock_relation_id.assert_called_once_with(
|
||||
relation_name='amqp-cell',
|
||||
service_or_unit='rabbitmq-server-cell2')
|
||||
|
||||
def test_get_sql_uri(self):
|
||||
base_ctxt = {
|
||||
'database_type': 'mysql',
|
||||
'database_user': 'nova',
|
||||
'database_password': 'novapass',
|
||||
'database_host': '10.0.0.10',
|
||||
'database': 'novadb'}
|
||||
self.assertEqual(
|
||||
utils.get_sql_uri(base_ctxt),
|
||||
'mysql://nova:novapass@10.0.0.10/novadb')
|
||||
sslca_ctxt = {'database_ssl_ca': 'myca'}
|
||||
sslca_ctxt.update(base_ctxt)
|
||||
self.assertEqual(
|
||||
utils.get_sql_uri(sslca_ctxt),
|
||||
'mysql://nova:novapass@10.0.0.10/novadb?ssl_ca=myca')
|
||||
ssl_cert_ctxt = {
|
||||
'database_ssl_cert': 'mycert',
|
||||
'database_ssl_key': 'mykey'}
|
||||
ssl_cert_ctxt.update(sslca_ctxt)
|
||||
self.assertEqual(
|
||||
utils.get_sql_uri(ssl_cert_ctxt),
|
||||
('mysql://nova:novapass@10.0.0.10/novadb?ssl_ca=myca&'
|
||||
'ssl_cert=mycert&ssl_key=mykey'))
|
||||
|
||||
@patch.object(utils, 'is_db_initialised')
|
||||
@patch.object(utils, 'get_cell_details')
|
||||
@patch.object(utils, 'get_cell_db_context')
|
||||
@patch.object(utils, 'get_cell_amqp_context')
|
||||
@patch.object(utils, 'get_sql_uri')
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_update_child_cell(self, mock_service_restart, mock_check_output,
|
||||
mock_get_sql_uri, mock_get_cell_amqp_context,
|
||||
mock_get_cell_db_context, mock_get_cell_details,
|
||||
mock_is_db_initialised):
|
||||
mock_is_db_initialised.return_value = True
|
||||
mock_get_cell_details.return_value = {'cell1': 'cell1uuid'}
|
||||
mock_get_cell_db_context.return_value = {'ctxt': 'a full context'}
|
||||
mock_get_cell_amqp_context.return_value = {'transport_url': 'amqp-uri'}
|
||||
mock_get_sql_uri.return_value = 'db-uri'
|
||||
utils.update_child_cell('cell2', 'mysql-cell2', 'amqp-cell2')
|
||||
mock_get_cell_amqp_context.assert_called_once_with('amqp-cell2')
|
||||
mock_get_cell_db_context.assert_called_once_with('mysql-cell2')
|
||||
mock_check_output.assert_called_once_with([
|
||||
'nova-manage',
|
||||
'cell_v2',
|
||||
'create_cell',
|
||||
'--verbose',
|
||||
'--name', 'cell2',
|
||||
'--transport-url', 'amqp-uri',
|
||||
'--database_connection', 'db-uri'])
|
||||
mock_service_restart.assert_called_once_with('nova-scheduler')
|
||||
|
||||
@patch.object(utils, 'is_db_initialised')
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_update_child_cell_no_local_db(self, mock_service_restart,
|
||||
mock_check_output,
|
||||
mock_is_db_initialised):
|
||||
mock_is_db_initialised.return_value = False
|
||||
utils.update_child_cell('cell2', 'mysql-cell2', 'amqp-cell2')
|
||||
self.assertFalse(mock_check_output.called)
|
||||
self.assertFalse(mock_service_restart.called)
|
||||
|
||||
@patch.object(utils, 'get_cell_details')
|
||||
@patch.object(utils, 'is_db_initialised')
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_update_child_cell_api_cell_not_registered(self,
|
||||
mock_service_restart,
|
||||
mock_check_output,
|
||||
mock_is_db_initialised,
|
||||
mock_get_cell_details):
|
||||
mock_is_db_initialised.return_value = True
|
||||
mock_get_cell_details.return_value = {}
|
||||
utils.update_child_cell('cell2', 'mysql-cell2', 'amqp-cell2')
|
||||
mock_get_cell_details.assert_called_once_with()
|
||||
self.assertFalse(mock_check_output.called)
|
||||
self.assertFalse(mock_service_restart.called)
|
||||
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
@patch.object(utils, 'service_restart')
|
||||
@patch.object(utils, 'get_cell_details')
|
||||
@patch.object(utils, 'is_db_initialised')
|
||||
@patch.object(utils, 'get_cell_db_context')
|
||||
def test_update_child_cell_no_cell_db(self, mock_get_cell_db_context,
|
||||
mock_is_db_initialised,
|
||||
mock_get_cell_details,
|
||||
mock_service_restart,
|
||||
mock_check_output):
|
||||
mock_is_db_initialised.return_value = True
|
||||
mock_get_cell_details.return_value = {'cell1': 'uuid4cell1'}
|
||||
mock_get_cell_db_context.return_value = {}
|
||||
utils.update_child_cell('cell2', 'mysql-cell2', 'amqp-cell2')
|
||||
self.assertFalse(mock_check_output.called)
|
||||
self.assertFalse(mock_service_restart.called)
|
||||
|
||||
@patch.object(utils, 'get_cell_amqp_context')
|
||||
@patch.object(utils, 'get_sql_uri')
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
@patch.object(utils, 'service_restart')
|
||||
@patch.object(utils, 'get_cell_details')
|
||||
@patch.object(utils, 'is_db_initialised')
|
||||
@patch.object(utils, 'get_cell_db_context')
|
||||
def test_update_child_cell_no_cell_amqp(self, mock_get_cell_db_context,
|
||||
mock_is_db_initialised,
|
||||
mock_get_cell_details,
|
||||
mock_service_restart,
|
||||
mock_check_output,
|
||||
mock_get_sql_uri,
|
||||
mock_get_cell_amqp_context):
|
||||
mock_is_db_initialised.return_value = True
|
||||
mock_get_cell_details.return_value = {'cell1': 'uuid4cell1'}
|
||||
mock_get_cell_db_context.return_value = {'ctxt': 'a full context'}
|
||||
mock_get_cell_amqp_context.return_value = {}
|
||||
utils.update_child_cell('cell2', 'mysql-cell2', 'amqp-cell2')
|
||||
self.assertFalse(mock_check_output.called)
|
||||
self.assertFalse(mock_service_restart.called)
|
||||
|
Loading…
x
Reference in New Issue
Block a user