From 7702073099e6661342c09d2e9cfa2377d6f79c8f Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Fri, 24 Oct 2014 10:20:36 -0300 Subject: [PATCH 01/13] Add relation with memcached to use it to store nova-authconsole tokens Fix bug #989337 --- hooks/cache-relation-broken | 1 + hooks/cache-relation-changed | 1 + hooks/cache-relation-departed | 1 + hooks/cache-relation-joined | 1 + hooks/nova_cc_context.py | 21 ++++++++++- hooks/nova_cc_hooks.py | 9 +++++ metadata.yaml | 2 + templates/folsom/nova.conf | 5 +++ templates/grizzly/nova.conf | 5 +++ templates/havana/nova.conf | 4 ++ templates/icehouse/nova.conf | 4 ++ unit_tests/test_nova_cc_contexts.py | 58 +++++++++++++++++++++++++++++ 12 files changed, 111 insertions(+), 1 deletion(-) create mode 120000 hooks/cache-relation-broken create mode 120000 hooks/cache-relation-changed create mode 120000 hooks/cache-relation-departed create mode 120000 hooks/cache-relation-joined create mode 100644 unit_tests/test_nova_cc_contexts.py diff --git a/hooks/cache-relation-broken b/hooks/cache-relation-broken new file mode 120000 index 00000000..f6702415 --- /dev/null +++ b/hooks/cache-relation-broken @@ -0,0 +1 @@ +nova_cc_hooks.py \ No newline at end of file diff --git a/hooks/cache-relation-changed b/hooks/cache-relation-changed new file mode 120000 index 00000000..f6702415 --- /dev/null +++ b/hooks/cache-relation-changed @@ -0,0 +1 @@ +nova_cc_hooks.py \ No newline at end of file diff --git a/hooks/cache-relation-departed b/hooks/cache-relation-departed new file mode 120000 index 00000000..f6702415 --- /dev/null +++ b/hooks/cache-relation-departed @@ -0,0 +1 @@ +nova_cc_hooks.py \ No newline at end of file diff --git a/hooks/cache-relation-joined b/hooks/cache-relation-joined new file mode 120000 index 00000000..f6702415 --- /dev/null +++ b/hooks/cache-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 bb3db4fb..94557ffd 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -1,6 +1,6 @@ from charmhelpers.core.hookenv import ( config, relation_ids, relation_set, log, ERROR, - unit_get, related_units, relation_get) + unit_get, related_units, relation_get, relations_for_id) from charmhelpers.fetch import apt_install, filter_installed_packages from charmhelpers.contrib.openstack import context, neutron, utils @@ -281,3 +281,22 @@ class NovaIPv6Context(context.BindHostContext): ctxt = super(NovaIPv6Context, self).__call__() ctxt['use_ipv6'] = config('prefer-ipv6') return ctxt + + +class InstanceConsoleContext(context.OSContextGenerator): + interfaces = [] + + def __call__(self): + ctxt = {} + servers = [] + try: + for rid in relation_ids('cache'): + for rel in relations_for_id(rid): + servers.append({'private-address': rel['private-address'], + 'port': rel['port']}) + except Exception as ex: + log(str(ex)) + servers = [] + + ctxt['memcached_servers'] = servers + return ctxt diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 7fd18916..5fe9eea7 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -852,6 +852,15 @@ def neutron_api_relation_broken(): quantum_joined(rid=rid) +@hooks.hook('cache-relation-joined', + 'cache-relation-departed', + 'cache-relation-changed', + 'cache-relation-broken') +@restart_on_change(restart_map()) +def memcached_joined(): + CONFIGS.write(NOVA_CONF) + + def main(): try: hooks.execute(sys.argv) diff --git a/metadata.yaml b/metadata.yaml index 573e5232..be2440de 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -40,6 +40,8 @@ requires: nova-vmware: interface: nova-vmware scope: container + cache: + interface: memcache peers: cluster: interface: nova-ha diff --git a/templates/folsom/nova.conf b/templates/folsom/nova.conf index ed0f13ac..bbc5d832 100644 --- a/templates/folsom/nova.conf +++ b/templates/folsom/nova.conf @@ -21,6 +21,11 @@ volumes_path=/var/lib/nova/volumes enabled_apis=ec2,osapi_compute,metadata auth_strategy=keystone compute_driver=libvirt.LibvirtDriver + +{% if memcached_servers %} +memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +{% endif %} + {% if keystone_ec2_url -%} keystone_ec2_url = {{ keystone_ec2_url }} {% endif -%} diff --git a/templates/grizzly/nova.conf b/templates/grizzly/nova.conf index 9c308fae..e67c32fc 100644 --- a/templates/grizzly/nova.conf +++ b/templates/grizzly/nova.conf @@ -20,6 +20,11 @@ volumes_path=/var/lib/nova/volumes enabled_apis=ec2,osapi_compute,metadata auth_strategy=keystone compute_driver=libvirt.LibvirtDriver + +{% if memcached_servers %} +memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +{% endif %} + {% if keystone_ec2_url -%} keystone_ec2_url = {{ keystone_ec2_url }} {% endif -%} diff --git a/templates/havana/nova.conf b/templates/havana/nova.conf index 24a0fcfd..22cd8ed9 100644 --- a/templates/havana/nova.conf +++ b/templates/havana/nova.conf @@ -26,6 +26,10 @@ scheduler_default_filters = RetryFilter,AvailabilityZoneFilter,CoreFilter,RamFil cpu_allocation_ratio = {{ cpu_allocation_ratio }} use_syslog={{ use_syslog }} +{% if memcached_servers %} +memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +{% endif %} + {% if keystone_ec2_url -%} keystone_ec2_url = {{ keystone_ec2_url }} {% endif -%} diff --git a/templates/icehouse/nova.conf b/templates/icehouse/nova.conf index c2b62e42..a0e19da0 100644 --- a/templates/icehouse/nova.conf +++ b/templates/icehouse/nova.conf @@ -38,6 +38,10 @@ ram_allocation_ratio = {{ ram_allocation_ratio }} use_syslog={{ use_syslog }} +{% if memcached_servers %} +memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +{% endif %} + {% if keystone_ec2_url -%} keystone_ec2_url = {{ keystone_ec2_url }} {% endif -%} diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py new file mode 100644 index 00000000..1945d949 --- /dev/null +++ b/unit_tests/test_nova_cc_contexts.py @@ -0,0 +1,58 @@ +from __future__ import print_function + +import mock +import nova_cc_context as context + +from charmhelpers.contrib.openstack import utils + +from test_utils import CharmTestCase + + +TO_PATCH = [ + 'apt_install', + 'filter_installed_packages', + 'relation_ids', + 'relation_get', + 'related_units', + 'config', + 'log', + 'unit_get', + 'relations_for_id', +] + + +def fake_log(msg, level=None): + level = level or 'INFO' + print('[juju test log (%s)] %s' % (level, msg)) + + +class NovaComputeContextTests(CharmTestCase): + def setUp(self): + super(NovaComputeContextTests, self).setUp(context, TO_PATCH) + self.relation_get.side_effect = self.test_relation.get + self.config.side_effect = self.test_config.get + self.log.side_effect = fake_log + + @mock.patch.object(utils, 'os_release') + def test_instance_console_context_without_memcache(self, os_release): + self.unit_get.return_value = '127.0.0.1' + self.relation_ids.return_value = 'cache:0' + self.related_units.return_value = 'memcached/0' + instance_console = context.InstanceConsoleContext() + os_release.return_value = 'icehouse' + self.assertEqual({'memcached_servers': []}, + instance_console()) + + @mock.patch.object(utils, 'os_release') + def test_instance_console_context_with_memcache(self, os_release): + memcached_servers = [{'private-address': '127.0.1.1', + 'port': '11211'}] + self.unit_get.return_value = '127.0.0.1' + self.relation_ids.return_value = ['cache:0'] + self.relations_for_id.return_value = memcached_servers + self.related_units.return_value = 'memcached/0' + instance_console = context.InstanceConsoleContext() + os_release.return_value = 'icehouse' + self.maxDiff = None + self.assertEqual({'memcached_servers': memcached_servers}, + instance_console()) From 641bbc776ebdd1014574599d41c13a52b621ae46 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Fri, 24 Oct 2014 12:00:23 -0300 Subject: [PATCH 02/13] Add InstanceConsoleContext to the resource map --- hooks/nova_cc_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 88112039..5f23866b 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -123,7 +123,8 @@ BASE_RESOURCE_MAP = OrderedDict([ nova_cc_context.VolumeServiceContext(), nova_cc_context.NovaIPv6Context(), nova_cc_context.NeutronCCContext(), - nova_cc_context.NovaConfigContext()], + nova_cc_context.NovaConfigContext(), + nova_cc_context.InstanceConsoleContext()], }), (NOVA_API_PASTE, { 'services': [s for s in BASE_SERVICES if 'api' in s], From d291474335d592bdfe85c46b23e1e943e06ce8ab Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Fri, 24 Oct 2014 17:47:02 -0300 Subject: [PATCH 03/13] Add python-memcache to be installed --- hooks/nova_cc_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 5f23866b..9a2e5d12 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -68,6 +68,7 @@ BASE_PACKAGES = [ 'python-psycopg2', 'python-psutil', 'uuid', + 'python-memcached', ] BASE_SERVICES = [ From 547660045d1883da9b3cd0e4fb254c4cbc9d3a1f Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Fri, 24 Oct 2014 18:04:26 -0300 Subject: [PATCH 04/13] Fix typo in memcache package --- hooks/nova_cc_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 9a2e5d12..ea1dae5d 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -68,7 +68,7 @@ BASE_PACKAGES = [ 'python-psycopg2', 'python-psutil', 'uuid', - 'python-memcached', + 'python-memcache', ] BASE_SERVICES = [ From a37379fef5f6d5e1b4f9aaf5437154ad2dc7be81 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Tue, 4 Nov 2014 15:11:18 -0300 Subject: [PATCH 05/13] Changed the way charmhelpers.core.hookenv.config is imported This change allows to easily monkey patch the function with a mock, otherwise the 'config' function is left imported at the module level. --- hooks/nova_cc_context.py | 32 ++++++++++++++--------------- unit_tests/test_nova_cc_contexts.py | 2 -- unit_tests/test_nova_cc_utils.py | 13 ++++++++---- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index 94557ffd..b190dbd5 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -1,7 +1,7 @@ from charmhelpers.core.hookenv import ( - config, relation_ids, relation_set, log, ERROR, + relation_ids, relation_set, log, ERROR, unit_get, related_units, relation_get, relations_for_id) - +from charmhelpers.core import hookenv from charmhelpers.fetch import apt_install, filter_installed_packages from charmhelpers.contrib.openstack import context, neutron, utils @@ -181,14 +181,14 @@ def canonical_url(vip_setting='vip'): if https(): scheme = 'https' - if config('prefer-ipv6'): + if hookenv.config('prefer-ipv6'): if is_clustered(): - addr = '[%s]' % config(vip_setting) + addr = '[%s]' % hookenv.config(vip_setting) else: - addr = '[%s]' % get_ipv6_addr(exc_list=[config('vip')])[0] + addr = '[%s]' % get_ipv6_addr(exc_list=[hookenv.config('vip')])[0] else: if is_clustered(): - addr = config(vip_setting) + addr = hookenv.config(vip_setting) else: addr = unit_get('private-address') @@ -209,8 +209,8 @@ class NeutronCCContext(context.NeutronContext): @property def neutron_security_groups(self): - sec_groups = (config('neutron-security-groups') or - config('quantum-security-groups')) + sec_groups = (hookenv.config('neutron-security-groups') or + hookenv.config('quantum-security-groups')) return sec_groups.lower() == 'yes' def _ensure_packages(self): @@ -220,9 +220,9 @@ class NeutronCCContext(context.NeutronContext): def __call__(self): ctxt = super(NeutronCCContext, self).__call__() - ctxt['external_network'] = config('neutron-external-network') - if config('quantum-plugin') in ['nvp', 'nsx']: - _config = config() + ctxt['external_network'] = hookenv.config('neutron-external-network') + if hookenv.config('quantum-plugin') in ['nvp', 'nsx']: + _config = hookenv.config() for k, v in _config.iteritems(): if k.startswith('nvp'): ctxt[k.replace('-', '_')] = v @@ -251,7 +251,7 @@ class IdentityServiceContext(context.IdentityServiceContext): ctxt['service_port'] ) ctxt['keystone_ec2_url'] = ec2_tokens - ctxt['region'] = config('region') + ctxt['region'] = hookenv.config('region') return ctxt @@ -265,21 +265,21 @@ class NeutronPostgresqlDBContext(context.PostgresqlDBContext): def __init__(self): super(NeutronPostgresqlDBContext, - self).__init__(config('neutron-database')) + self).__init__(hookenv.config('neutron-database')) class NovaConfigContext(context.WorkerConfigContext): def __call__(self): ctxt = super(NovaConfigContext, self).__call__() - ctxt['cpu_allocation_ratio'] = config('cpu-allocation-ratio') - ctxt['ram_allocation_ratio'] = config('ram-allocation-ratio') + ctxt['cpu_allocation_ratio'] = hookenv.config('cpu-allocation-ratio') + ctxt['ram_allocation_ratio'] = hookenv.config('ram-allocation-ratio') return ctxt class NovaIPv6Context(context.BindHostContext): def __call__(self): ctxt = super(NovaIPv6Context, self).__call__() - ctxt['use_ipv6'] = config('prefer-ipv6') + ctxt['use_ipv6'] = hookenv.config('prefer-ipv6') return ctxt diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py index 1945d949..1f4660ff 100644 --- a/unit_tests/test_nova_cc_contexts.py +++ b/unit_tests/test_nova_cc_contexts.py @@ -14,7 +14,6 @@ TO_PATCH = [ 'relation_ids', 'relation_get', 'related_units', - 'config', 'log', 'unit_get', 'relations_for_id', @@ -30,7 +29,6 @@ class NovaComputeContextTests(CharmTestCase): def setUp(self): super(NovaComputeContextTests, self).setUp(context, TO_PATCH) self.relation_get.side_effect = self.test_relation.get - self.config.side_effect = self.test_config.get self.log.side_effect = fake_log @mock.patch.object(utils, 'os_release') diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index 7351a2ec..6c9864c5 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -155,8 +155,9 @@ class NovaCCUtilsTests(CharmTestCase): _map = utils.resource_map() return _map + @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_resource_map_quantum(self, subcontext): + def test_resource_map_quantum(self, subcontext, config_): self.is_relation_made.return_value = False self._resource_map(network_manager='quantum') _map = utils.resource_map() @@ -167,8 +168,9 @@ class NovaCCUtilsTests(CharmTestCase): ] [self.assertIn(q_conf, _map.keys()) for q_conf in confs] + @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_resource_map_neutron(self, subcontext): + def test_resource_map_neutron(self, subcontext, config_): self.is_relation_made.return_value = False self._resource_map(network_manager='neutron') _map = utils.resource_map() @@ -259,9 +261,11 @@ class NovaCCUtilsTests(CharmTestCase): for service in console_services: self.assertIn(service, _map['/etc/nova/nova.conf']['services']) + @patch('charmhelpers.core.hookenv.config') @patch('os.path.exists') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_restart_map_api_before_frontends(self, subcontext, _exists): + def test_restart_map_api_before_frontends(self, subcontext, _exists, + config_): self.is_relation_made.return_value = False _exists.return_value = False self._resource_map(network_manager='neutron') @@ -303,8 +307,9 @@ class NovaCCUtilsTests(CharmTestCase): pkgs = utils.determine_packages() self.assertIn('quantum-server', pkgs) + @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_determine_packages_neutron(self, subcontext): + def test_determine_packages_neutron(self, subcontext, config_): self.is_relation_made.return_value = False self._resource_map(network_manager='neutron') pkgs = utils.determine_packages() From 85562f5ef4b91704946e718e308855155958efb9 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Thu, 20 Nov 2014 11:37:06 -0300 Subject: [PATCH 06/13] Revert "Changed the way charmhelpers.core.hookenv.config is imported" --- hooks/nova_cc_context.py | 32 ++++++++++++++--------------- unit_tests/test_nova_cc_contexts.py | 2 ++ unit_tests/test_nova_cc_utils.py | 13 ++++-------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index b190dbd5..94557ffd 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -1,7 +1,7 @@ from charmhelpers.core.hookenv import ( - relation_ids, relation_set, log, ERROR, + config, relation_ids, relation_set, log, ERROR, unit_get, related_units, relation_get, relations_for_id) -from charmhelpers.core import hookenv + from charmhelpers.fetch import apt_install, filter_installed_packages from charmhelpers.contrib.openstack import context, neutron, utils @@ -181,14 +181,14 @@ def canonical_url(vip_setting='vip'): if https(): scheme = 'https' - if hookenv.config('prefer-ipv6'): + if config('prefer-ipv6'): if is_clustered(): - addr = '[%s]' % hookenv.config(vip_setting) + addr = '[%s]' % config(vip_setting) else: - addr = '[%s]' % get_ipv6_addr(exc_list=[hookenv.config('vip')])[0] + addr = '[%s]' % get_ipv6_addr(exc_list=[config('vip')])[0] else: if is_clustered(): - addr = hookenv.config(vip_setting) + addr = config(vip_setting) else: addr = unit_get('private-address') @@ -209,8 +209,8 @@ class NeutronCCContext(context.NeutronContext): @property def neutron_security_groups(self): - sec_groups = (hookenv.config('neutron-security-groups') or - hookenv.config('quantum-security-groups')) + sec_groups = (config('neutron-security-groups') or + config('quantum-security-groups')) return sec_groups.lower() == 'yes' def _ensure_packages(self): @@ -220,9 +220,9 @@ class NeutronCCContext(context.NeutronContext): def __call__(self): ctxt = super(NeutronCCContext, self).__call__() - ctxt['external_network'] = hookenv.config('neutron-external-network') - if hookenv.config('quantum-plugin') in ['nvp', 'nsx']: - _config = hookenv.config() + ctxt['external_network'] = config('neutron-external-network') + if config('quantum-plugin') in ['nvp', 'nsx']: + _config = config() for k, v in _config.iteritems(): if k.startswith('nvp'): ctxt[k.replace('-', '_')] = v @@ -251,7 +251,7 @@ class IdentityServiceContext(context.IdentityServiceContext): ctxt['service_port'] ) ctxt['keystone_ec2_url'] = ec2_tokens - ctxt['region'] = hookenv.config('region') + ctxt['region'] = config('region') return ctxt @@ -265,21 +265,21 @@ class NeutronPostgresqlDBContext(context.PostgresqlDBContext): def __init__(self): super(NeutronPostgresqlDBContext, - self).__init__(hookenv.config('neutron-database')) + self).__init__(config('neutron-database')) class NovaConfigContext(context.WorkerConfigContext): def __call__(self): ctxt = super(NovaConfigContext, self).__call__() - ctxt['cpu_allocation_ratio'] = hookenv.config('cpu-allocation-ratio') - ctxt['ram_allocation_ratio'] = hookenv.config('ram-allocation-ratio') + ctxt['cpu_allocation_ratio'] = config('cpu-allocation-ratio') + ctxt['ram_allocation_ratio'] = config('ram-allocation-ratio') return ctxt class NovaIPv6Context(context.BindHostContext): def __call__(self): ctxt = super(NovaIPv6Context, self).__call__() - ctxt['use_ipv6'] = hookenv.config('prefer-ipv6') + ctxt['use_ipv6'] = config('prefer-ipv6') return ctxt diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py index 1f4660ff..1945d949 100644 --- a/unit_tests/test_nova_cc_contexts.py +++ b/unit_tests/test_nova_cc_contexts.py @@ -14,6 +14,7 @@ TO_PATCH = [ 'relation_ids', 'relation_get', 'related_units', + 'config', 'log', 'unit_get', 'relations_for_id', @@ -29,6 +30,7 @@ class NovaComputeContextTests(CharmTestCase): def setUp(self): super(NovaComputeContextTests, self).setUp(context, TO_PATCH) self.relation_get.side_effect = self.test_relation.get + self.config.side_effect = self.test_config.get self.log.side_effect = fake_log @mock.patch.object(utils, 'os_release') diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index 6c9864c5..7351a2ec 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -155,9 +155,8 @@ class NovaCCUtilsTests(CharmTestCase): _map = utils.resource_map() return _map - @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_resource_map_quantum(self, subcontext, config_): + def test_resource_map_quantum(self, subcontext): self.is_relation_made.return_value = False self._resource_map(network_manager='quantum') _map = utils.resource_map() @@ -168,9 +167,8 @@ class NovaCCUtilsTests(CharmTestCase): ] [self.assertIn(q_conf, _map.keys()) for q_conf in confs] - @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_resource_map_neutron(self, subcontext, config_): + def test_resource_map_neutron(self, subcontext): self.is_relation_made.return_value = False self._resource_map(network_manager='neutron') _map = utils.resource_map() @@ -261,11 +259,9 @@ class NovaCCUtilsTests(CharmTestCase): for service in console_services: self.assertIn(service, _map['/etc/nova/nova.conf']['services']) - @patch('charmhelpers.core.hookenv.config') @patch('os.path.exists') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_restart_map_api_before_frontends(self, subcontext, _exists, - config_): + def test_restart_map_api_before_frontends(self, subcontext, _exists): self.is_relation_made.return_value = False _exists.return_value = False self._resource_map(network_manager='neutron') @@ -307,9 +303,8 @@ class NovaCCUtilsTests(CharmTestCase): pkgs = utils.determine_packages() self.assertIn('quantum-server', pkgs) - @patch('charmhelpers.core.hookenv.config') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_determine_packages_neutron(self, subcontext, config_): + def test_determine_packages_neutron(self, subcontext): self.is_relation_made.return_value = False self._resource_map(network_manager='neutron') pkgs = utils.determine_packages() From b61604b4d90dd8622331b0ece85a60e28da6753a Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Thu, 20 Nov 2014 12:07:29 -0300 Subject: [PATCH 07/13] Patch nova_cc_utils config() before it's imported by nova_cc_context --- unit_tests/test_nova_cc_contexts.py | 14 ++++++++++++++ unit_tests/test_nova_cc_hooks.py | 1 + 2 files changed, 15 insertions(+) diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py index 1945d949..c777b7d3 100644 --- a/unit_tests/test_nova_cc_contexts.py +++ b/unit_tests/test_nova_cc_contexts.py @@ -1,6 +1,20 @@ from __future__ import print_function import mock + +##### +# NOTE(freyes): this is a workaround to patch config() function imported by +# nova_cc_utils before it gets a reference to the actual config() provided by +# hookenv module. +from charmhelpers.core import hookenv +_conf = hookenv.config +hookenv.config = mock.MagicMock() +import nova_cc_utils as _utils +# this assert is a double check + to avoid pep8 warning +assert _utils.config == hookenv.config +hookenv.config = _conf +##### + import nova_cc_context as context from charmhelpers.contrib.openstack import utils diff --git a/unit_tests/test_nova_cc_hooks.py b/unit_tests/test_nova_cc_hooks.py index a2dc4d84..1aef9ffe 100644 --- a/unit_tests/test_nova_cc_hooks.py +++ b/unit_tests/test_nova_cc_hooks.py @@ -1,6 +1,7 @@ from mock import MagicMock, patch, call from test_utils import CharmTestCase, patch_open import os + with patch('charmhelpers.core.hookenv.config') as config: config.return_value = 'neutron' import nova_cc_utils as utils From b4e6cf2f5b226e8d35fc2f03b4f0824c8759e342 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Thu, 20 Nov 2014 12:13:57 -0300 Subject: [PATCH 08/13] Format message, set proper level and include exception --- hooks/nova_cc_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index 94557ffd..bbbcc88d 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -295,7 +295,8 @@ class InstanceConsoleContext(context.OSContextGenerator): servers.append({'private-address': rel['private-address'], 'port': rel['port']}) except Exception as ex: - log(str(ex)) + log("Couldn't get caching servers: {}".format(str(ex)), + level='WARNING') servers = [] ctxt['memcached_servers'] = servers From 73cd15bebf003c2ea93e6883a611d92632c25826 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Thu, 20 Nov 2014 13:49:23 -0300 Subject: [PATCH 09/13] Renamed relation from 'cache' to 'memcache' --- hooks/{cache-relation-broken => memcache-relation-broken} | 0 .../{cache-relation-changed => memcache-relation-changed} | 0 ...cache-relation-departed => memcache-relation-departed} | 0 hooks/{cache-relation-joined => memcache-relation-joined} | 0 hooks/nova_cc_hooks.py | 8 ++++---- metadata.yaml | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename hooks/{cache-relation-broken => memcache-relation-broken} (100%) rename hooks/{cache-relation-changed => memcache-relation-changed} (100%) rename hooks/{cache-relation-departed => memcache-relation-departed} (100%) rename hooks/{cache-relation-joined => memcache-relation-joined} (100%) diff --git a/hooks/cache-relation-broken b/hooks/memcache-relation-broken similarity index 100% rename from hooks/cache-relation-broken rename to hooks/memcache-relation-broken diff --git a/hooks/cache-relation-changed b/hooks/memcache-relation-changed similarity index 100% rename from hooks/cache-relation-changed rename to hooks/memcache-relation-changed diff --git a/hooks/cache-relation-departed b/hooks/memcache-relation-departed similarity index 100% rename from hooks/cache-relation-departed rename to hooks/memcache-relation-departed diff --git a/hooks/cache-relation-joined b/hooks/memcache-relation-joined similarity index 100% rename from hooks/cache-relation-joined rename to hooks/memcache-relation-joined diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 5fe9eea7..cd6fa6f7 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -852,10 +852,10 @@ def neutron_api_relation_broken(): quantum_joined(rid=rid) -@hooks.hook('cache-relation-joined', - 'cache-relation-departed', - 'cache-relation-changed', - 'cache-relation-broken') +@hooks.hook('memcache-relation-joined', + 'memcache-relation-departed', + 'memcache-relation-changed', + 'memcache-relation-broken') @restart_on_change(restart_map()) def memcached_joined(): CONFIGS.write(NOVA_CONF) diff --git a/metadata.yaml b/metadata.yaml index be2440de..f277b1cd 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -40,7 +40,7 @@ requires: nova-vmware: interface: nova-vmware scope: container - cache: + memcache: interface: memcache peers: cluster: From 3482bf647a0210bc1f9bf79664fb899868150e9e Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Thu, 20 Nov 2014 13:51:44 -0300 Subject: [PATCH 10/13] Renamed relation from 'cache' to 'memcache' --- hooks/{cache-relation-broken => memcache-relation-broken} | 0 .../{cache-relation-changed => memcache-relation-changed} | 0 ...cache-relation-departed => memcache-relation-departed} | 0 hooks/{cache-relation-joined => memcache-relation-joined} | 0 hooks/nova_cc_context.py | 2 +- hooks/nova_cc_hooks.py | 8 ++++---- metadata.yaml | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename hooks/{cache-relation-broken => memcache-relation-broken} (100%) rename hooks/{cache-relation-changed => memcache-relation-changed} (100%) rename hooks/{cache-relation-departed => memcache-relation-departed} (100%) rename hooks/{cache-relation-joined => memcache-relation-joined} (100%) diff --git a/hooks/cache-relation-broken b/hooks/memcache-relation-broken similarity index 100% rename from hooks/cache-relation-broken rename to hooks/memcache-relation-broken diff --git a/hooks/cache-relation-changed b/hooks/memcache-relation-changed similarity index 100% rename from hooks/cache-relation-changed rename to hooks/memcache-relation-changed diff --git a/hooks/cache-relation-departed b/hooks/memcache-relation-departed similarity index 100% rename from hooks/cache-relation-departed rename to hooks/memcache-relation-departed diff --git a/hooks/cache-relation-joined b/hooks/memcache-relation-joined similarity index 100% rename from hooks/cache-relation-joined rename to hooks/memcache-relation-joined diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index bbbcc88d..75c97e1b 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -290,7 +290,7 @@ class InstanceConsoleContext(context.OSContextGenerator): ctxt = {} servers = [] try: - for rid in relation_ids('cache'): + for rid in relation_ids('memcache'): for rel in relations_for_id(rid): servers.append({'private-address': rel['private-address'], 'port': rel['port']}) diff --git a/hooks/nova_cc_hooks.py b/hooks/nova_cc_hooks.py index 5fe9eea7..cd6fa6f7 100755 --- a/hooks/nova_cc_hooks.py +++ b/hooks/nova_cc_hooks.py @@ -852,10 +852,10 @@ def neutron_api_relation_broken(): quantum_joined(rid=rid) -@hooks.hook('cache-relation-joined', - 'cache-relation-departed', - 'cache-relation-changed', - 'cache-relation-broken') +@hooks.hook('memcache-relation-joined', + 'memcache-relation-departed', + 'memcache-relation-changed', + 'memcache-relation-broken') @restart_on_change(restart_map()) def memcached_joined(): CONFIGS.write(NOVA_CONF) diff --git a/metadata.yaml b/metadata.yaml index be2440de..f277b1cd 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -40,7 +40,7 @@ requires: nova-vmware: interface: nova-vmware scope: container - cache: + memcache: interface: memcache peers: cluster: From 2bffd104ebb46954ad8de106142a63660c65c19d Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Wed, 26 Nov 2014 18:24:02 -0300 Subject: [PATCH 11/13] Added IPv6 support Added test to check that IPv6 addresses are properly formatted. --- hooks/nova_cc_context.py | 8 ++++++-- unit_tests/test_nova_cc_contexts.py | 23 +++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index 75c97e1b..25f4784e 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -13,7 +13,8 @@ from charmhelpers.contrib.hahelpers.cluster import ( ) from charmhelpers.contrib.network.ip import ( - get_ipv6_addr + get_ipv6_addr, + format_ipv6_addr ) @@ -292,7 +293,10 @@ class InstanceConsoleContext(context.OSContextGenerator): try: for rid in relation_ids('memcache'): for rel in relations_for_id(rid): - servers.append({'private-address': rel['private-address'], + priv_addr = rel['private-address'] + # format it as IPv6 address if neeeded + priv_addr = format_ipv6_addr(priv_addr) or priv_addr + servers.append({'private-address': priv_addr, 'port': rel['port']}) except Exception as ex: log("Couldn't get caching servers: {}".format(str(ex)), diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py index c777b7d3..33ea3d44 100644 --- a/unit_tests/test_nova_cc_contexts.py +++ b/unit_tests/test_nova_cc_contexts.py @@ -48,7 +48,8 @@ class NovaComputeContextTests(CharmTestCase): self.log.side_effect = fake_log @mock.patch.object(utils, 'os_release') - def test_instance_console_context_without_memcache(self, os_release): + @mock.patch('charmhelpers.contrib.network.ip.log') + def test_instance_console_context_without_memcache(self, os_release, log_): self.unit_get.return_value = '127.0.0.1' self.relation_ids.return_value = 'cache:0' self.related_units.return_value = 'memcached/0' @@ -58,10 +59,24 @@ class NovaComputeContextTests(CharmTestCase): instance_console()) @mock.patch.object(utils, 'os_release') - def test_instance_console_context_with_memcache(self, os_release): - memcached_servers = [{'private-address': '127.0.1.1', + @mock.patch('charmhelpers.contrib.network.ip.log') + def test_instance_console_context_with_memcache(self, os_release, log_): + self.check_instance_console_context_with_memcache(os_release, + '127.0.1.1', + '127.0.1.1') + + @mock.patch.object(utils, 'os_release') + @mock.patch('charmhelpers.contrib.network.ip.log') + def test_instance_console_context_with_memcache_ipv6(self, os_release, + log_): + self.check_instance_console_context_with_memcache(os_release, '::1', + '[::1]') + + def check_instance_console_context_with_memcache(self, os_release, ip, + formated_ip): + memcached_servers = [{'private-address': formated_ip, 'port': '11211'}] - self.unit_get.return_value = '127.0.0.1' + self.unit_get.return_value = ip self.relation_ids.return_value = ['cache:0'] self.relations_for_id.return_value = memcached_servers self.related_units.return_value = 'memcached/0' From fd40c349b2e3e4d42ac0aed0f20300b6716cc236 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Mon, 15 Dec 2014 13:47:17 -0300 Subject: [PATCH 12/13] Replace "Couldn't get caching servers" with "Couldn't get memcache servers" --- hooks/nova_cc_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index 508a3865..19a35320 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -317,7 +317,7 @@ class InstanceConsoleContext(context.OSContextGenerator): servers.append({'private-address': priv_addr, 'port': rel['port']}) except Exception as ex: - log("Couldn't get caching servers: {}".format(str(ex)), + log("Couldn't get memcache servers: {}".format(str(ex)), level='WARNING') servers = [] From ec00658edf7f94b2a2c79a6b43a693e49dc22a12 Mon Sep 17 00:00:00 2001 From: Felipe Reyes Date: Tue, 16 Dec 2014 11:08:58 -0300 Subject: [PATCH 13/13] Refactor the way memcached_servers config is put in the templates Instead of formatting the string with Jinja2, it's formatted with python and passed to the template as a string. --- hooks/nova_cc_context.py | 3 ++- templates/grizzly/nova.conf | 2 +- templates/havana/nova.conf | 2 +- templates/icehouse/nova.conf | 2 +- unit_tests/test_nova_cc_contexts.py | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hooks/nova_cc_context.py b/hooks/nova_cc_context.py index 19a35320..d61bf273 100644 --- a/hooks/nova_cc_context.py +++ b/hooks/nova_cc_context.py @@ -321,5 +321,6 @@ class InstanceConsoleContext(context.OSContextGenerator): level='WARNING') servers = [] - ctxt['memcached_servers'] = servers + ctxt['memcached_servers'] = ','.join( + ["%s:%s" % (s['private-address'], s['port']) for s in servers]) return ctxt diff --git a/templates/grizzly/nova.conf b/templates/grizzly/nova.conf index e67c32fc..4921d893 100644 --- a/templates/grizzly/nova.conf +++ b/templates/grizzly/nova.conf @@ -22,7 +22,7 @@ auth_strategy=keystone compute_driver=libvirt.LibvirtDriver {% if memcached_servers %} -memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +memcached_servers = {{ memcached_servers }} {% endif %} {% if keystone_ec2_url -%} diff --git a/templates/havana/nova.conf b/templates/havana/nova.conf index 7cbf0ef0..77b88110 100644 --- a/templates/havana/nova.conf +++ b/templates/havana/nova.conf @@ -28,7 +28,7 @@ use_syslog={{ use_syslog }} my_ip = {{ host_ip }} {% if memcached_servers %} -memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +memcached_servers = {{ memcached_servers }} {% endif %} {% if keystone_ec2_url -%} diff --git a/templates/icehouse/nova.conf b/templates/icehouse/nova.conf index 3e0d0883..67385124 100644 --- a/templates/icehouse/nova.conf +++ b/templates/icehouse/nova.conf @@ -39,7 +39,7 @@ use_syslog={{ use_syslog }} my_ip = {{ host_ip }} {% if memcached_servers %} -memcached_servers = {%for s in memcached_servers %}{% if loop.index0 != 0 %},{% endif %}{{s['private-address']}}:{{s['port']}}{% endfor %} +memcached_servers = {{ memcached_servers }} {% endif %} {% if keystone_ec2_url -%} diff --git a/unit_tests/test_nova_cc_contexts.py b/unit_tests/test_nova_cc_contexts.py index 33ea3d44..76486f34 100644 --- a/unit_tests/test_nova_cc_contexts.py +++ b/unit_tests/test_nova_cc_contexts.py @@ -55,7 +55,7 @@ class NovaComputeContextTests(CharmTestCase): self.related_units.return_value = 'memcached/0' instance_console = context.InstanceConsoleContext() os_release.return_value = 'icehouse' - self.assertEqual({'memcached_servers': []}, + self.assertEqual({'memcached_servers': ''}, instance_console()) @mock.patch.object(utils, 'os_release') @@ -83,5 +83,5 @@ class NovaComputeContextTests(CharmTestCase): instance_console = context.InstanceConsoleContext() os_release.return_value = 'icehouse' self.maxDiff = None - self.assertEqual({'memcached_servers': memcached_servers}, + self.assertEqual({'memcached_servers': "%s:11211" % (formated_ip, )}, instance_console())