Add nova-metadata service
Add a service for handling nova metadata api services. This was previously handled by the neutron-gateway and still is for deployemnts up to and including Pike, For the neutron metadata service and the nova service to communicate they need a shared secret. To achieve this, the change includes: * A charmhelper sync to get support for multiple wsgi vhosts * Rendering new wsgi vhost and corresponding haproxy config. * Setting a shared-secret down the relation with the neutron gateway. * Remove fragile keystone authtoken checks as they are failing after a ch sync and any issues will be caught by the instance launch functional test. Change-Id: I5ad15ba782cb87b6fdb3c0941a6482d201670bff
This commit is contained in:
parent
d3a843ea4c
commit
e20db83c7d
18
config.yaml
18
config.yaml
|
@ -431,3 +431,21 @@ options:
|
|||
description: |
|
||||
A comma-separated list of nagios servicegroups. If left empty, the
|
||||
nagios_context will be used as the servicegroup.
|
||||
vendor-data:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
A JSON-formatted string that will serve as vendor metadata
|
||||
(via "StaticJSON" provider) to all VM's within an OpenStack deployment,
|
||||
regardless of project or domain. For deployments prior to Queens this
|
||||
value should be set in the neutron-gateway charm.
|
||||
vendor-data-url:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
A URL serving JSON-formatted data that will serve as vendor metadata
|
||||
(via "DynamicJSON" provider) to all VM's within an OpenStack deployment,
|
||||
regardless of project or domain.
|
||||
.
|
||||
Only supported in OpenStack Newton and higher. For deployments prior to
|
||||
Queens this value should be set in the neutron-gateway charm.
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{% if auth_host -%}
|
||||
[keystone_authtoken]
|
||||
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
auth_type = password
|
||||
{% if api_version == "3" -%}
|
||||
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v3
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v3
|
||||
project_domain_name = {{ admin_domain_name }}
|
||||
user_domain_name = {{ admin_domain_name }}
|
||||
{% else -%}
|
||||
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
project_domain_name = default
|
||||
user_domain_name = default
|
||||
{% endif -%}
|
||||
|
|
|
@ -19,6 +19,7 @@ from charmhelpers.core.hookenv import (
|
|||
config,
|
||||
relation_ids,
|
||||
relation_set,
|
||||
leader_get,
|
||||
log,
|
||||
DEBUG,
|
||||
related_units,
|
||||
|
@ -44,6 +45,10 @@ from charmhelpers.contrib.openstack.ip import (
|
|||
INTERNAL,
|
||||
PUBLIC,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
os_release,
|
||||
CompareOpenStackReleases,
|
||||
)
|
||||
|
||||
|
||||
def context_complete(ctxt):
|
||||
|
@ -159,6 +164,8 @@ class HAProxyContext(context.HAProxyContext):
|
|||
singlenode_mode=True)
|
||||
placement_api = determine_api_port(api_port('nova-placement-api'),
|
||||
singlenode_mode=True)
|
||||
metadata_api = determine_api_port(api_port('nova-api-metadata'),
|
||||
singlenode_mode=True)
|
||||
# Apache ports
|
||||
a_compute_api = determine_apache_port(api_port('nova-api-os-compute'),
|
||||
singlenode_mode=True)
|
||||
|
@ -168,12 +175,15 @@ class HAProxyContext(context.HAProxyContext):
|
|||
singlenode_mode=True)
|
||||
a_placement_api = determine_apache_port(api_port('nova-placement-api'),
|
||||
singlenode_mode=True)
|
||||
a_metadata_api = determine_apache_port(api_port('nova-api-metadata'),
|
||||
singlenode_mode=True)
|
||||
# to be set in nova.conf accordingly.
|
||||
listen_ports = {
|
||||
'osapi_compute_listen_port': compute_api,
|
||||
'ec2_listen_port': ec2_api,
|
||||
's3_listen_port': s3_api,
|
||||
'placement_listen_port': placement_api,
|
||||
'metadata_listen_port': metadata_api,
|
||||
}
|
||||
|
||||
port_mapping = {
|
||||
|
@ -185,6 +195,8 @@ class HAProxyContext(context.HAProxyContext):
|
|||
api_port('nova-objectstore'), a_s3_api],
|
||||
'nova-placement-api': [
|
||||
api_port('nova-placement-api'), a_placement_api],
|
||||
'nova-api-metadata': [
|
||||
api_port('nova-api-metadata'), a_metadata_api],
|
||||
}
|
||||
|
||||
# for haproxy.conf
|
||||
|
@ -195,6 +207,15 @@ class HAProxyContext(context.HAProxyContext):
|
|||
return ctxt
|
||||
|
||||
|
||||
class MetaDataHAProxyContext(HAProxyContext):
|
||||
"""Context for the nova metadata service."""
|
||||
|
||||
def __call__(self):
|
||||
ctxt = super(MetaDataHAProxyContext, self).__call__()
|
||||
ctxt['port'] = ctxt['listen_ports']['metadata_listen_port']
|
||||
return ctxt
|
||||
|
||||
|
||||
def canonical_url():
|
||||
"""Returns the correct HTTP URL to this host given the state of HTTPS
|
||||
configuration and hacluster.
|
||||
|
@ -395,3 +416,31 @@ class NovaAPISharedDBContext(context.SharedDBContext):
|
|||
prefix = 'nova_api_{}'
|
||||
ctxt = {prefix.format(k): v for k, v in ctxt.items()}
|
||||
return ctxt
|
||||
|
||||
|
||||
class NovaMetadataContext(context.OSContextGenerator):
|
||||
'''
|
||||
Context used for configuring the nova metadata service.
|
||||
'''
|
||||
def __call__(self):
|
||||
cmp_os_release = CompareOpenStackReleases(os_release('nova-common'))
|
||||
ctxt = {}
|
||||
if cmp_os_release >= 'rocky':
|
||||
ctxt['vendordata_providers'] = []
|
||||
vdata = config('vendor-data')
|
||||
vdata_url = config('vendor-data-url')
|
||||
|
||||
if vdata:
|
||||
ctxt['vendor_data'] = True
|
||||
ctxt['vendordata_providers'].append('StaticJSON')
|
||||
|
||||
if vdata_url:
|
||||
ctxt['vendor_data_url'] = vdata_url
|
||||
ctxt['vendordata_providers'].append('DynamicJSON')
|
||||
ctxt['metadata_proxy_shared_secret'] = leader_get(
|
||||
'shared-metadata-secret')
|
||||
ctxt['enable_metadata'] = True
|
||||
else:
|
||||
ctxt['enable_metadata'] = False
|
||||
|
||||
return ctxt
|
||||
|
|
|
@ -91,6 +91,8 @@ from nova_cc_utils import (
|
|||
determine_ports,
|
||||
disable_package_apache_site,
|
||||
do_openstack_upgrade,
|
||||
get_metadata_settings,
|
||||
get_shared_metadatasecret,
|
||||
is_api_ready,
|
||||
is_cellv2_init_ready,
|
||||
keystone_ca_cert_b64,
|
||||
|
@ -98,6 +100,7 @@ from nova_cc_utils import (
|
|||
placement_api_enabled,
|
||||
save_script_rc,
|
||||
services,
|
||||
set_shared_metadatasecret,
|
||||
ssh_compute_add,
|
||||
ssh_compute_remove,
|
||||
ssh_known_hosts_lines,
|
||||
|
@ -116,6 +119,7 @@ from nova_cc_utils import (
|
|||
serial_console_settings,
|
||||
pause_unit_helper,
|
||||
resume_unit_helper,
|
||||
write_vendordata,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import (
|
||||
|
@ -349,6 +353,11 @@ def config_changed():
|
|||
update_nova_consoleauth_config()
|
||||
update_aws_compat_services()
|
||||
|
||||
if config('vendor-data'):
|
||||
write_vendordata(config('vendor-data'))
|
||||
if is_leader() and not get_shared_metadatasecret():
|
||||
set_shared_metadatasecret()
|
||||
|
||||
|
||||
@hooks.hook('amqp-relation-joined')
|
||||
def amqp_joined(relation_id=None):
|
||||
|
@ -744,6 +753,7 @@ def quantum_joined(rid=None, remote_restart=False):
|
|||
if remote_restart:
|
||||
rel_settings['restart_trigger'] = str(uuid.uuid4())
|
||||
|
||||
rel_settings.update(get_metadata_settings(CONFIGS))
|
||||
relation_set(relation_id=rid, **rel_settings)
|
||||
|
||||
|
||||
|
@ -790,6 +800,10 @@ def cluster_changed():
|
|||
log('Database sync not ready. Would shut down services but '
|
||||
'unit is in paused state, not issuing stop/pause to all '
|
||||
'services')
|
||||
# The shared metadata secret is stored in the leader-db and if its changed
|
||||
# the gateway needs to know.
|
||||
for rid in relation_ids('quantum-network-service'):
|
||||
quantum_joined(rid=rid, remote_restart=False)
|
||||
|
||||
|
||||
@hooks.hook('ha-relation-joined')
|
||||
|
|
|
@ -19,6 +19,9 @@ import ConfigParser
|
|||
from base64 import b64encode
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from urlparse import urlparse
|
||||
from uuid import uuid1
|
||||
import json
|
||||
|
||||
from charmhelpers.contrib.openstack import context, templating
|
||||
|
||||
|
@ -63,12 +66,14 @@ from charmhelpers.core.hookenv import (
|
|||
config,
|
||||
is_leader,
|
||||
log,
|
||||
leader_get,
|
||||
leader_set,
|
||||
relation_get,
|
||||
relation_ids,
|
||||
remote_unit,
|
||||
DEBUG,
|
||||
INFO,
|
||||
ERROR,
|
||||
INFO,
|
||||
status_set,
|
||||
related_units,
|
||||
local_unit,
|
||||
|
@ -93,12 +98,19 @@ from charmhelpers.core.decorators import (
|
|||
retry_on_exception,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.openstack.ip import (
|
||||
canonical_url,
|
||||
INTERNAL,
|
||||
)
|
||||
|
||||
import nova_cc_context
|
||||
|
||||
TEMPLATES = 'templates/'
|
||||
|
||||
CLUSTER_RES = 'grp_nova_vips'
|
||||
|
||||
SHARED_METADATA_SECRET_KEY = 'shared-metadata-secret'
|
||||
|
||||
# The interface is said to be satisfied if anyone of the interfaces in the
|
||||
# list has a complete context.
|
||||
REQUIRED_INTERFACES = {
|
||||
|
@ -119,7 +131,6 @@ BASE_PACKAGES = [
|
|||
'python-psycopg2',
|
||||
'python-psutil',
|
||||
'python-six',
|
||||
'uuid',
|
||||
'python-memcache',
|
||||
]
|
||||
|
||||
|
@ -144,6 +155,7 @@ SERVICE_BLACKLIST = {
|
|||
API_PORTS = {
|
||||
'nova-api-ec2': 8773,
|
||||
'nova-api-os-compute': 8774,
|
||||
'nova-api-metadata': 8775,
|
||||
'nova-api-os-volume': 8776,
|
||||
'nova-placement-api': 8778,
|
||||
'nova-objectstore': 3333,
|
||||
|
@ -162,6 +174,9 @@ WSGI_NOVA_PLACEMENT_API_CONF = \
|
|||
'/etc/apache2/sites-enabled/wsgi-openstack-api.conf'
|
||||
PACKAGE_NOVA_PLACEMENT_API_CONF = \
|
||||
'/etc/apache2/sites-enabled/nova-placement-api.conf'
|
||||
WSGI_NOVA_METADATA_API_CONF = \
|
||||
'/etc/apache2/sites-enabled/wsgi-openstack-metadata.conf'
|
||||
VENDORDATA_FILE = '/etc/nova/vendor_data.json'
|
||||
|
||||
|
||||
def resolve_services():
|
||||
|
@ -208,7 +223,8 @@ BASE_RESOURCE_MAP = OrderedDict([
|
|||
context.VolumeAPIContext('nova-common'),
|
||||
nova_cc_context.NeutronAPIContext(),
|
||||
nova_cc_context.SerialConsoleContext(),
|
||||
context.MemcacheContext()],
|
||||
context.MemcacheContext(),
|
||||
nova_cc_context.NovaMetadataContext()],
|
||||
}),
|
||||
(NOVA_API_PASTE, {
|
||||
'services': [s for s in resolve_services() if 'api' in s],
|
||||
|
@ -337,7 +353,20 @@ def resource_map(actual_services=True):
|
|||
svcs = resource_map[cfile]['services']
|
||||
if 'nova-placement-api' in svcs:
|
||||
svcs.remove('nova-placement-api')
|
||||
|
||||
if enable_metadata_api():
|
||||
if actual_services:
|
||||
svcs = ['apache2']
|
||||
else:
|
||||
svcs = ['nova-api-metadata']
|
||||
resource_map[WSGI_NOVA_METADATA_API_CONF] = {
|
||||
'contexts': [
|
||||
context.WSGIWorkerConfigContext(
|
||||
name="nova_meta",
|
||||
user='nova',
|
||||
group='nova',
|
||||
script='/usr/bin/nova-metadata-wsgi'),
|
||||
nova_cc_context.MetaDataHAProxyContext()],
|
||||
'services': svcs}
|
||||
return resource_map
|
||||
|
||||
|
||||
|
@ -413,13 +442,20 @@ def console_attributes(attr, proto=None):
|
|||
|
||||
def determine_packages():
|
||||
# currently all packages match service names
|
||||
cmp_os_release = CompareOpenStackReleases(os_release('nova-common'))
|
||||
packages = deepcopy(BASE_PACKAGES)
|
||||
for v in resource_map(actual_services=False).values():
|
||||
packages.extend(v['services'])
|
||||
# The nova-api-metadata service is served via wsgi and the package is
|
||||
# only needed for the standalone service so remove it to avoid port
|
||||
# clashes.
|
||||
try:
|
||||
packages.remove("nova-api-metadata")
|
||||
except ValueError:
|
||||
pass
|
||||
if console_attributes('packages'):
|
||||
packages.extend(console_attributes('packages'))
|
||||
if (config('enable-serial-console') and
|
||||
CompareOpenStackReleases(os_release('nova-common')) >= 'juno'):
|
||||
if (config('enable-serial-console') and cmp_os_release >= 'juno'):
|
||||
packages.extend(SERIAL_CONSOLE['packages'])
|
||||
|
||||
packages.extend(token_cache_pkgs(source=config('openstack-origin')))
|
||||
|
@ -1359,9 +1395,52 @@ def placement_api_enabled():
|
|||
return CompareOpenStackReleases(os_release('nova-common')) >= 'ocata'
|
||||
|
||||
|
||||
def enable_metadata_api(release=None):
|
||||
"""Should nova-metadata-api be running on this unit for this release."""
|
||||
if not release:
|
||||
release = os_release('nova-common')
|
||||
return CompareOpenStackReleases(os_release('nova-common')) >= 'rocky'
|
||||
|
||||
|
||||
def disable_package_apache_site():
|
||||
"""Ensure that the package-provided apache configuration is disabled to
|
||||
prevent it from conflicting with the charm-provided version.
|
||||
"""
|
||||
if os.path.exists(PACKAGE_NOVA_PLACEMENT_API_CONF):
|
||||
subprocess.check_call(['a2dissite', 'nova-placement-api'])
|
||||
|
||||
|
||||
def get_shared_metadatasecret():
|
||||
"""Return the shared metadata secret."""
|
||||
return leader_get(SHARED_METADATA_SECRET_KEY)
|
||||
|
||||
|
||||
def set_shared_metadatasecret():
|
||||
"""Store the shared metadata secret."""
|
||||
leader_set({SHARED_METADATA_SECRET_KEY: uuid1()})
|
||||
|
||||
|
||||
def get_metadata_settings(configs):
|
||||
"""Return the settings for accessing the metadata service."""
|
||||
if enable_metadata_api():
|
||||
url = urlparse(canonical_url(configs, INTERNAL))
|
||||
settings = {
|
||||
'nova-metadata-host': url.netloc,
|
||||
'nova-metadata-protocol': url.scheme,
|
||||
'nova-metadata-port': API_PORTS['nova-api-metadata'],
|
||||
'shared-metadata-secret': get_shared_metadatasecret()}
|
||||
else:
|
||||
settings = {}
|
||||
return settings
|
||||
|
||||
|
||||
def write_vendordata(vdata):
|
||||
"""Write supplied vendor data out to a file."""
|
||||
try:
|
||||
json_vdata = json.loads(vdata)
|
||||
except (TypeError, json.decoder.JSONDecodeError) as e:
|
||||
log('Error decoding vendor-data. {}'.format(e), level=ERROR)
|
||||
return False
|
||||
with open(VENDORDATA_FILE, 'w') as vdata_file:
|
||||
vdata_file.write(json.dumps(json_vdata, sort_keys=True, indent=2))
|
||||
return True
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
pbr>=1.8.0,<1.9.0
|
||||
PyYAML>=3.1.0
|
||||
simplejson>=2.2.0
|
||||
netifaces>=0.10.4
|
||||
netaddr>=0.7.12,!=0.7.16
|
||||
|
|
|
@ -112,6 +112,9 @@ quantum_admin_password = {{ admin_password }}
|
|||
quantum_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
|
||||
{% endif -%}
|
||||
{% elif network_manager and network_manager == 'neutron' -%}
|
||||
neutron_metadata_proxy_shared_secret = {{ metadata_proxy_shared_secret }}
|
||||
service_neutron_metadata_proxy = True
|
||||
metadata_workers = {{ workers }}
|
||||
network_api_class = nova.network.neutronv2.api.API
|
||||
neutron_url = {{ neutron_url }}
|
||||
{% if auth_host -%}
|
||||
|
|
|
@ -111,6 +111,11 @@ volume_api_class=nova.volume.cinder.API
|
|||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if vendor_data -%}
|
||||
vendordata_driver = nova.api.metadata.vendordata_json.JsonFileVendorData
|
||||
vendordata_jsonfile_path = /etc/nova/vendor_data.json
|
||||
{% endif -%}
|
||||
|
||||
{% if listen_ports -%}
|
||||
{% for key, value in listen_ports.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
|
@ -134,13 +139,9 @@ volume_api_class=nova.volume.cinder.API
|
|||
api_servers = {{ glance_api_servers }}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' -%}
|
||||
[neutron]
|
||||
url = {{ neutron_url }}
|
||||
auth_strategy = keystone
|
||||
auth_section = keystone_authtoken
|
||||
auth_plugin = password
|
||||
{% endif -%}
|
||||
{% if network_manager and network_manager == 'neutron' %}
|
||||
{% include "parts/section-neutron" %}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-keystone-authtoken-mitaka" %}
|
||||
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
# newton
|
||||
###############################################################################
|
||||
# [ WARNING ]
|
||||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
###############################################################################
|
||||
[DEFAULT]
|
||||
verbose={{ verbose }}
|
||||
debug={{ debug }}
|
||||
dhcpbridge_flagfile=/etc/nova/nova.conf
|
||||
dhcpbridge=/usr/bin/nova-dhcpbridge
|
||||
logdir=/var/log/nova
|
||||
state_path=/var/lib/nova
|
||||
force_dhcp_release=True
|
||||
iscsi_helper=tgtadm
|
||||
libvirt_use_virtio_for_bridges=True
|
||||
connection_type=libvirt
|
||||
root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
volumes_path=/var/lib/nova/volumes
|
||||
enabled_apis=osapi_compute,metadata
|
||||
auth_strategy=keystone
|
||||
compute_driver=libvirt.LibvirtDriver
|
||||
use_ipv6 = {{ use_ipv6 }}
|
||||
osapi_compute_listen = {{ bind_host }}
|
||||
metadata_host = {{ bind_host }}
|
||||
s3_listen = {{ bind_host }}
|
||||
|
||||
osapi_compute_workers = {{ workers }}
|
||||
|
||||
{% if vendor_data -%}
|
||||
vendordata_driver = nova.api.metadata.vendordata_json.JsonFileVendorData
|
||||
vendordata_jsonfile_path = /etc/nova/vendor_data.json
|
||||
{% endif -%}
|
||||
|
||||
{% if additional_neutron_filters is defined %}
|
||||
scheduler_default_filters = {{ scheduler_default_filters }},{{ additional_neutron_filters }}
|
||||
{% else %}
|
||||
scheduler_default_filters = {{ scheduler_default_filters }}
|
||||
{% endif %}
|
||||
{% if pci_alias %}
|
||||
pci_alias = {{ pci_alias }}
|
||||
{% endif %}
|
||||
cpu_allocation_ratio = {{ cpu_allocation_ratio }}
|
||||
ram_allocation_ratio = {{ ram_allocation_ratio }}
|
||||
disk_allocation_ratio = {{ disk_allocation_ratio }}
|
||||
|
||||
use_syslog={{ use_syslog }}
|
||||
my_ip = {{ host_ip }}
|
||||
|
||||
{% include "parts/novnc" %}
|
||||
|
||||
{% if rbd_pool -%}
|
||||
rbd_pool = {{ rbd_pool }}
|
||||
rbd_user = {{ rbd_user }}
|
||||
rbd_secret_uuid = {{ rbd_secret_uuid }}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin in ('ovs', 'midonet') -%}
|
||||
libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver
|
||||
libvirt_user_virtio_for_bridges = True
|
||||
{% if neutron_security_groups -%}
|
||||
security_group_api = {{ network_manager }}
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
{% if external_network -%}
|
||||
default_floating_pool = {{ external_network }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'vsp' -%}
|
||||
neutron_ovs_bridge = alubr0
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'nvp' -%}
|
||||
security_group_api = neutron
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% if external_network -%}
|
||||
default_floating_pool = {{ external_network }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'Calico' -%}
|
||||
security_group_api = neutron
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'plumgrid' -%}
|
||||
security_group_api=neutron
|
||||
firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager_config -%}
|
||||
{% for key, value in network_manager_config.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' -%}
|
||||
network_api_class = nova.network.neutronv2.api.API
|
||||
use_neutron = True
|
||||
{% else -%}
|
||||
network_manager = nova.network.manager.FlatDHCPManager
|
||||
{% endif -%}
|
||||
|
||||
{% if default_floating_pool -%}
|
||||
default_floating_pool = {{ default_floating_pool }}
|
||||
{% endif -%}
|
||||
|
||||
{% if volume_service -%}
|
||||
volume_api_class=nova.volume.cinder.API
|
||||
{% endif -%}
|
||||
|
||||
{% if user_config_flags -%}
|
||||
{% for key, value in user_config_flags.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if listen_ports -%}
|
||||
{% for key, value in listen_ports.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if sections and 'DEFAULT' in sections -%}
|
||||
{% for key, value in sections['DEFAULT'] -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-zeromq" %}
|
||||
|
||||
{% include "parts/database-v2" %}
|
||||
|
||||
{% include "parts/database-api" %}
|
||||
|
||||
{% if glance_api_servers -%}
|
||||
[glance]
|
||||
api_servers = {{ glance_api_servers }}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' %}
|
||||
{% include "parts/section-neutron" %}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-keystone-authtoken-mitaka" %}
|
||||
|
||||
{% include "parts/section-cinder" %}
|
||||
|
||||
[osapi_v3]
|
||||
enabled=True
|
||||
|
||||
{% include "parts/cell" %}
|
||||
|
||||
[conductor]
|
||||
workers = {{ workers }}
|
||||
|
||||
{% include "section-rabbitmq-oslo" %}
|
||||
|
||||
{% include "section-oslo-notifications" %}
|
||||
|
||||
[oslo_concurrency]
|
||||
lock_path=/var/lock/nova
|
||||
|
||||
[spice]
|
||||
{% include "parts/spice" %}
|
||||
|
||||
{% include "parts/section-serial-console" %}
|
||||
|
||||
{% if memcached_servers %}
|
||||
[cache]
|
||||
enabled = true
|
||||
backend = oslo_cache.memcache_pool
|
||||
memcache_servers = {{ memcached_servers }}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-oslo-middleware" %}
|
||||
|
||||
[wsgi]
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
|
|
@ -126,13 +126,9 @@ volume_api_class=nova.volume.cinder.API
|
|||
api_servers = {{ glance_api_servers }}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' -%}
|
||||
[neutron]
|
||||
url = {{ neutron_url }}
|
||||
auth_strategy = keystone
|
||||
auth_section = keystone_authtoken
|
||||
auth_type = password
|
||||
{% endif -%}
|
||||
{% if network_manager and network_manager == 'neutron' %}
|
||||
{% include "parts/section-neutron" %}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-keystone-authtoken-mitaka" %}
|
||||
|
||||
|
@ -183,6 +179,15 @@ enabled_filters = {{ scheduler_default_filters }}
|
|||
|
||||
[api]
|
||||
auth_strategy=keystone
|
||||
{% if vendor_data or vendor_data_url -%}
|
||||
vendordata_providers = {{ vendordata_providers }}
|
||||
{% if vendor_data -%}
|
||||
vendordata_jsonfile_path = /etc/nova/vendor_data.json
|
||||
{% endif -%}
|
||||
{% if vendor_data_url -%}
|
||||
vendordata_dynamic_targets = {{ vendor_data_url }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
[wsgi]
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
[neutron]
|
||||
url = {{ neutron_url }}
|
||||
{% if auth_host -%}
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
auth_type = password
|
||||
{% if api_version == "3" -%}
|
||||
project_domain_name = {{ admin_domain_name }}
|
||||
user_domain_name = {{ admin_domain_name }}
|
||||
{% else -%}
|
||||
project_domain_name = default
|
||||
user_domain_name = default
|
||||
{% endif -%}
|
||||
project_name = {{ admin_tenant_name }}
|
||||
username = {{ admin_user }}
|
||||
password = {{ admin_password }}
|
||||
{% endif -%}
|
||||
# {{ enable_metadata }}
|
||||
{% if enable_metadata -%}
|
||||
service_metadata_proxy = True
|
||||
metadata_proxy_shared_secret = {{ metadata_proxy_shared_secret }}
|
||||
{% endif -%}
|
|
@ -202,6 +202,15 @@ enabled_filters = {{ scheduler_default_filters }}
|
|||
|
||||
[api]
|
||||
auth_strategy=keystone
|
||||
{% if vendor_data or vendor_data_url -%}
|
||||
vendordata_providers = {{ vendordata_providers }}
|
||||
{% if vendor_data -%}
|
||||
vendordata_jsonfile_path = /etc/nova/vendor_data.json
|
||||
{% endif -%}
|
||||
{% if vendor_data_url -%}
|
||||
vendordata_dynamic_targets = {{ vendor_data_url }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
[wsgi]
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
charm-tools>=2.0.0
|
||||
coverage>=3.6
|
||||
mock>=1.2
|
||||
flake8>=2.2.4,<=2.4.1
|
||||
os-testr>=0.4.1
|
||||
charm-tools>=2.0.0
|
||||
requests==2.6.0
|
||||
requests>=2.18.4
|
||||
# BEGIN: Amulet OpenStack Charm Helper Requirements
|
||||
# Liberty client lower constraints
|
||||
amulet>=1.14.3,<2.0
|
||||
|
|
|
@ -660,16 +660,6 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
|||
|
||||
ks_ec2 = "{}/ec2tokens".format(ks_ep)
|
||||
|
||||
ks_ncc_rel = self.keystone_sentry.relation(
|
||||
'identity-service', 'nova-cloud-controller:identity-service')
|
||||
|
||||
ks_uri = "http://{}:{}/".format(ks_ncc_rel['service_host'],
|
||||
ks_ncc_rel['service_port'])
|
||||
|
||||
id_uri = "{}://{}:{}/".format(ks_ncc_rel['auth_protocol'],
|
||||
ks_ncc_rel['service_host'],
|
||||
ks_ncc_rel['auth_port'])
|
||||
|
||||
db_ncc_rel = self.pxc_sentry.relation(
|
||||
'shared-db', 'nova-cloud-controller:shared-db')
|
||||
|
||||
|
@ -706,15 +696,6 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
|||
expected['database'] = {
|
||||
'connection': db_uri
|
||||
}
|
||||
expected['keystone_authtoken'] = {
|
||||
'auth_uri': ks_uri,
|
||||
'auth_host': ks_ncc_rel['service_host'],
|
||||
'auth_port': ks_ncc_rel['auth_port'],
|
||||
'auth_protocol': ks_ncc_rel['auth_protocol'],
|
||||
'admin_tenant_name': ks_ncc_rel['service_tenant'],
|
||||
'admin_user': ks_ncc_rel['service_username'],
|
||||
'admin_password': ks_ncc_rel['service_password'],
|
||||
}
|
||||
expected['DEFAULT'].update({
|
||||
'lock_path': '/var/lock/nova',
|
||||
'libvirt_use_virtio_for_bridges': 'True',
|
||||
|
@ -734,14 +715,6 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
|||
expected['glance'] = {
|
||||
'api_servers': gl_ncc_rel['glance-api-server'],
|
||||
}
|
||||
expected['keystone_authtoken'] = {
|
||||
'identity_uri': id_uri.rstrip('/'),
|
||||
'auth_uri': ks_uri,
|
||||
'admin_tenant_name': ks_ncc_rel['service_tenant'],
|
||||
'admin_user': ks_ncc_rel['service_username'],
|
||||
'admin_password': ks_ncc_rel['service_password'],
|
||||
'signing_dir': '/var/cache/nova',
|
||||
}
|
||||
expected['osapi_v3'] = {
|
||||
'enabled': 'True',
|
||||
}
|
||||
|
@ -761,44 +734,6 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
|||
'lock_path': '/var/lock/nova',
|
||||
}
|
||||
|
||||
if self._get_openstack_release() >= self.xenial_queens:
|
||||
expected['keystone_authtoken'] = {
|
||||
'auth_uri': ks_uri.rstrip('/'),
|
||||
'auth_url': id_uri.rstrip('/'),
|
||||
'auth_type': 'password',
|
||||
'project_domain_name': 'service_domain',
|
||||
'user_domain_name': 'service_domain',
|
||||
'project_name': 'services',
|
||||
'username': ks_ncc_rel['service_username'],
|
||||
'password': ks_ncc_rel['service_password'],
|
||||
'signing_dir': '/var/cache/nova'
|
||||
}
|
||||
elif self._get_openstack_release() >= self.trusty_mitaka:
|
||||
expected['keystone_authtoken'] = {
|
||||
'auth_uri': ks_uri.rstrip('/'),
|
||||
'auth_url': id_uri.rstrip('/'),
|
||||
'auth_type': 'password',
|
||||
'project_domain_name': 'default',
|
||||
'user_domain_name': 'default',
|
||||
'project_name': 'services',
|
||||
'username': ks_ncc_rel['service_username'],
|
||||
'password': ks_ncc_rel['service_password'],
|
||||
'signing_dir': '/var/cache/nova'
|
||||
}
|
||||
elif self._get_openstack_release() >= self.trusty_liberty:
|
||||
# Liberty
|
||||
expected['keystone_authtoken'] = {
|
||||
'auth_uri': ks_uri.rstrip('/'),
|
||||
'auth_url': id_uri.rstrip('/'),
|
||||
'auth_plugin': 'password',
|
||||
'project_domain_id': 'default',
|
||||
'user_domain_id': 'default',
|
||||
'project_name': 'services',
|
||||
'username': 'nova',
|
||||
'password': ks_ncc_rel['service_password'],
|
||||
'signing_dir': '/var/cache/nova',
|
||||
}
|
||||
|
||||
if self._get_openstack_release() < self.trusty_mitaka:
|
||||
expected['DEFAULT'].update({
|
||||
'ec2_private_dns_show_ip': 'True',
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from mock import patch, MagicMock
|
||||
from mock import patch
|
||||
|
||||
os.environ['JUJU_UNIT_NAME'] = 'nova-cloud-controller'
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
|
@ -22,20 +22,11 @@ with patch('charmhelpers.core.hookenv.config') as config:
|
|||
config.return_value = 'nova'
|
||||
import nova_cc_utils as utils # noqa
|
||||
|
||||
_reg = utils.register_configs
|
||||
_map = utils.restart_map
|
||||
|
||||
utils.register_configs = MagicMock()
|
||||
utils.restart_map = MagicMock()
|
||||
|
||||
with patch('nova_cc_utils.guard_map') as gmap:
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
config.return_value = False
|
||||
gmap.return_value = {}
|
||||
import openstack_upgrade
|
||||
|
||||
utils.register_configs = _reg
|
||||
utils.restart_map = _map
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
with patch('nova_cc_utils.restart_map'):
|
||||
config.return_value = 'ovs'
|
||||
with patch('nova_cc_utils.register_configs') as register_configs:
|
||||
import openstack_upgrade
|
||||
|
||||
from test_utils import CharmTestCase
|
||||
|
||||
|
|
|
@ -26,13 +26,15 @@ from charmhelpers.contrib.openstack import utils
|
|||
from test_utils import CharmTestCase
|
||||
|
||||
TO_PATCH = [
|
||||
'relation_ids',
|
||||
'relation_get',
|
||||
'related_units',
|
||||
'config',
|
||||
'log',
|
||||
'relations_for_id',
|
||||
'https',
|
||||
'leader_get',
|
||||
'log',
|
||||
'os_release',
|
||||
'related_units',
|
||||
'relation_get',
|
||||
'relation_ids',
|
||||
'relations_for_id',
|
||||
]
|
||||
|
||||
|
||||
|
@ -392,3 +394,47 @@ class NovaComputeContextTests(CharmTestCase):
|
|||
expected['additional_neutron_filters'] = 'PciPassthroughFilter'
|
||||
ctxt = context.NeutronAPIContext()()
|
||||
self.assertEqual(ctxt, expected)
|
||||
|
||||
def test_vendordata_static(self):
|
||||
_vdata = '{"good": "json"}'
|
||||
self.os_release.return_value = 'rocky'
|
||||
|
||||
self.test_config.set('vendor-data', _vdata)
|
||||
ctxt = context.NovaMetadataContext()()
|
||||
|
||||
self.assertTrue(ctxt['vendor_data'])
|
||||
self.assertEqual(ctxt['vendordata_providers'], ['StaticJSON'])
|
||||
|
||||
def test_vendordata_dynamic(self):
|
||||
_vdata_url = 'http://example.org/vdata'
|
||||
self.os_release.return_value = 'rocky'
|
||||
|
||||
self.test_config.set('vendor-data-url', _vdata_url)
|
||||
ctxt = context.NovaMetadataContext()()
|
||||
|
||||
self.assertEqual(ctxt['vendor_data_url'], _vdata_url)
|
||||
self.assertEqual(ctxt['vendordata_providers'], ['DynamicJSON'])
|
||||
|
||||
def test_vendordata_static_and_dynamic(self):
|
||||
self.os_release.return_value = 'rocky'
|
||||
_vdata = '{"good": "json"}'
|
||||
_vdata_url = 'http://example.org/vdata'
|
||||
|
||||
self.test_config.set('vendor-data', _vdata)
|
||||
self.test_config.set('vendor-data-url', _vdata_url)
|
||||
ctxt = context.NovaMetadataContext()()
|
||||
|
||||
self.assertTrue(ctxt['vendor_data'])
|
||||
self.assertEqual(ctxt['vendor_data_url'], _vdata_url)
|
||||
self.assertEqual(ctxt['vendordata_providers'], ['StaticJSON',
|
||||
'DynamicJSON'])
|
||||
|
||||
def test_vendordata_mitaka(self):
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.leader_get.return_value = 'auuid'
|
||||
_vdata_url = 'http://example.org/vdata'
|
||||
|
||||
self.test_config.set('vendor-data-url', _vdata_url)
|
||||
ctxt = context.NovaMetadataContext()()
|
||||
|
||||
self.assertEqual(ctxt, {'enable_metadata': False})
|
||||
|
|
|
@ -137,6 +137,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
self.assertTrue(self.execd_preinstall.called)
|
||||
self.assertTrue(self.service_pause.called)
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'is_leader')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -150,7 +153,11 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_determine_packages,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_config,
|
||||
mock_update_aws_compat_services):
|
||||
mock_update_aws_compat_services,
|
||||
mock_is_leader,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
self.get_shared_metadatasecret = None
|
||||
mock_determine_packages.return_value = []
|
||||
utils_config.side_effect = self.test_config.get
|
||||
self.test_config.set('console-access-protocol', 'dummy')
|
||||
|
@ -163,6 +170,41 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
self.assertTrue(mock_update_nova_consoleauth_config.called)
|
||||
self.assertTrue(mock_update_aws_compat_services.called)
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(hooks, 'determine_packages')
|
||||
@patch.object(utils, 'service_resume')
|
||||
@patch.object(utils, 'config')
|
||||
@patch.object(hooks, 'filter_installed_packages')
|
||||
@patch.object(hooks, 'configure_https')
|
||||
def test_config_changed_ocata(self, conf_https, mock_filter_packages,
|
||||
utils_config, mock_service_resume,
|
||||
mock_determine_packages,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_config,
|
||||
mock_update_aws_compat_services,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
mock_get_shared_metadatasecret.return_value = None
|
||||
self.is_leader.return_value = True
|
||||
mock_determine_packages.return_value = []
|
||||
utils_config.side_effect = self.test_config.get
|
||||
self.test_config.set('console-access-protocol', 'dummy')
|
||||
self.openstack_upgrade_available.return_value = False
|
||||
mock_is_db_initialised.return_value = False
|
||||
self.os_release.return_value = 'diablo'
|
||||
hooks.config_changed()
|
||||
self.assertTrue(self.save_script_rc.called)
|
||||
mock_filter_packages.assert_called_with([])
|
||||
self.assertTrue(mock_update_nova_consoleauth_config.called)
|
||||
self.assertTrue(mock_update_aws_compat_services.called)
|
||||
mock_set_shared_metadatasecret.assert_called_once_with()
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -177,7 +219,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_determine_packages,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_cfg,
|
||||
mock_update_aws_compat_services):
|
||||
mock_update_aws_compat_services,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
mock_determine_packages.return_value = []
|
||||
utils_config.side_effect = self.test_config.get
|
||||
self.test_config.set('console-access-protocol', 'dummy')
|
||||
|
@ -191,6 +235,8 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
self.assertTrue(mock_update_aws_compat_services.called)
|
||||
self.service_pause.assert_called_with('neutron-server')
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -205,7 +251,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_determine_packages,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_cfg,
|
||||
mock_update_aws_compat_services):
|
||||
mock_update_aws_compat_services,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
mock_determine_packages.return_value = []
|
||||
utils_config.side_effect = self.test_config.get
|
||||
self.test_config.set('console-access-protocol', 'dummy')
|
||||
|
@ -220,6 +268,8 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
self.assertTrue(mock_update_aws_compat_services.called)
|
||||
self.service_pause.assert_called_with('neutron-server')
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -247,7 +297,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_quantum_joined,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_config,
|
||||
mock_update_aws_compat_services):
|
||||
mock_update_aws_compat_services,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
mock_determine_packages.return_value = []
|
||||
mock_is_db_initialised.return_value = False
|
||||
self.openstack_upgrade_available.return_value = True
|
||||
|
@ -269,6 +321,8 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
self.assertTrue(mock_update_nova_consoleauth_config.called)
|
||||
self.assertTrue(mock_update_aws_compat_services.called)
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'update_nova_consoleauth_config')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -282,7 +336,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_service_resume,
|
||||
mock_is_db_initialised,
|
||||
mock_update_nova_consoleauth_config,
|
||||
mock_update_aws_compat_services):
|
||||
mock_update_aws_compat_services,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
self.openstack_upgrade_available.return_value = False
|
||||
self.config_value_changed.return_value = True
|
||||
self.related_units.return_value = ['unit/0']
|
||||
|
@ -1007,6 +1063,8 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
call(**args),
|
||||
])
|
||||
|
||||
@patch.object(hooks, 'set_shared_metadatasecret')
|
||||
@patch.object(hooks, 'get_shared_metadatasecret')
|
||||
@patch.object(hooks, 'update_aws_compat_services')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(hooks, 'determine_packages')
|
||||
|
@ -1020,7 +1078,9 @@ class NovaCCHooksTests(CharmTestCase):
|
|||
mock_service_pause,
|
||||
mock_determine_packages,
|
||||
mock_is_db_initialised,
|
||||
mock_update_aws_compat_svcs):
|
||||
mock_update_aws_compat_svcs,
|
||||
mock_get_shared_metadatasecret,
|
||||
mock_set_shared_metadatasecret):
|
||||
mock_determine_packages.return_value = []
|
||||
mock_is_db_initialised.return_value = False
|
||||
self.config_value_changed.return_value = False
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
from collections import OrderedDict
|
||||
from mock import patch, MagicMock, call
|
||||
from mock import patch, MagicMock, call, mock_open
|
||||
|
||||
from test_utils import (
|
||||
CharmTestCase,
|
||||
|
@ -36,10 +36,13 @@ TO_PATCH = [
|
|||
'apt_install',
|
||||
'config',
|
||||
'configure_installation_source',
|
||||
'canonical_url',
|
||||
'disable_policy_rcd',
|
||||
'is_leader',
|
||||
'is_unit_paused_set',
|
||||
'lsb_release',
|
||||
'leader_get',
|
||||
'leader_set',
|
||||
'enable_policy_rcd',
|
||||
'get_os_codename_install_source',
|
||||
'log',
|
||||
|
@ -62,6 +65,7 @@ TO_PATCH = [
|
|||
'token_cache_pkgs',
|
||||
'enable_memcache',
|
||||
'status_set',
|
||||
'uuid1',
|
||||
]
|
||||
|
||||
SCRIPTRC_ENV_VARS = {
|
||||
|
@ -138,7 +142,7 @@ RESTART_MAP_ICEHOUSE = OrderedDict([
|
|||
RESTART_MAP_OCATA_ACTUAL = OrderedDict([
|
||||
('/etc/nova/nova.conf', [
|
||||
'nova-api-ec2', 'nova-api-os-compute', 'nova-objectstore',
|
||||
'nova-cert', 'nova-scheduler', 'nova-conductor', 'apache2'
|
||||
'nova-cert', 'nova-scheduler', 'nova-conductor', 'apache2',
|
||||
]),
|
||||
('/etc/nova/api-paste.ini', [
|
||||
'nova-api-ec2', 'nova-api-os-compute', 'apache2'
|
||||
|
@ -417,7 +421,7 @@ class NovaCCUtilsTests(CharmTestCase):
|
|||
ex = list(set(utils.BASE_PACKAGES + utils.BASE_SERVICES))
|
||||
# nova-placement-api is purposely dropped unless it's ocata
|
||||
ex.remove('nova-placement-api')
|
||||
self.assertEqual(ex, pkgs)
|
||||
self.assertEqual(sorted(ex), sorted(pkgs))
|
||||
|
||||
@patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext')
|
||||
def test_determine_packages_base_ocata(self, subcontext):
|
||||
|
@ -427,7 +431,7 @@ class NovaCCUtilsTests(CharmTestCase):
|
|||
self.enable_memcache.return_value = False
|
||||
pkgs = utils.determine_packages()
|
||||
ex = list(set(utils.BASE_PACKAGES + utils.BASE_SERVICES))
|
||||
self.assertEqual(ex, pkgs)
|
||||
self.assertEqual(sorted(ex), sorted(pkgs))
|
||||
|
||||
@patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext')
|
||||
def test_determine_packages_serial_console(self,
|
||||
|
@ -1234,3 +1238,54 @@ class NovaCCUtilsTests(CharmTestCase):
|
|||
amqp.assert_called_once()
|
||||
shared_db.assert_called_once()
|
||||
self.log.assert_not_called()
|
||||
|
||||
def test_placement_api_enabled(self):
|
||||
self.os_release.return_value = 'ocata'
|
||||
self.assertTrue(utils.placement_api_enabled())
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.assertFalse(utils.placement_api_enabled())
|
||||
|
||||
def test_enable_metadata_api(self):
|
||||
self.os_release.return_value = 'pike'
|
||||
self.assertFalse(utils.enable_metadata_api())
|
||||
self.os_release.return_value = 'rocky'
|
||||
self.assertTrue(utils.enable_metadata_api())
|
||||
|
||||
def test_get_shared_metadatasecret(self):
|
||||
self.leader_get.return_value = 'auuid'
|
||||
self.assertEqual(utils.get_shared_metadatasecret(), 'auuid')
|
||||
|
||||
def test_set_shared_metadatasecret(self):
|
||||
self.uuid1.return_value = 'auuid'
|
||||
utils.set_shared_metadatasecret()
|
||||
self.leader_set.assert_called_once_with({
|
||||
'shared-metadata-secret': 'auuid'})
|
||||
|
||||
@patch.object(utils, 'get_shared_metadatasecret')
|
||||
def test_get_metadata_settings(self, mock_get_shared_metadatasecret):
|
||||
self.os_release.return_value = 'rocky'
|
||||
self.canonical_url.return_value = 'http://someaddr'
|
||||
mock_get_shared_metadatasecret.return_value = 'auuid'
|
||||
self.assertEqual(
|
||||
utils.get_metadata_settings('configs'),
|
||||
{
|
||||
'nova-metadata-host': 'someaddr',
|
||||
'nova-metadata-port': 8775,
|
||||
'nova-metadata-protocol': 'http',
|
||||
'shared-metadata-secret': 'auuid'})
|
||||
|
||||
def test_get_metadata_settings_pike(self):
|
||||
self.os_release.return_value = 'pike'
|
||||
self.assertEqual(
|
||||
utils.get_metadata_settings('configs'),
|
||||
{})
|
||||
|
||||
def test_write_vendordata(self):
|
||||
m = mock_open()
|
||||
with patch.object(utils, 'open', m, create=True):
|
||||
utils.write_vendordata('{"a": "b"}')
|
||||
expected_calls = [
|
||||
call('/etc/nova/vendor_data.json', 'w'),
|
||||
call().write('{\n "a": "b"\n}')]
|
||||
for c in expected_calls:
|
||||
self.assertTrue(c in m.mock_calls)
|
||||
|
|
Loading…
Reference in New Issue