From 05a48269464795b5dc3ea333b172c2688cc45e47 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 11:47:19 +0100 Subject: [PATCH 01/14] Add support for NVP --- charm-helpers.yaml | 3 +- config.yaml | 29 +++++++++++++++++++ .../charmhelpers/contrib/openstack/neutron.py | 20 +++++++++++++ hooks/nova_cc_context.py | 10 +++++++ hooks/nova_cc_hooks.py | 11 ++----- hooks/nova_cc_utils.py | 5 ++-- 6 files changed, 66 insertions(+), 12 deletions(-) diff --git a/charm-helpers.yaml b/charm-helpers.yaml index 30ff4ca7..0ebaaf0d 100644 --- a/charm-helpers.yaml +++ b/charm-helpers.yaml @@ -1,4 +1,4 @@ -branch: lp:charm-helpers +branch: ../charm-helpers destination: hooks/charmhelpers include: - core @@ -7,5 +7,4 @@ include: - contrib.storage - contrib.hahelpers: - apache - - ceph - payload.execd diff --git a/config.yaml b/config.yaml index c734d12b..5bbae565 100644 --- a/config.yaml +++ b/config.yaml @@ -69,6 +69,7 @@ options: Quantum plugin to use for network management; supports . ovs - OpenvSwitch Plugin + nvp - Nicira Network Virtualization Platform . This configuration only has context when used with network-manager Quantum. @@ -125,3 +126,31 @@ options: ssl_key: type: string description: SSL key to use with certificate specified as ssl_cert. + # Neutron NVP Plugin configuration + nvp-controllers: + type: string + description: Space delimited addresses of NVP controllers + nvp-username: + type: string + default: admin + description: Username to connect to NVP controllers with + nvp-password: + type: string + default: admin + description: Password to connect to NVP controllers with + nvp-cluster-name: + type: string + default: example + description: Name of the NVP cluster configuration to create (grizzly only) + nvp-tz-uuid: + type: string + description: | + This is uuid of the default NVP Transport zone that will be used for + creating tunneled isolated Quantum networks. It needs to be created + in NVP before starting Quantum with the nvp plugin. + nvp-l3-uuid: + type: string + description: | + This is uuid of the default NVP L3 Gateway Service. + # end of NVP configuration + diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index a27ce953..8d32bd00 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -34,13 +34,23 @@ def quantum_plugins(): 'services': ['quantum-plugin-openvswitch-agent'], 'packages': [[headers_package(), 'openvswitch-datapath-dkms'], ['quantum-plugin-openvswitch-agent']], + 'server_packages': ['quantum-server', + 'quantum-plugin-openvswitch'], + 'server_services': ['quantum-server'] }, 'nvp': { 'config': '/etc/quantum/plugins/nicira/nvp.ini', 'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.' 'QuantumPlugin.NvpPluginV2', + 'contexts': [ + context.SharedDBContext(user=config('neutron-database-user'), + database=config('neutron-database'), + relation_prefix='neutron')], 'services': [], 'packages': [], + 'server_packages': ['quantum-server', + 'quantum-plugin-nicira'], + 'server_services': ['quantum-server'] } } @@ -60,13 +70,23 @@ def neutron_plugins(): 'services': ['neutron-plugin-openvswitch-agent'], 'packages': [[headers_package(), 'openvswitch-datapath-dkms'], ['quantum-plugin-openvswitch-agent']], + 'server_packages': ['neutron-server', + 'neutron-plugin-openvswitch'], + 'server_services': ['neutron-server'] }, 'nvp': { 'config': '/etc/neutron/plugins/nicira/nvp.ini', 'driver': 'neutron.plugins.nicira.nicira_nvp_plugin.' 'NeutronPlugin.NvpPluginV2', + 'contexts': [ + context.SharedDBContext(user=config('neutron-database-user'), + database=config('neutron-database'), + relation_prefix='neutron')], 'services': [], 'packages': [], + 'server_packages': ['neutron-server', + 'neutron-plugin-nicira'], + 'server_services': ['neutron-server'] } } diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index ccbc0923..72d0d145 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -139,6 +139,16 @@ class NeutronCCContext(context.NeutronContext): def __call__(self): ctxt = super(NeutronCCContext, self).__call__() ctxt['external_network'] = config('neutron-external-network') + if 'nvp' in [config('quantum-plugin'), config('neutron-plugin')]: + _config = config() + for k, v in _config.iteritems(): + if k.startswith('nvp'): + ctxt[k.replace('-', '_')] = v + if 'nvp-controllers' in _config: + ctxt['nvp_controllers'] = \ + ','.join(_config['nvp-controllers'].split()) + ctxt['nvp_controllers_list'] = \ + _config['nvp-controllers'].split() return ctxt diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 9008121c..75308007 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -286,14 +286,9 @@ def quantum_joined(rid=None): if not eligible_leader(CLUSTER_RES): return - if network_manager() == 'quantum': - pkg = 'quantum-server' - else: - pkg = 'neutron-server' - - required_pkg = filter_installed_packages([pkg]) - if required_pkg: - apt_install(required_pkg) + pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', + network_manager()) + apt_install(filter_installed_packages(pkgs)) url = canonical_url(CONFIGS) + ':9696' # XXX: Can we rename to neutron_*? diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 430eeaee..b2a259e6 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -166,11 +166,12 @@ def resource_map(): plugin = neutron_plugin() if plugin: conf = neutron_plugin_attribute(plugin, 'config', net_manager) - service = '%s-server' % net_manager ctxts = (neutron_plugin_attribute(plugin, 'contexts', net_manager) or []) + services = neutron_plugin_attribute(plugin, 'server_services', + net_manager) resource_map[conf] = {} - resource_map[conf]['services'] = [service] + resource_map[conf]['services'] = services resource_map[conf]['contexts'] = ctxts resource_map[conf]['contexts'].append( nova_cc_context.NeutronCCContext()) From 794c262543d31cc0911d09ca575c348b12352666 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 11:51:45 +0100 Subject: [PATCH 02/14] Add missing template for havana --- templates/havana/nvp.ini | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 templates/havana/nvp.ini diff --git a/templates/havana/nvp.ini b/templates/havana/nvp.ini new file mode 100644 index 00000000..a954de58 --- /dev/null +++ b/templates/havana/nvp.ini @@ -0,0 +1,11 @@ +# havana +############################################################################### +# [ WARNING ] +# Configuration file maintained by Juju. Local changes may be overwritten. +############################################################################### +[DEFAULT] +nvp_user = {{ nvp_user }} +nvp_password = {{ nvp_password }} +nvp_controllers = {{ nvp_controllers }} +default_tz_uuid = {{ nvp_tz_uuid }} +default_l3_gw_service_uuid = {{ nvp_l3_uuid }} From 51cbe6283d9fa5b1ec6a4a12dde6b2429331c52c Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:02:35 +0100 Subject: [PATCH 03/14] Update default for plugin for neutron server --- hooks/nova_cc_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index b2a259e6..b9a52fbb 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -175,6 +175,10 @@ def resource_map(): resource_map[conf]['contexts'] = ctxts resource_map[conf]['contexts'].append( nova_cc_context.NeutronCCContext()) + # TODO: make a proper context - this is a bit ugly + with open('/etc/default/{}-server'.format(net_manager), 'w') as f: + f.write('{}_PLUGIN_CONFIG="{}"'.format(net_manager.upper(), + conf)) # nova-conductor for releases >= G. if os_release('nova-common') not in ['essex', 'folsom']: From 7dbbe4c4c0dc00389b5fde4e3df5aede457a89f4 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:07:14 +0100 Subject: [PATCH 04/14] Update ch's --- hooks/charmhelpers/contrib/openstack/context.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 13fdd65a..d72a4d46 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -395,6 +395,19 @@ class NeutronContext(object): return ovs_ctxt + def nvp_ctxt(self): + driver = neutron_plugin_attribute(self.plugin, 'driver', + self.network_manager) + + nvp_ctxt = { + 'core_plugin': driver, + 'neutron_plugin': 'nvp', + 'neutron_security_groups': self.neutron_security_groups, + 'local_ip': unit_private_ip(), + } + + return nvp_ctxt + def __call__(self): self._ensure_packages() @@ -408,6 +421,8 @@ class NeutronContext(object): if self.plugin == 'ovs': ctxt.update(self.ovs_ctxt()) + elif self.plugin == 'nvp': + ctxt.update(self.nvp_ctxt()) self._save_flag_file() return ctxt From fe708d66bb00fef6fbfa4820ad1e8bd335ebbd2b Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:14:35 +0100 Subject: [PATCH 05/14] Fixup username in template --- templates/havana/nvp.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/havana/nvp.ini b/templates/havana/nvp.ini index a954de58..43df47bf 100644 --- a/templates/havana/nvp.ini +++ b/templates/havana/nvp.ini @@ -4,7 +4,7 @@ # Configuration file maintained by Juju. Local changes may be overwritten. ############################################################################### [DEFAULT] -nvp_user = {{ nvp_user }} +nvp_user = {{ nvp_username }} nvp_password = {{ nvp_password }} nvp_controllers = {{ nvp_controllers }} default_tz_uuid = {{ nvp_tz_uuid }} From 44de33e56196096069a2d48c963053dd21114970 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:44:27 +0100 Subject: [PATCH 06/14] Fixup neutron package installs --- hooks/nova_cc_hooks.py | 4 ---- hooks/nova_cc_utils.py | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 75308007..c5e816bd 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -286,10 +286,6 @@ def quantum_joined(rid=None): if not eligible_leader(CLUSTER_RES): return - pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', - network_manager()) - apt_install(filter_installed_packages(pkgs)) - url = canonical_url(CONFIGS) + ':9696' # XXX: Can we rename to neutron_*? rel_settings = { diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index b9a52fbb..413ab742 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -220,8 +220,9 @@ def api_port(service): def determine_packages(): # currently all packages match service names packages = [] + BASE_PACKAGES - for k, v in resource_map().iteritems(): - packages.extend(v['services']) + pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', + network_manager()) + packages.extent(pkgs) return list(set(packages)) From 0eaeba3fe69497a6086017ee1bb020ae5b107f44 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:47:26 +0100 Subject: [PATCH 07/14] Add check for neutron networking during install --- hooks/nova_cc_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 413ab742..5f719f81 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -220,9 +220,10 @@ def api_port(service): def determine_packages(): # currently all packages match service names packages = [] + BASE_PACKAGES - pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', - network_manager()) - packages.extent(pkgs) + if network_manager() in ['neutron', 'quantum']: + pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', + network_manager()) + packages.extent(pkgs) return list(set(packages)) From 975bfe5a0ea153671b5e7e5516186b38ccc0ba0b Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 12:54:16 +0100 Subject: [PATCH 08/14] Write neutron-server default via context --- hooks/charmhelpers/contrib/openstack/context.py | 8 ++++++-- hooks/nova_cc_utils.py | 14 ++++++++++---- templates/folsom/quantum-server | 6 ++++++ templates/havana/neutron-server | 6 ++++++ 4 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 templates/folsom/quantum-server create mode 100644 templates/havana/neutron-server diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index d72a4d46..8a982ffa 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -385,12 +385,14 @@ class NeutronContext(object): def ovs_ctxt(self): driver = neutron_plugin_attribute(self.plugin, 'driver', self.network_manager) - + config = neutron_plugin_attribute(self.plugin, 'config', + self.network_manager) ovs_ctxt = { 'core_plugin': driver, 'neutron_plugin': 'ovs', 'neutron_security_groups': self.neutron_security_groups, 'local_ip': unit_private_ip(), + 'config': config } return ovs_ctxt @@ -398,12 +400,14 @@ class NeutronContext(object): def nvp_ctxt(self): driver = neutron_plugin_attribute(self.plugin, 'driver', self.network_manager) - + config = neutron_plugin_attribute(self.plugin, 'config', + self.network_manager) nvp_ctxt = { 'core_plugin': driver, 'neutron_plugin': 'nvp', 'neutron_security_groups': self.neutron_security_groups, 'local_ip': unit_private_ip(), + 'config': config } return nvp_ctxt diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 5f719f81..37c4e135 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -76,6 +76,8 @@ NEUTRON_CONF = '/etc/neutron/neutron.conf' HAPROXY_CONF = '/etc/haproxy/haproxy.cfg' APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend' APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf' +NEUTRON_DEFAULT = '/etc/default/neutron-server' +QUANTUM_DEFAULT = '/etc/default/quantum-server' BASE_RESOURCE_MAP = OrderedDict([ (NOVA_CONF, { @@ -100,6 +102,10 @@ BASE_RESOURCE_MAP = OrderedDict([ nova_cc_context.IdentityServiceContext(), nova_cc_context.NeutronCCContext()], }), + (QUANTUM_DEFAULT, { + 'services': ['quantum-server'], + 'contexts': [nova_cc_context.NeutronCCContext()], + }), (QUANTUM_API_PASTE, { 'services': ['quantum-server'], 'contexts': [nova_cc_context.IdentityServiceContext()], @@ -111,6 +117,10 @@ BASE_RESOURCE_MAP = OrderedDict([ nova_cc_context.NeutronCCContext(), nova_cc_context.HAProxyContext()], }), + (NEUTRON_DEFAULT, { + 'services': ['neutron-server'], + 'contexts': [nova_cc_context.NeutronCCContext()], + }), (HAPROXY_CONF, { 'contexts': [context.HAProxyContext(), nova_cc_context.HAProxyContext()], @@ -175,10 +185,6 @@ def resource_map(): resource_map[conf]['contexts'] = ctxts resource_map[conf]['contexts'].append( nova_cc_context.NeutronCCContext()) - # TODO: make a proper context - this is a bit ugly - with open('/etc/default/{}-server'.format(net_manager), 'w') as f: - f.write('{}_PLUGIN_CONFIG="{}"'.format(net_manager.upper(), - conf)) # nova-conductor for releases >= G. if os_release('nova-common') not in ['essex', 'folsom']: diff --git a/templates/folsom/quantum-server b/templates/folsom/quantum-server new file mode 100644 index 00000000..2f7e52c5 --- /dev/null +++ b/templates/folsom/quantum-server @@ -0,0 +1,6 @@ +# quantum +############################################################################### +# [ WARNING ] +# Configuration file maintained by Juju. Local changes may be overwritten. +############################################################################### +QUANTUM_PLUGIN_CONFIG="{{ config }}" \ No newline at end of file diff --git a/templates/havana/neutron-server b/templates/havana/neutron-server new file mode 100644 index 00000000..cbbc435c --- /dev/null +++ b/templates/havana/neutron-server @@ -0,0 +1,6 @@ +# havana +############################################################################### +# [ WARNING ] +# Configuration file maintained by Juju. Local changes may be overwritten. +############################################################################### +NEUTRON_PLUGIN_CONFIG="{{ config }}" \ No newline at end of file From d86ea9fc0e3bcc2e1fad3bf1f4a86025bb51fb4b Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 16 Oct 2013 13:12:13 +0100 Subject: [PATCH 09/14] Fixup tests --- hooks/nova_cc_utils.py | 4 +++- unit_tests/test_nova_cc_utils.py | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 37c4e135..b64d5037 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -226,10 +226,12 @@ def api_port(service): def determine_packages(): # currently all packages match service names packages = [] + BASE_PACKAGES + for k, v in resource_map().iteritems(): + packages.extend(v['services']) if network_manager() in ['neutron', 'quantum']: pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages', network_manager()) - packages.extent(pkgs) + packages.extend(pkgs) return list(set(packages)) diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index bc554f91..b34ff685 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -70,10 +70,11 @@ RESTART_MAP = OrderedDict([ 'nova-api-ec2', 'nova-api-os-compute' ]), ('/etc/neutron/neutron.conf', ['neutron-server']), + ('/etc/default/neutron-server', ['neutron-server']), ('/etc/haproxy/haproxy.cfg', ['haproxy']), ('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']), ('/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini', - ['neutron-server']) + ['quantum-server']) ]) @@ -87,13 +88,17 @@ PLUGIN_ATTRIBUTES = { 'services': ['quantum-plugin-openvswitch-agent'], 'packages': ['quantum-plugin-openvswitch-agent', 'openvswitch-datapath-dkms'], + 'server_packages': ['quantum-server', 'quantum-plugin-openvswitch'], + 'server_services': ['quantum-server'], }, 'nvp': { 'config': '/etc/quantum/plugins/nicira/nvp.ini', 'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.' 'QuantumPlugin.NvpPluginV2', 'services': [], - 'packages': ['quantum-plugin-nicira'], + 'packages': [], + 'server_packages': ['quantum-server', 'quantum-plugin-nicria'], + 'server_services': ['quantum-server'], } } From a33cdbf19afcf78d287b98b0301cec3d49f3a65c Mon Sep 17 00:00:00 2001 From: James Page Date: Tue, 22 Oct 2013 15:30:06 -0700 Subject: [PATCH 10/14] Fixup template for nvp --- .project | 2 +- .pydevproject | 4 ++-- templates/folsom/nova.conf | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.project b/.project index 97aa0f99..22e90774 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - nova-cloud-controller + nvp-nova-cloud-controller diff --git a/.pydevproject b/.pydevproject index 3b124098..90f0dd85 100644 --- a/.pydevproject +++ b/.pydevproject @@ -1,8 +1,8 @@ -/nova-cloud-controller/hooks -/nova-cloud-controller/unit_tests +/nvp-nova-cloud-controller/hooks +/nvp-nova-cloud-controller/unit_tests python 2.7 Default diff --git a/templates/folsom/nova.conf b/templates/folsom/nova.conf index a7b79254..b74e7a1d 100644 --- a/templates/folsom/nova.conf +++ b/templates/folsom/nova.conf @@ -57,6 +57,16 @@ default_floating_pool = {{ external_network }} {% endif -%} {% endif -%} +{% if neutron_plugin and neutron_plugin == 'nvp' -%} +{% 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 network_manager_config -%} {% for key, value in network_manager_config.iteritems() -%} {{ key }} = {{ value }} From aa292323257d188b6a99c4e98987b643f8ed6aa9 Mon Sep 17 00:00:00 2001 From: James Page Date: Tue, 22 Oct 2013 15:31:38 -0700 Subject: [PATCH 11/14] Force neutron security for NVP --- templates/folsom/nova.conf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/templates/folsom/nova.conf b/templates/folsom/nova.conf index b74e7a1d..414e6ea7 100644 --- a/templates/folsom/nova.conf +++ b/templates/folsom/nova.conf @@ -58,10 +58,8 @@ default_floating_pool = {{ external_network }} {% endif -%} {% if neutron_plugin and neutron_plugin == 'nvp' -%} -{% if neutron_security_groups -%} -security_group_api = {{ network_manager }} +security_group_api = neutron nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver -{% endif -%} {% if external_network -%} default_floating_pool = {{ external_network }} {% endif -%} From 801ac9b82f4895d452e37fe3970f0595d931977c Mon Sep 17 00:00:00 2001 From: James Page Date: Tue, 22 Oct 2013 16:01:40 -0700 Subject: [PATCH 12/14] resync with helpers --- charm-helpers.yaml | 2 +- hooks/charmhelpers/core/hookenv.py | 81 ++++++++++++++++++++-------- hooks/charmhelpers/core/host.py | 24 +++++---- hooks/charmhelpers/fetch/__init__.py | 26 +++++++-- 4 files changed, 96 insertions(+), 37 deletions(-) diff --git a/charm-helpers.yaml b/charm-helpers.yaml index 0ebaaf0d..b1d07eab 100644 --- a/charm-helpers.yaml +++ b/charm-helpers.yaml @@ -1,4 +1,4 @@ -branch: ../charm-helpers +branch: lp:~james-page/charm-helpers/nvp-updates destination: hooks/charmhelpers include: - core diff --git a/hooks/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py index 2b06706c..e86f8654 100644 --- a/hooks/charmhelpers/core/hookenv.py +++ b/hooks/charmhelpers/core/hookenv.py @@ -9,6 +9,7 @@ import json import yaml import subprocess import UserDict +from subprocess import CalledProcessError CRITICAL = "CRITICAL" ERROR = "ERROR" @@ -21,7 +22,7 @@ cache = {} def cached(func): - ''' Cache return values for multiple executions of func + args + """Cache return values for multiple executions of func + args For example: @@ -32,7 +33,7 @@ def cached(func): unit_get('test') will cache the result of unit_get + 'test' for future calls. - ''' + """ def wrapper(*args, **kwargs): global cache key = str((func, args, kwargs)) @@ -46,8 +47,8 @@ def cached(func): def flush(key): - ''' Flushes any entries from function cache where the - key is found in the function+args ''' + """Flushes any entries from function cache where the + key is found in the function+args """ flush_list = [] for item in cache: if key in item: @@ -57,7 +58,7 @@ def flush(key): def log(message, level=None): - "Write a message to the juju log" + """Write a message to the juju log""" command = ['juju-log'] if level: command += ['-l', level] @@ -66,7 +67,7 @@ def log(message, level=None): class Serializable(UserDict.IterableUserDict): - "Wrapper, an object that can be serialized to yaml or json" + """Wrapper, an object that can be serialized to yaml or json""" def __init__(self, obj): # wrap the object @@ -96,11 +97,11 @@ class Serializable(UserDict.IterableUserDict): self.data = state def json(self): - "Serialize the object to json" + """Serialize the object to json""" return json.dumps(self.data) def yaml(self): - "Serialize the object to yaml" + """Serialize the object to yaml""" return yaml.dump(self.data) @@ -119,38 +120,38 @@ def execution_environment(): def in_relation_hook(): - "Determine whether we're running in a relation hook" + """Determine whether we're running in a relation hook""" return 'JUJU_RELATION' in os.environ def relation_type(): - "The scope for the current relation hook" + """The scope for the current relation hook""" return os.environ.get('JUJU_RELATION', None) def relation_id(): - "The relation ID for the current relation hook" + """The relation ID for the current relation hook""" return os.environ.get('JUJU_RELATION_ID', None) def local_unit(): - "Local unit ID" + """Local unit ID""" return os.environ['JUJU_UNIT_NAME'] def remote_unit(): - "The remote unit for the current relation hook" + """The remote unit for the current relation hook""" return os.environ['JUJU_REMOTE_UNIT'] def service_name(): - "The name service group this unit belongs to" + """The name service group this unit belongs to""" return local_unit().split('/')[0] @cached def config(scope=None): - "Juju charm configuration" + """Juju charm configuration""" config_cmd_line = ['config-get'] if scope is not None: config_cmd_line.append(scope) @@ -163,6 +164,7 @@ def config(scope=None): @cached def relation_get(attribute=None, unit=None, rid=None): + """Get relation information""" _args = ['relation-get', '--format=json'] if rid: _args.append('-r') @@ -174,9 +176,14 @@ def relation_get(attribute=None, unit=None, rid=None): return json.loads(subprocess.check_output(_args)) except ValueError: return None + except CalledProcessError, e: + if e.returncode == 2: + return None + raise def relation_set(relation_id=None, relation_settings={}, **kwargs): + """Set relation information for the current unit""" relation_cmd_line = ['relation-set'] if relation_id is not None: relation_cmd_line.extend(('-r', relation_id)) @@ -192,7 +199,7 @@ def relation_set(relation_id=None, relation_settings={}, **kwargs): @cached def relation_ids(reltype=None): - "A list of relation_ids" + """A list of relation_ids""" reltype = reltype or relation_type() relid_cmd_line = ['relation-ids', '--format=json'] if reltype is not None: @@ -203,7 +210,7 @@ def relation_ids(reltype=None): @cached def related_units(relid=None): - "A list of related units" + """A list of related units""" relid = relid or relation_id() units_cmd_line = ['relation-list', '--format=json'] if relid is not None: @@ -213,7 +220,7 @@ def related_units(relid=None): @cached def relation_for_unit(unit=None, rid=None): - "Get the json represenation of a unit's relation" + """Get the json represenation of a unit's relation""" unit = unit or remote_unit() relation = relation_get(unit=unit, rid=rid) for key in relation: @@ -225,7 +232,7 @@ def relation_for_unit(unit=None, rid=None): @cached def relations_for_id(relid=None): - "Get relations of a specific relation ID" + """Get relations of a specific relation ID""" relation_data = [] relid = relid or relation_ids() for unit in related_units(relid): @@ -237,7 +244,7 @@ def relations_for_id(relid=None): @cached def relations_of_type(reltype=None): - "Get relations of a specific type" + """Get relations of a specific type""" relation_data = [] reltype = reltype or relation_type() for relid in relation_ids(reltype): @@ -249,7 +256,7 @@ def relations_of_type(reltype=None): @cached def relation_types(): - "Get a list of relation types supported by this charm" + """Get a list of relation types supported by this charm""" charmdir = os.environ.get('CHARM_DIR', '') mdf = open(os.path.join(charmdir, 'metadata.yaml')) md = yaml.safe_load(mdf) @@ -264,6 +271,7 @@ def relation_types(): @cached def relations(): + """Get a nested dictionary of relation data for all related units""" rels = {} for reltype in relation_types(): relids = {} @@ -278,14 +286,14 @@ def relations(): def open_port(port, protocol="TCP"): - "Open a service network port" + """Open a service network port""" _args = ['open-port'] _args.append('{}/{}'.format(port, protocol)) subprocess.check_call(_args) def close_port(port, protocol="TCP"): - "Close a service network port" + """Close a service network port""" _args = ['close-port'] _args.append('{}/{}'.format(port, protocol)) subprocess.check_call(_args) @@ -293,6 +301,7 @@ def close_port(port, protocol="TCP"): @cached def unit_get(attribute): + """Get the unit ID for the remote unit""" _args = ['unit-get', '--format=json', attribute] try: return json.loads(subprocess.check_output(_args)) @@ -301,22 +310,46 @@ def unit_get(attribute): def unit_private_ip(): + """Get this unit's private IP address""" return unit_get('private-address') class UnregisteredHookError(Exception): + """Raised when an undefined hook is called""" pass class Hooks(object): + """A convenient handler for hook functions. + + Example: + hooks = Hooks() + + # register a hook, taking its name from the function name + @hooks.hook() + def install(): + ... + + # register a hook, providing a custom hook name + @hooks.hook("config-changed") + def config_changed(): + ... + + if __name__ == "__main__": + # execute a hook based on the name the program is called by + hooks.execute(sys.argv) + """ + def __init__(self): super(Hooks, self).__init__() self._hooks = {} def register(self, name, function): + """Register a hook""" self._hooks[name] = function def execute(self, args): + """Execute a registered hook based on args[0]""" hook_name = os.path.basename(args[0]) if hook_name in self._hooks: self._hooks[hook_name]() @@ -324,6 +357,7 @@ class Hooks(object): raise UnregisteredHookError(hook_name) def hook(self, *hook_names): + """Decorator, registering them as hooks""" def wrapper(decorated): for hook_name in hook_names: self.register(hook_name, decorated) @@ -337,4 +371,5 @@ class Hooks(object): def charm_dir(): + """Return the root directory of the current charm""" return os.environ.get('CHARM_DIR') diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index 1a63bf89..4a6a4a8c 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -19,18 +19,22 @@ from hookenv import log def service_start(service_name): + """Start a system service""" return service('start', service_name) def service_stop(service_name): + """Stop a system service""" return service('stop', service_name) def service_restart(service_name): + """Restart a system service""" return service('restart', service_name) def service_reload(service_name, restart_on_failure=False): + """Reload a system service, optionally falling back to restart if reload fails""" service_result = service('reload', service_name) if not service_result and restart_on_failure: service_result = service('restart', service_name) @@ -38,11 +42,13 @@ def service_reload(service_name, restart_on_failure=False): def service(action, service_name): + """Control a system service""" cmd = ['service', service_name, action] return subprocess.call(cmd) == 0 def service_running(service): + """Determine whether a system service is running""" try: output = subprocess.check_output(['service', service, 'status']) except subprocess.CalledProcessError: @@ -55,7 +61,7 @@ def service_running(service): def adduser(username, password=None, shell='/bin/bash', system_user=False): - """Add a user""" + """Add a user to the system""" try: user_info = pwd.getpwnam(username) log('user {0} already exists!'.format(username)) @@ -138,7 +144,7 @@ def write_file(path, content, owner='root', group='root', perms=0444): def mount(device, mountpoint, options=None, persist=False): - '''Mount a filesystem''' + """Mount a filesystem at a particular mountpoint""" cmd_args = ['mount'] if options is not None: cmd_args.extend(['-o', options]) @@ -155,7 +161,7 @@ def mount(device, mountpoint, options=None, persist=False): def umount(mountpoint, persist=False): - '''Unmount a filesystem''' + """Unmount a filesystem""" cmd_args = ['umount', mountpoint] try: subprocess.check_output(cmd_args) @@ -169,7 +175,7 @@ def umount(mountpoint, persist=False): def mounts(): - '''List of all mounted volumes as [[mountpoint,device],[...]]''' + """Get a list of all mounted volumes as [[mountpoint,device],[...]]""" with open('/proc/mounts') as f: # [['/mount/point','/dev/path'],[...]] system_mounts = [m[1::-1] for m in [l.strip().split() @@ -178,7 +184,7 @@ def mounts(): def file_hash(path): - ''' Generate a md5 hash of the contents of 'path' or None if not found ''' + """Generate a md5 hash of the contents of 'path' or None if not found """ if os.path.exists(path): h = hashlib.md5() with open(path, 'r') as source: @@ -189,7 +195,7 @@ def file_hash(path): def restart_on_change(restart_map): - ''' Restart services based on configuration files changing + """Restart services based on configuration files changing This function is used a decorator, for example @@ -202,7 +208,7 @@ def restart_on_change(restart_map): In this example, the cinder-api and cinder-volume services would be restarted if /etc/ceph/ceph.conf is changed by the ceph_client_changed function. - ''' + """ def wrap(f): def wrapped_f(*args): checksums = {} @@ -220,7 +226,7 @@ def restart_on_change(restart_map): def lsb_release(): - '''Return /etc/lsb-release in a dict''' + """Return /etc/lsb-release in a dict""" d = {} with open('/etc/lsb-release', 'r') as lsb: for l in lsb: @@ -230,7 +236,7 @@ def lsb_release(): def pwgen(length=None): - '''Generate a random pasword.''' + """Generate a random pasword.""" if length is None: length = random.choice(range(35, 45)) alphanumeric_chars = [ diff --git a/hooks/charmhelpers/fetch/__init__.py b/hooks/charmhelpers/fetch/__init__.py index b2f96467..68f55f00 100644 --- a/hooks/charmhelpers/fetch/__init__.py +++ b/hooks/charmhelpers/fetch/__init__.py @@ -79,9 +79,24 @@ def apt_purge(packages, fatal=False): subprocess.call(cmd) +def apt_hold(packages, fatal=False): + """Hold one or more packages""" + cmd = ['apt-mark', 'hold'] + if isinstance(packages, basestring): + cmd.append(packages) + else: + cmd.extend(packages) + log("Holding {}".format(packages)) + if fatal: + subprocess.check_call(cmd) + else: + subprocess.call(cmd) + + def add_source(source, key=None): - if ((source.startswith('ppa:') or - source.startswith('http:'))): + if (source.startswith('ppa:') or + source.startswith('http:') or + source.startswith('deb ')): subprocess.check_call(['add-apt-repository', '--yes', source]) elif source.startswith('cloud:'): apt_install(filter_installed_packages(['ubuntu-cloud-keyring']), @@ -118,8 +133,11 @@ def configure_sources(update=False, Note that 'null' (a.k.a. None) should not be quoted. """ sources = safe_load(config(sources_var)) - keys = safe_load(config(keys_var)) - if isinstance(sources, basestring) and isinstance(keys, basestring): + keys = config(keys_var) + if keys is not None: + keys = safe_load(keys) + if isinstance(sources, basestring) and ( + keys is None or isinstance(keys, basestring)): add_source(sources, keys) else: if not len(sources) == len(keys): From 661aaf11e3b7eed080e74ef734b252f728512789 Mon Sep 17 00:00:00 2001 From: James Page Date: Wed, 23 Oct 2013 09:55:26 -0700 Subject: [PATCH 13/14] Use correct key when setting data for quantum_joined --- hooks/nova_cc_hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 9008121c..e718553e 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -314,7 +314,7 @@ def quantum_joined(rid=None): if ks_auth_config and ks_ca: rel_settings['ca_cert'] = ks_ca - relation_set(rid=rid, **rel_settings) + relation_set(relation_id=rid, **rel_settings) @hooks.hook('cluster-relation-changed', From a0e2deac210f9b37fc78906a14e8df5ae21b8950 Mon Sep 17 00:00:00 2001 From: Adam Gandelman Date: Wed, 23 Oct 2013 13:14:56 -0700 Subject: [PATCH 14/14] Update icon.svg --- icon.svg | 1257 +++++++++++++++++++++++++----------------------------- 1 file changed, 590 insertions(+), 667 deletions(-) diff --git a/icon.svg b/icon.svg index e88ea625..b481490c 100644 --- a/icon.svg +++ b/icon.svg @@ -14,380 +14,8 @@ height="96" id="svg6517" version="1.1" - inkscape:version="0.48+devel r12304" - sodipodi:docname="Openstack.svg"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + inkscape:version="0.48+devel r12591" + sodipodi:docname="openstack-nova.svg"> + inkscape:snap-center="true" + inkscape:snap-grids="false" + inkscape:snap-nodes="true" + inkscape:snap-others="false"> + id="grid821" + type="xygrid" /> + id="guide823" + position="18.34962,45.78585" + orientation="1,0" /> + id="guide827" + position="78.02001,46.32673" + orientation="1,0" /> + inkscape:label="" + id="guide4184" + position="65.586619,19.307" + orientation="-0.087155743,0.9961947" /> + inkscape:label="" + id="guide4188" + position="62.756032,71.583147" + orientation="-0.087155743,0.9961947" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -460,308 +491,200 @@ + id="layer1" + inkscape:groupmode="layer" + inkscape:label="BACKGROUND"> + id="path6455" + d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z" + style="fill:url(#linearGradient908);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)" /> + + id="g4336"> - - - - - + transform="matrix(0.06790711,0,0,-0.06790711,-239.0411,765.68623)" + id="g3897" + xml:space="default"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + style="opacity:0.7;color:#000000;fill:url(#radialGradient3902);fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3831);enable-background:accumulate" + d="m -48.09375,67.8125 c -0.873996,-0.0028 -2.089735,0.01993 -3.40625,0.09375 -2.633031,0.147647 -5.700107,0.471759 -7.78125,1.53125 a 1.0001,1.0001 0 0 0 -0.25,1.59375 L -38.8125,92.375 a 1.0001,1.0001 0 0 0 0.84375,0.3125 L -24,90.5625 a 1.0001,1.0001 0 0 0 0.53125,-1.71875 L -46.0625,68.125 a 1.0001,1.0001 0 0 0 -0.625,-0.28125 c 0,0 -0.532254,-0.02842 -1.40625,-0.03125 z" + transform="matrix(10.616011,0,0,-10.616011,357.98166,1725.8152)" + id="path3821" + xml:space="default" /> + + + + + + + + + + + + + + + id="layer3" + inkscape:groupmode="layer" />