[freyes,r=hopem]

Install python-memcache, configure nova.conf adding the key
memcached_servers when a relationship with memcached service
is established.

If multiple units of memcached are available, all of them
are used i.e. memcached_servers = host1:port1,host2:port,host3:port3

To secure memcached access this relies in the memcached charm
ability to use iptables rules to only allow access to related
machines.

Closes-Bug: 1386271
This commit is contained in:
Edward Hope-Morley 2014-12-17 18:20:59 +00:00
commit c42017fe2c
14 changed files with 146 additions and 1 deletions

View File

@ -0,0 +1 @@
nova_cc_hooks.py

View File

@ -0,0 +1 @@
nova_cc_hooks.py

View File

@ -0,0 +1 @@
nova_cc_hooks.py

View File

@ -0,0 +1 @@
nova_cc_hooks.py

View File

@ -6,6 +6,7 @@ from charmhelpers.core.hookenv import (
ERROR,
unit_get,
related_units,
relations_for_id,
relation_get,
)
from charmhelpers.fetch import (
@ -299,3 +300,24 @@ 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('memcache'):
for rel in relations_for_id(rid):
priv_addr = rel['private-address']
# Format it as IPv6 address if needed
priv_addr = format_ipv6_addr(priv_addr) or priv_addr
servers.append("%s:%s" % (priv_addr, rel['port']))
except Exception as ex:
log("Could not get memcache servers: %s" % (ex), level='WARNING')
servers = []
ctxt['memcached_servers'] = ','.join(servers)
return ctxt

View File

@ -849,6 +849,15 @@ def neutron_api_relation_broken():
quantum_joined(rid=rid)
@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)
def main():
try:
hooks.execute(sys.argv)

View File

@ -69,6 +69,7 @@ BASE_PACKAGES = [
'python-psutil',
'python-six',
'uuid',
'python-memcache',
]
BASE_SERVICES = [
@ -124,7 +125,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],

View File

@ -40,6 +40,8 @@ requires:
nova-vmware:
interface: nova-vmware
scope: container
memcache:
interface: memcache
peers:
cluster:
interface: nova-ha

View File

@ -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 = {{ memcached_servers }}
{% endif %}
{% if keystone_ec2_url -%}
keystone_ec2_url = {{ keystone_ec2_url }}
{% endif -%}

View File

@ -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 = {{ memcached_servers }}
{% endif %}
{% if keystone_ec2_url -%}
keystone_ec2_url = {{ keystone_ec2_url }}
{% endif -%}

View File

@ -27,6 +27,10 @@ cpu_allocation_ratio = {{ cpu_allocation_ratio }}
use_syslog={{ use_syslog }}
my_ip = {{ host_ip }}
{% if memcached_servers %}
memcached_servers = {{ memcached_servers }}
{% endif %}
{% if keystone_ec2_url -%}
keystone_ec2_url = {{ keystone_ec2_url }}
{% endif -%}

View File

@ -38,6 +38,10 @@ ram_allocation_ratio = {{ ram_allocation_ratio }}
use_syslog={{ use_syslog }}
my_ip = {{ host_ip }}
{% if memcached_servers %}
memcached_servers = {{ memcached_servers }}
{% endif %}
{% if keystone_ec2_url -%}
keystone_ec2_url = {{ keystone_ec2_url }}
{% endif -%}

View File

@ -0,0 +1,87 @@
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
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')
@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'
instance_console = context.InstanceConsoleContext()
os_release.return_value = 'icehouse'
self.assertEqual({'memcached_servers': ''},
instance_console())
@mock.patch.object(utils, 'os_release')
@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 = ip
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': "%s:11211" % (formated_ip, )},
instance_console())

View File

@ -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