Last active
January 12, 2018 12:17
-
-
Save gnuoy/aff86d0ad616a890ba731a3cb7deef51 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/config.yaml b/config.yaml | |
index 3e4a4e9..387d7b6 100644 | |
--- a/config.yaml | |
+++ b/config.yaml | |
@@ -1,4 +1,11 @@ | |
options: | |
+ cell-name: | |
+ type: string | |
+ default: | |
+ description: | | |
+ Name of the compute cell this controller is associated with. If this is | |
+ left unset or set to api then it is assumed that this controller will be | |
+ the top level api and cell0 controller. | |
debug: | |
type: boolean | |
default: False | |
diff --git a/hooks/amqp-cell-relation-broken b/hooks/amqp-cell-relation-broken | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/amqp-cell-relation-broken | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/amqp-cell-relation-changed b/hooks/amqp-cell-relation-changed | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/amqp-cell-relation-changed | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/amqp-cell-relation-joined b/hooks/amqp-cell-relation-joined | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/amqp-cell-relation-joined | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py | |
index 70850c1..9f6079b 100644 | |
--- a/hooks/charmhelpers/contrib/openstack/context.py | |
+++ b/hooks/charmhelpers/contrib/openstack/context.py | |
@@ -192,8 +192,8 @@ class OSContextGenerator(object): | |
class SharedDBContext(OSContextGenerator): | |
interfaces = ['shared-db'] | |
- def __init__(self, | |
- database=None, user=None, relation_prefix=None, ssl_dir=None): | |
+ def __init__(self, database=None, user=None, relation_prefix=None, | |
+ ssl_dir=None, relation_id=None): | |
"""Allows inspecting relation for settings prefixed with | |
relation_prefix. This is useful for parsing access for multiple | |
databases returned via the shared-db interface (eg, nova_password, | |
@@ -204,6 +204,7 @@ class SharedDBContext(OSContextGenerator): | |
self.user = user | |
self.ssl_dir = ssl_dir | |
self.rel_name = self.interfaces[0] | |
+ self.relation_id = relation_id | |
def __call__(self): | |
self.database = self.database or config('database') | |
@@ -237,7 +238,12 @@ class SharedDBContext(OSContextGenerator): | |
if self.relation_prefix: | |
password_setting = self.relation_prefix + '_password' | |
- for rid in relation_ids(self.interfaces[0]): | |
+ if self.relation_id: | |
+ rids = [self.relation_id] | |
+ else: | |
+ rids = relation_ids(self.interfaces[0]) | |
+ | |
+ for rid in rids: | |
self.related = True | |
for unit in related_units(rid): | |
rdata = relation_get(rid=rid, unit=unit) | |
@@ -334,10 +340,7 @@ class IdentityServiceContext(OSContextGenerator): | |
self.rel_name = rel_name | |
self.interfaces = [self.rel_name] | |
- def __call__(self): | |
- log('Generating template context for ' + self.rel_name, level=DEBUG) | |
- ctxt = {} | |
- | |
+ def _setup_pki_cache(self): | |
if self.service and self.service_user: | |
# This is required for pki token signing if we don't want /tmp to | |
# be used. | |
@@ -347,6 +350,15 @@ class IdentityServiceContext(OSContextGenerator): | |
mkdir(path=cachedir, owner=self.service_user, | |
group=self.service_user, perms=0o700) | |
+ return cachedir | |
+ return None | |
+ | |
+ def __call__(self): | |
+ log('Generating template context for ' + self.rel_name, level=DEBUG) | |
+ ctxt = {} | |
+ | |
+ cachedir = self._setup_pki_cache() | |
+ if cachedir: | |
ctxt['signing_dir'] = cachedir | |
for rid in relation_ids(self.rel_name): | |
@@ -385,13 +397,71 @@ class IdentityServiceContext(OSContextGenerator): | |
return {} | |
+class IdentityCredentialsContext(IdentityServiceContext): | |
+ '''Context for identity-credentials interface type''' | |
+ | |
+ def __init__(self, | |
+ service=None, | |
+ service_user=None, | |
+ rel_name='identity-credentials'): | |
+ super(IdentityCredentialsContext, self).__init__(service, | |
+ service_user, | |
+ rel_name) | |
+ | |
+ def __call__(self): | |
+ log('Generating template context for ' + self.rel_name, level=DEBUG) | |
+ ctxt = {} | |
+ | |
+ cachedir = self._setup_pki_cache() | |
+ if cachedir: | |
+ ctxt['signing_dir'] = cachedir | |
+ | |
+ for rid in relation_ids(self.rel_name): | |
+ self.related = True | |
+ for unit in related_units(rid): | |
+ rdata = relation_get(rid=rid, unit=unit) | |
+ credentials_host = rdata.get('credentials_host') | |
+ credentials_host = ( | |
+ format_ipv6_addr(credentials_host) or credentials_host | |
+ ) | |
+ auth_host = rdata.get('auth_host') | |
+ auth_host = format_ipv6_addr(auth_host) or auth_host | |
+ svc_protocol = rdata.get('credentials_protocol') or 'http' | |
+ auth_protocol = rdata.get('auth_protocol') or 'http' | |
+ api_version = rdata.get('api_version') or '2.0' | |
+ ctxt.update({ | |
+ 'service_port': rdata.get('credentials_port'), | |
+ 'service_host': credentials_host, | |
+ 'auth_host': auth_host, | |
+ 'auth_port': rdata.get('auth_port'), | |
+ 'admin_tenant_name': rdata.get('credentials_project'), | |
+ 'admin_tenant_id': rdata.get('credentials_project_id'), | |
+ 'admin_user': rdata.get('credentials_username'), | |
+ 'admin_password': rdata.get('credentials_password'), | |
+ 'service_protocol': svc_protocol, | |
+ 'auth_protocol': auth_protocol, | |
+ 'api_version': api_version | |
+ }) | |
+ | |
+ if float(api_version) > 2: | |
+ ctxt.update({'admin_domain_name': | |
+ rdata.get('domain')}) | |
+ | |
+ if self.context_complete(ctxt): | |
+ return ctxt | |
+ | |
+ return {} | |
+ | |
+ | |
class AMQPContext(OSContextGenerator): | |
- def __init__(self, ssl_dir=None, rel_name='amqp', relation_prefix=None): | |
+ def __init__(self, ssl_dir=None, rel_name='amqp', relation_prefix=None, | |
+ relation_id=None): | |
self.ssl_dir = ssl_dir | |
self.rel_name = rel_name | |
self.relation_prefix = relation_prefix | |
self.interfaces = [rel_name] | |
+ self.relation_id = relation_id | |
def __call__(self): | |
log('Generating template context for amqp', level=DEBUG) | |
@@ -412,7 +482,11 @@ class AMQPContext(OSContextGenerator): | |
raise OSContextError | |
ctxt = {} | |
- for rid in relation_ids(self.rel_name): | |
+ if self.relation_id: | |
+ rids = [self.relation_id] | |
+ else: | |
+ rids = relation_ids(self.rel_name) | |
+ for rid in rids: | |
ha_vip_only = False | |
self.related = True | |
transport_hosts = None | |
diff --git a/hooks/nova-cell-api-relation-changed b/hooks/nova-cell-api-relation-changed | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/nova-cell-api-relation-changed | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/nova-cell-api-relation-joined b/hooks/nova-cell-api-relation-joined | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/nova-cell-api-relation-joined | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/nova-cell-relation-changed b/hooks/nova-cell-relation-changed | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/nova-cell-relation-changed | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/nova-cell-relation-joined b/hooks/nova-cell-relation-joined | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/nova-cell-relation-joined | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py | |
index 4874a9c..6457b3c 100644 | |
--- a/hooks/nova_cc_context.py | |
+++ b/hooks/nova_cc_context.py | |
@@ -412,4 +412,8 @@ class NovaAPISharedDBContext(context.SharedDBContext): | |
if ctxt is not None: | |
prefix = 'nova_api_{}' | |
ctxt = {prefix.format(k): v for k, v in ctxt.items()} | |
+ if not config('cell-name') or config('cell-name') == 'cell0': | |
+ ctxt['enable_api_db'] = True | |
+ else: | |
+ ctxt['enable_api_db'] = False | |
return ctxt | |
diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py | |
index e25d8c7..c12ca69 100755 | |
--- a/hooks/nova_cc_hooks.py | |
+++ b/hooks/nova_cc_hooks.py | |
@@ -117,6 +117,10 @@ from nova_cc_utils import ( | |
assess_status, | |
update_aws_compat_services, | |
serial_console_settings, | |
+ get_cell_name, | |
+ get_cell_db_name, | |
+ is_api_cell, | |
+ register_cell, | |
) | |
from charmhelpers.contrib.hahelpers.cluster import ( | |
@@ -353,6 +357,16 @@ def amqp_joined(relation_id=None): | |
username=config('rabbit-user'), vhost=config('rabbit-vhost')) | |
+@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('amqp-cell-relation-changed') | |
+def amqp_cell_changed(relation_id=None): | |
+ log(relation_get()) | |
+ | |
+ | |
@hooks.hook('amqp-relation-changed') | |
@hooks.hook('amqp-relation-departed') | |
@service_guard(guard_map(), CONFIGS, | |
@@ -379,7 +393,55 @@ def amqp_changed(): | |
# amqp connection (avoiding service down on n-gateway) | |
for rid in relation_ids('quantum-network-service'): | |
quantum_joined(rid=rid, remote_restart=True) | |
- | |
+ for r_id in relation_ids('nova-cell'): | |
+ cell_relation_joined(rid=r_id) | |
+ 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('shared-db-api-relation-joined') | |
+#def shared_db_api_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) | |
+# relation_set(relation_id=relation_id, novaapi_hostname=host, | |
+# novaapi_database='nova_api', novaapi_username='nova') | |
+# | |
+#@hooks.hook('shared-db-api-relation-changed') | |
+#def shared_db_api_cell_changed(relation_id=None): | |
+# log(relation_get()) | |
+ | |
+@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_name = get_cell_db_name() | |
+# cell_name = get_cell_name() | |
+# cell_db = { | |
+# 'nova{}_database'.format(cell_name): cell_db_name, | |
+# 'nova{}_username'.format(cell_name): config('database-user'), | |
+# 'nova{}_hostname'.format(cell_name): host} | |
+ cell_db = { | |
+ 'nova_database': 'nova', | |
+ 'nova_username': config('database-user'), | |
+ 'nova_hostname': host} | |
+ relation_set(relation_id=relation_id, **cell_db) | |
+ | |
+@hooks.hook('shared-db-cell-relation-changed') | |
+def shared_db_cell_changed(relation_id=None): | |
+ 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('shared-db-relation-joined') | |
def db_joined(relation_id=None): | |
@@ -389,17 +451,20 @@ def db_joined(relation_id=None): | |
config('database-user'), | |
relation_prefix='nova') | |
- if cmp_os_release >= 'mitaka': | |
+ if cmp_os_release >= 'mitaka' and is_api_cell(): | |
# NOTE: mitaka uses a second nova-api database as well | |
sync_db_with_multi_ipv6_addresses('nova_api', | |
config('database-user'), | |
relation_prefix='novaapi') | |
if cmp_os_release >= 'ocata': | |
+ cell_db_name = get_cell_db_name() | |
+ cell_name = get_cell_name() | |
# NOTE: ocata requires cells v2 | |
- sync_db_with_multi_ipv6_addresses('nova_cell0', | |
- config('database-user'), | |
- relation_prefix='novacell0') | |
+ sync_db_with_multi_ipv6_addresses( | |
+ 'nova{}'.format(cell_name), | |
+ config('database-user'), | |
+ relation_prefix='nova{}'.format(cell_name)) | |
else: | |
# Avoid churn check for access-network early | |
access_network = None | |
@@ -415,20 +480,34 @@ def db_joined(relation_id=None): | |
nova_hostname=host, | |
relation_id=relation_id) | |
- if cmp_os_release >= 'mitaka': | |
+ if cmp_os_release >= 'mitaka' and is_api_cell(): | |
# NOTE: mitaka uses a second nova-api database as well | |
relation_set(novaapi_database='nova_api', | |
novaapi_username=config('database-user'), | |
novaapi_hostname=host, | |
relation_id=relation_id) | |
- if cmp_os_release >= 'ocata': | |
+ if cmp_os_release >= 'ocata' and is_api_cell(): | |
# NOTE: ocata requires cells v2 | |
relation_set(novacell0_database='nova_cell0', | |
novacell0_username=config('database-user'), | |
novacell0_hostname=host, | |
relation_id=relation_id) | |
+ #if cmp_os_release >= 'ocata': | |
+# cell_db_name = get_cell_db_name() | |
+# cell_name = get_cell_name() | |
+# # NOTE: ocata requires cells v2 | |
+# cell_db = { | |
+# 'nova{}_database'.format(cell_name): get_cell_db_name(), | |
+# 'nova{}_username'.format(cell_name): config('database-user'), | |
+# 'nova{}_hostname'.format(cell_name): host} | |
+# relation_set(relation_id, **cell_db) | |
+# #relation_set(novacell0_database='nova_cell0', | |
+# # novacell0_username=config('database-user'), | |
+# # novacell0_hostname=host, | |
+# # relation_id=relation_id) | |
+ | |
@hooks.hook('shared-db-relation-changed') | |
@service_guard(guard_map(), CONFIGS, | |
@@ -445,6 +524,9 @@ 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() | |
+ 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('image-service-relation-changed') | |
@@ -966,23 +1048,58 @@ def upgrade_charm(): | |
update_nova_consoleauth_config() | |
-# remote_restart is defaulted to true as nova-cells may have started the | |
-# nova-cell process before the db migration was run so it will need a | |
-# kick | |
-@hooks.hook('cell-relation-joined') | |
-def nova_cell_relation_joined(rid=None, remote_restart=True): | |
+@hooks.hook('nova-cell-relation-joined') | |
+def cell_relation_joined(rid=None): | |
+ db_rids = relation_ids('shared-db') | |
+ amqp_rids = relation_ids('amqp') | |
+ if not db_rids or not amqp_rids: | |
+ log("db and/or amqp relations not ready") | |
+ return | |
+ | |
+ db_svc_names = [u.split('/')[0] for u in related_units(db_rids[0])] | |
+ amqp_svc_names = [u.split('/')[0] for u in related_units(amqp_rids[0])] | |
+ if not db_svc_names or not amqp_svc_names: | |
+ log("db and/or amqp relations not ready") | |
+ return | |
+ | |
+ assert len(set(db_svc_names)) == 1, "Too many relations!" | |
+ | |
+ assert len(set(amqp_svc_names)) == 1, "Too many relations!" | |
+ | |
rel_settings = { | |
- 'nova_url': "%s:8774/v2" % canonical_url(CONFIGS, INTERNAL) | |
- } | |
- if remote_restart: | |
- rel_settings['restart_trigger'] = str(uuid.uuid4()) | |
+ 'amqp-service': amqp_svc_names[0], | |
+ 'db-service': db_svc_names[0], | |
+ 'cell-name': config('cell-name')} | |
relation_set(relation_id=rid, **rel_settings) | |
-@hooks.hook('cell-relation-changed') | |
-@restart_on_change(restart_map()) | |
-def nova_cell_relation_changed(): | |
- CONFIGS.write(NOVA_CONF) | |
+@hooks.hook('nova-cell-api-relation-changed') | |
+def nova_cell_api_relation_changed(rid=None, unit=None): | |
+ data = relation_get(rid=rid, unit=unit) | |
+ if not data.get('cell-name'): | |
+ return | |
+ register_cell( | |
+ name=data['cell-name'], | |
+ db_service=data['db-service'], | |
+ amqp_service=data['amqp-service']) | |
+ | |
+# remote_restart is defaulted to true as nova-cells may have started the | |
+# nova-cell process before the db migration was run so it will need a | |
+# kick | |
+@hooks.hook('cell-relation-joined') | |
+#def nova_cell_relation_joined(rid=None, remote_restart=True): | |
+# rel_settings = { | |
+# 'nova_url': "%s:8774/v2" % canonical_url(CONFIGS, INTERNAL) | |
+# } | |
+# if remote_restart: | |
+# rel_settings['restart_trigger'] = str(uuid.uuid4()) | |
+# relation_set(relation_id=rid, **rel_settings) | |
+# | |
+# | |
+#@hooks.hook('cell-relation-changed') | |
+#@restart_on_change(restart_map()) | |
+#def nova_cell_relation_changed(): | |
+# CONFIGS.write(NOVA_CONF) | |
def get_cell_type(): | |
diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py | |
index 9cee2a5..ede87f8 100644 | |
--- a/hooks/nova_cc_utils.py | |
+++ b/hooks/nova_cc_utils.py | |
@@ -77,6 +77,7 @@ from charmhelpers.core.hookenv import ( | |
is_leader, | |
log, | |
relation_get, | |
+ relation_id, | |
relation_ids, | |
remote_unit, | |
DEBUG, | |
@@ -322,6 +323,35 @@ SERIAL_CONSOLE = { | |
'services': ['nova-serialproxy', 'nova-consoleauth'], | |
} | |
+def register_cell(name, db_service, amqp_service): | |
+ # XXX try/except to catch subprocess error due to shared-sb and/or amqp contexts for api db not ready. | |
+ # catching CalledProcessError is too generic, need to examine contexts instead? | |
+ try: | |
+ if get_cell_uuid(name, fatal=False): | |
+ return | |
+ except subprocess.CalledProcessError: | |
+ return | |
+ amq_rid = relation_id(relation_name='amqp-cell', service_or_unit=amqp_service) | |
+ db_rid = relation_id(relation_name='shared-db-cell', service_or_unit=db_service) | |
+ amqp_ctxt = context.AMQPContext(ssl_dir=NOVA_CONF_DIR, relation_id=amq_rid)() | |
+ db_ctxt = context.SharedDBContext(relation_prefix='nova', ssl_dir=NOVA_CONF_DIR, relation_id=db_rid)() | |
+ if not amqp_ctxt or not db_ctxt: | |
+ return | |
+ cmd = ['nova-manage', 'cell_v2', 'create_cell', '--name', name, '--verbose'] | |
+ | |
+ cmd.extend(['--transport-url', amqp_ctxt['transport_url']]) | |
+ | |
+ sql_connection = "{database_type}://{database_user}:{database_password}@{database_host}/{database}".format(**db_ctxt) | |
+ if db_ctxt.get('database_ssl_ca'): | |
+ sql_connection = sql_connection + '?ssl_ca={{database_ssl_ca}}'.format(**db_ctxt) | |
+ if db_ctxt.get('database_ssl_cert'): | |
+ sql_connection = sql_connection + '&ssl_cert={database_ssl_cert}&ssl_key={database_ssl_key}'.format(**db_ctxt) | |
+ cmd.extend(['--database_connection', sql_connection]) | |
+ try: | |
+ subprocess.check_output(cmd) | |
+ except subprocess.CalledProcessError as e: | |
+ log('Register cell failed\n{}'.format(e.output), level=ERROR) | |
+ raise | |
def resource_map(actual_services=True): | |
''' | |
@@ -597,6 +627,25 @@ def is_db_initialised(): | |
return False | |
+def get_cell_name(): | |
+ return config('cell-name') or 'cell0' | |
+ | |
+def get_cell_db_name(): | |
+ return 'nova_cell' | |
+ | |
+def is_api_cell(): | |
+ if not config('cell-name') or config('cell-name') == 'cell0': | |
+ return True | |
+ else: | |
+ return False | |
+ | |
+def is_cellv2_child_cell_init_ready(): | |
+ shared_db = context.SharedDBContext(relation_prefix='nova', ssl_dir=NOVA_CONF_DIR) | |
+ if (CompareOpenStackReleases(os_release('nova-common')) >= 'ocata' and | |
+ shared_db()): | |
+ return True | |
+ return False | |
+ | |
def is_cellv2_init_ready(): | |
"""Determine if we're ready to initialize the cell v2 databases | |
@@ -786,7 +835,7 @@ 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 | |
@@ -798,10 +847,13 @@ def get_cell_uuid(cell): | |
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)) | |
+ _cell_uuid = out.split(cell, 1) | |
+ if len(_cell_uuid) < 2: | |
+ if fatal: | |
+ raise Exception("Cannot find cell, '{}', in list_cells." | |
+ "".format(cell)) | |
+ return None | |
+ cell_uuid = _cell_uuid[1].split()[1] | |
return cell_uuid | |
@@ -876,7 +928,7 @@ def migrate_nova_databases(): | |
online_data_migrations_if_needed() | |
finalize_migrate_nova_databases() | |
- elif is_cellv2_init_ready(): | |
+ elif is_api_cell() and is_cellv2_init_ready(): | |
migrate_nova_api_database() | |
initialize_cell_databases() | |
migrate_nova_database() | |
@@ -884,6 +936,11 @@ def migrate_nova_databases(): | |
add_hosts_to_cell() | |
map_instances() | |
finalize_migrate_nova_databases() | |
+ elif is_cellv2_child_cell_init_ready() and not is_api_cell(): | |
+ migrate_nova_database() | |
+ online_data_migrations_if_needed() | |
+ #add_hosts_to_cell() | |
+ finalize_migrate_nova_databases() | |
# TODO: refactor to use unit storage or related data | |
diff --git a/hooks/shared-db-cell-relation-broken b/hooks/shared-db-cell-relation-broken | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/shared-db-cell-relation-broken | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/shared-db-cell-relation-changed b/hooks/shared-db-cell-relation-changed | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/shared-db-cell-relation-changed | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/shared-db-cell-relation-joined b/hooks/shared-db-cell-relation-joined | |
new file mode 120000 | |
index 0000000..f670241 | |
--- /dev/null | |
+++ b/hooks/shared-db-cell-relation-joined | |
@@ -0,0 +1 @@ | |
+nova_cc_hooks.py | |
\ No newline at end of file | |
diff --git a/metadata.yaml b/metadata.yaml | |
index ab6b2ea..46bd6f9 100644 | |
--- a/metadata.yaml | |
+++ b/metadata.yaml | |
@@ -30,9 +30,17 @@ provides: | |
scope: container | |
cloud-controller: | |
interface: nova | |
+ nova-cell-api: | |
+ interface: cell | |
requires: | |
+ shared-db-cell: | |
+ interface: mysql-shared | |
+ amqp-cell: | |
+ interface: rabbitmq | |
shared-db: | |
interface: mysql-shared | |
+# shared-db-api: | |
+# interface: mysql-shared | |
amqp: | |
interface: rabbitmq | |
image-service: | |
@@ -57,6 +65,8 @@ requires: | |
scope: container | |
memcache: | |
interface: memcache | |
+ nova-cell: | |
+ interface: cell | |
peers: | |
cluster: | |
interface: nova-ha | |
diff --git a/templates/ocata/nova.conf b/templates/ocata/nova.conf | |
index 92019dc..7cbcae8 100644 | |
--- a/templates/ocata/nova.conf | |
+++ b/templates/ocata/nova.conf | |
@@ -119,7 +119,9 @@ volume_api_class=nova.volume.cinder.API | |
{% include "parts/database-v2" %} | |
+{% if enable_api_db %} | |
{% include "parts/database-api" %} | |
+{% endif %} | |
{% if glance_api_servers -%} | |
[glance] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py | |
index 70850c1..161be12 100644 | |
--- a/hooks/charmhelpers/contrib/openstack/context.py | |
+++ b/hooks/charmhelpers/contrib/openstack/context.py | |
@@ -97,8 +97,6 @@ from charmhelpers.contrib.network.ip import ( | |
from charmhelpers.contrib.openstack.utils import ( | |
config_flags_parser, | |
get_host_ip, | |
- git_determine_usr_bin, | |
- git_determine_python_path, | |
enable_memcache, | |
snap_install_requested, | |
CompareOpenStackReleases, | |
@@ -334,10 +332,7 @@ class IdentityServiceContext(OSContextGenerator): | |
self.rel_name = rel_name | |
self.interfaces = [self.rel_name] | |
- def __call__(self): | |
- log('Generating template context for ' + self.rel_name, level=DEBUG) | |
- ctxt = {} | |
- | |
+ def _setup_pki_cache(self): | |
if self.service and self.service_user: | |
# This is required for pki token signing if we don't want /tmp to | |
# be used. | |
@@ -347,6 +342,15 @@ class IdentityServiceContext(OSContextGenerator): | |
mkdir(path=cachedir, owner=self.service_user, | |
group=self.service_user, perms=0o700) | |
+ return cachedir | |
+ return None | |
+ | |
+ def __call__(self): | |
+ log('Generating template context for ' + self.rel_name, level=DEBUG) | |
+ ctxt = {} | |
+ | |
+ cachedir = self._setup_pki_cache() | |
+ if cachedir: | |
ctxt['signing_dir'] = cachedir | |
for rid in relation_ids(self.rel_name): | |
@@ -385,6 +389,62 @@ class IdentityServiceContext(OSContextGenerator): | |
return {} | |
+class IdentityCredentialsContext(IdentityServiceContext): | |
+ '''Context for identity-credentials interface type''' | |
+ | |
+ def __init__(self, | |
+ service=None, | |
+ service_user=None, | |
+ rel_name='identity-credentials'): | |
+ super(IdentityCredentialsContext, self).__init__(service, | |
+ service_user, | |
+ rel_name) | |
+ | |
+ def __call__(self): | |
+ log('Generating template context for ' + self.rel_name, level=DEBUG) | |
+ ctxt = {} | |
+ | |
+ cachedir = self._setup_pki_cache() | |
+ if cachedir: | |
+ ctxt['signing_dir'] = cachedir | |
+ | |
+ for rid in relation_ids(self.rel_name): | |
+ self.related = True | |
+ for unit in related_units(rid): | |
+ rdata = relation_get(rid=rid, unit=unit) | |
+ credentials_host = rdata.get('credentials_host') | |
+ credentials_host = ( | |
+ format_ipv6_addr(credentials_host) or credentials_host | |
+ ) | |
+ auth_host = rdata.get('auth_host') | |
+ auth_host = format_ipv6_addr(auth_host) or auth_host | |
+ svc_protocol = rdata.get('credentials_protocol') or 'http' | |
+ auth_protocol = rdata.get('auth_protocol') or 'http' | |
+ api_version = rdata.get('api_version') or '2.0' | |
+ ctxt.update({ | |
+ 'service_port': rdata.get('credentials_port'), | |
+ 'service_host': credentials_host, | |
+ 'auth_host': auth_host, | |
+ 'auth_port': rdata.get('auth_port'), | |
+ 'admin_tenant_name': rdata.get('credentials_project'), | |
+ 'admin_tenant_id': rdata.get('credentials_project_id'), | |
+ 'admin_user': rdata.get('credentials_username'), | |
+ 'admin_password': rdata.get('credentials_password'), | |
+ 'service_protocol': svc_protocol, | |
+ 'auth_protocol': auth_protocol, | |
+ 'api_version': api_version | |
+ }) | |
+ | |
+ if float(api_version) > 2: | |
+ ctxt.update({'admin_domain_name': | |
+ rdata.get('domain')}) | |
+ | |
+ if self.context_complete(ctxt): | |
+ return ctxt | |
+ | |
+ return {} | |
+ | |
+ | |
class AMQPContext(OSContextGenerator): | |
def __init__(self, ssl_dir=None, rel_name='amqp', relation_prefix=None): | |
@@ -1323,8 +1383,6 @@ class WSGIWorkerConfigContext(WorkerConfigContext): | |
"public_processes": int(math.ceil(self.public_process_weight * | |
total_processes)), | |
"threads": 1, | |
- "usr_bin": git_determine_usr_bin(), | |
- "python_path": git_determine_python_path(), | |
} | |
return ctxt | |
diff --git a/hooks/cloud-credentials-relation-changed b/hooks/cloud-credentials-relation-changed | |
new file mode 120000 | |
index 0000000..3ba0bde | |
--- /dev/null | |
+++ b/hooks/cloud-credentials-relation-changed | |
@@ -0,0 +1 @@ | |
+nova_compute_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/cloud-credentials-relation-joined b/hooks/cloud-credentials-relation-joined | |
new file mode 120000 | |
index 0000000..3ba0bde | |
--- /dev/null | |
+++ b/hooks/cloud-credentials-relation-joined | |
@@ -0,0 +1 @@ | |
+nova_compute_hooks.py | |
\ No newline at end of file | |
diff --git a/hooks/nova_compute_context.py b/hooks/nova_compute_context.py | |
index 05b2cfd..6a99a44 100644 | |
--- a/hooks/nova_compute_context.py | |
+++ b/hooks/nova_compute_context.py | |
@@ -462,6 +462,28 @@ class CloudComputeContext(context.OSContextGenerator): | |
return neutron_ctxt | |
+ def neutron_context_mini(self): | |
+ # generate config context for neutron or quantum. these get converted | |
+ # directly into flags in nova.conf | |
+ # NOTE: Its up to release templates to set correct driver | |
+ neutron_ctxt = {'neutron_url': None} | |
+ for rid in relation_ids('cloud-compute'): | |
+ for unit in related_units(rid): | |
+ rel = {'rid': rid, 'unit': unit} | |
+ | |
+ url = _neutron_url(**rel) | |
+ if not url: | |
+ # only bother with units that have a neutron url set. | |
+ continue | |
+ | |
+ neutron_ctxt = { | |
+ 'neutron_auth_strategy': 'keystone', | |
+ 'neutron_plugin': _neutron_plugin(), | |
+ 'neutron_url': url, | |
+ } | |
+ | |
+ return neutron_ctxt | |
+ | |
def volume_context(self): | |
# provide basic validation that the volume manager is supported on the | |
# given openstack release (nova-volume is only supported for E and F) | |
@@ -485,7 +507,8 @@ class CloudComputeContext(context.OSContextGenerator): | |
ctxt = self.flat_dhcp_context() | |
elif self.network_manager == 'neutron': | |
ctxt = self.neutron_context() | |
- | |
+ if not ctxt: | |
+ ctxt = self.neutron_context_mini() | |
_save_flag_file(path='/etc/nova/nm.conf', data=self.network_manager) | |
log('Generated config context for %s network manager.' % | |
@@ -542,6 +565,31 @@ class CloudComputeContext(context.OSContextGenerator): | |
return ctxt | |
+#class CloudCellComputeContext(CloudComputeContext): | |
+# | |
+# def neutron_context_mini(self): | |
+# # generate config context for neutron or quantum. these get converted | |
+# # directly into flags in nova.conf | |
+# # NOTE: Its up to release templates to set correct driver | |
+# neutron_ctxt = {'neutron_url': None} | |
+# for rid in relation_ids('cloud-compute'): | |
+# for unit in related_units(rid): | |
+# rel = {'rid': rid, 'unit': unit} | |
+# | |
+# url = _neutron_url(**rel) | |
+# if not url: | |
+# # only bother with units that have a neutron url set. | |
+# continue | |
+# | |
+# neutron_ctxt = { | |
+# 'neutron_auth_strategy': 'keystone', | |
+# 'neutron_plugin': _neutron_plugin(), | |
+# 'neutron_url': url, | |
+# } | |
+# | |
+# return neutron_ctxt | |
+ | |
+ | |
class InstanceConsoleContext(context.OSContextGenerator): | |
interfaces = [] | |
diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py | |
index 25a8896..9fc27ea 100755 | |
--- a/hooks/nova_compute_hooks.py | |
+++ b/hooks/nova_compute_hooks.py | |
@@ -27,6 +27,7 @@ from charmhelpers.core.hookenv import ( | |
Hooks, | |
config, | |
is_relation_made, | |
+ local_unit, | |
log, | |
relation_ids, | |
remote_service_name, | |
@@ -487,6 +488,16 @@ def lxd_joined(relid=None): | |
user='nova') | |
+@hooks.hook('cloud-credentials-relation-joined') | |
+def cloud_credentials_joined(): | |
+ svc_name = local_unit().split('/')[0].replace('-', '_') | |
+ relation_set(username=svc_name) | |
+ | |
+@hooks.hook('cloud-credentials-relation-changed') | |
+@restart_on_change(restart_map()) | |
+def cloud_credentials_changed(): | |
+ CONFIGS.write(NOVA_CONF) | |
+ | |
@hooks.hook('lxd-relation-changed') | |
@restart_on_change(restart_map()) | |
def lxc_changed(): | |
diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py | |
index fcccb50..cd706df 100644 | |
--- a/hooks/nova_compute_utils.py | |
+++ b/hooks/nova_compute_utils.py | |
@@ -230,7 +230,8 @@ BASE_RESOURCE_MAP = { | |
context.InternalEndpointContext('nova-common'), | |
SerialConsoleContext(), | |
NovaComputeAvailabilityZoneContext(), | |
- context.WorkerConfigContext()], | |
+ context.WorkerConfigContext(), | |
+ context.IdentityCredentialsContext(rel_name='cloud-credentials')] | |
}, | |
NOVA_API_AA_PROFILE_PATH: { | |
'services': ['nova-api'], | |
diff --git a/metadata.yaml b/metadata.yaml | |
index 93a2b3e..33b6bba 100644 | |
--- a/metadata.yaml | |
+++ b/metadata.yaml | |
@@ -48,6 +48,8 @@ requires: | |
scope: container | |
ceph-access: | |
interface: cinder-ceph-key | |
+ cloud-credentials: | |
+ interface: keystone-credentials | |
peers: | |
compute-peer: | |
interface: nova | |
diff --git a/templates/ocata/nova.conf b/templates/ocata/nova.conf | |
index 044fd82..62bb7f3 100644 | |
--- a/templates/ocata/nova.conf | |
+++ b/templates/ocata/nova.conf | |
@@ -142,7 +142,7 @@ resume_guests_state_on_host_boot = {{ resume_guests_state_on_host_boot }} | |
{% if network_manager == 'neutron' and network_manager_config -%} | |
[neutron] | |
url = {{ network_manager_config.neutron_url }} | |
-{% if network_manager_config.keystone_host -%} | |
+{% if network_manager_config.keystone_host or auth_host -%} | |
{% if neutron_plugin and neutron_plugin == 'vsp' -%} | |
ovs_bridge = alubr0 | |
{% endif -%} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment