Skip to content

Instantly share code, notes, and snippets.

@gnuoy
Last active January 12, 2018 12:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnuoy/aff86d0ad616a890ba731a3cb7deef51 to your computer and use it in GitHub Desktop.
Save gnuoy/aff86d0ad616a890ba731a3cb7deef51 to your computer and use it in GitHub Desktop.
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]
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