diff --git a/config.yaml b/config.yaml index 04afec7f..60b500c4 100644 --- a/config.yaml +++ b/config.yaml @@ -153,3 +153,15 @@ options: description: | Connect timeout configuration in ms for haproxy, used in HA configurations. If not provided, default value of 5000ms is used. + prefer-ipv6: + type: boolean + default: False + description: | + If True enables IPv6 support. The charm will expect network interfaces + to be configured with an IPv6 address. If set to False (default) IPv4 + is expected. + . + NOTE: these charms do not currently support IPv6 privacy extension. In + order for this charm to function correctly, the privacy extension must be + disabled and a non-temporary address must be configured/available on + your network interface. diff --git a/hooks/ceph_radosgw_context.py b/hooks/ceph_radosgw_context.py index 61276651..73558b17 100644 --- a/hooks/ceph_radosgw_context.py +++ b/hooks/ceph_radosgw_context.py @@ -1,3 +1,11 @@ +import os +import re +import socket +import tempfile +import glob +import shutil +import subprocess + from charmhelpers.contrib.openstack import context from charmhelpers.contrib.hahelpers.cluster import ( determine_api_port, @@ -5,17 +13,69 @@ from charmhelpers.contrib.hahelpers.cluster import ( ) from charmhelpers.core.host import cmp_pkgrevno from charmhelpers.core.hookenv import ( + DEBUG, WARNING, config, log, relation_ids, related_units, relation_get, - unit_get, + status_set, ) -import os -import socket -import dns.resolver +from charmhelpers.contrib.network.ip import ( + format_ipv6_addr, + get_host_ip, + get_ipv6_addr, +) + + +def is_apache_24(): + if os.path.exists('/etc/apache2/conf-available'): + return True + else: + return False + + +class ApacheContext(context.OSContextGenerator): + interfaces = ['http'] + service_namespace = 'ceph-radosgw' + + def __call__(self): + ctxt = {} + if config('use-embedded-webserver'): + log("Skipping ApacheContext since we are using the embedded " + "webserver") + return {} + + status_set('maintenance', 'configuring apache') + + src = 'files/www/*' + dst = '/var/www/' + log("Installing www scripts", level=DEBUG) + try: + for x in glob.glob(src): + shutil.copy(x, dst) + except IOError as e: + log("Error copying files from '%s' to '%s': %s" % (src, dst, e), + level=WARNING) + + try: + subprocess.check_call(['a2enmod', 'fastcgi']) + subprocess.check_call(['a2enmod', 'rewrite']) + except subprocess.CalledProcessError as e: + log("Error enabling apache modules - %s" % e, level=WARNING) + + try: + if is_apache_24(): + subprocess.check_call(['a2dissite', '000-default']) + else: + subprocess.check_call(['a2dissite', 'default']) + except subprocess.CalledProcessError as e: + log("Error disabling apache sites - %s" % e, level=WARNING) + + ctxt['hostname'] = socket.gethostname() + ctxt['port'] = determine_api_port(config('port'), singlenode_mode=True) + return ctxt class HAProxyContext(context.HAProxyContext): @@ -66,24 +126,60 @@ class IdentityServiceContext(context.IdentityServiceContext): return {} +def ensure_host_resolvable_v6(hostname): + """Ensure that we can resolve our hostname to an IPv6 address by adding it + to /etc/hosts if it is not already resolvable. + """ + try: + socket.getaddrinfo(hostname, None, socket.AF_INET6) + except socket.gaierror: + log("Host '%s' is not ipv6 resolvable - adding to /etc/hosts" % + hostname, level=DEBUG) + else: + log("Host '%s' appears to be ipv6 resolvable" % (hostname), + level=DEBUG) + return + + # This must be the backend address used by haproxy + host_addr = get_ipv6_addr(exc_list=[config('vip')])[0] + dtmp = tempfile.mkdtemp() + try: + tmp_hosts = os.path.join(dtmp, 'hosts') + shutil.copy('/etc/hosts', tmp_hosts) + with open(tmp_hosts, 'a+') as fd: + lines = fd.readlines() + for line in lines: + key = "^%s\s+" % (host_addr) + if re.search(key, line): + break + else: + fd.write("%s\t%s\n" % (host_addr, hostname)) + + os.rename(tmp_hosts, '/etc/hosts') + finally: + shutil.rmtree(dtmp) + + class MonContext(context.OSContextGenerator): interfaces = ['ceph-radosgw'] def __call__(self): if not relation_ids('mon'): return {} - hosts = [] + mon_hosts = [] auths = [] for relid in relation_ids('mon'): for unit in related_units(relid): ceph_public_addr = relation_get('ceph-public-address', unit, relid) if ceph_public_addr: - host_ip = self.get_host_ip(ceph_public_addr) - hosts.append('{}:6789'.format(host_ip)) + host_ip = format_ipv6_addr(ceph_public_addr) or \ + get_host_ip(ceph_public_addr) + mon_hosts.append('{}:6789'.format(host_ip)) _auth = relation_get('auth', unit, relid) if _auth: auths.append(_auth) + if len(set(auths)) != 1: e = ("Inconsistent or absent auth returned by mon units. Setting " "auth_supported to 'none'") @@ -91,17 +187,28 @@ class MonContext(context.OSContextGenerator): auth = 'none' else: auth = auths[0] - hosts.sort() + + # /etc/init.d/radosgw mandates that a dns name is used for this + # parameter so ensure that address is resolvable + host = socket.gethostname() + if config('prefer-ipv6'): + ensure_host_resolvable_v6(host) + + port = determine_apache_port(config('port'), singlenode_mode=True) + if config('prefer-ipv6'): + port = "[::]:%s" % (port) + + mon_hosts.sort() ctxt = { 'auth_supported': auth, - 'mon_hosts': ' '.join(hosts), - 'hostname': socket.gethostname(), + 'mon_hosts': ' '.join(mon_hosts), + 'hostname': host, 'old_auth': cmp_pkgrevno('radosgw', "0.51") < 0, 'use_syslog': str(config('use-syslog')).lower(), 'embedded_webserver': config('use-embedded-webserver'), 'loglevel': config('loglevel'), - 'port': determine_apache_port(config('port'), - singlenode_mode=True) + 'port': port, + 'ipv6': config('prefer-ipv6') } certs_path = '/var/lib/ceph/nss' @@ -121,17 +228,3 @@ class MonContext(context.OSContextGenerator): return ctxt return {} - - def get_host_ip(self, hostname=None): - try: - if not hostname: - hostname = unit_get('private-address') - # Test to see if already an IPv4 address - socket.inet_aton(hostname) - return hostname - except socket.error: - # This may throw an NXDOMAIN exception; in which case - # things are badly broken so just let it kill the hook - answers = dns.resolver.query(hostname, 'A') - if answers: - return answers[0].address diff --git a/hooks/hooks.py b/hooks/hooks.py index e88c633e..54ecf6e2 100755 --- a/hooks/hooks.py +++ b/hooks/hooks.py @@ -1,17 +1,16 @@ #!/usr/bin/python - # -# Copyright 2012 Canonical Ltd. +# Copyright 2016 Canonical Ltd. # # Authors: # James Page +# Edward Hope-Morley # -import shutil +import os import subprocess import sys -import glob -import os + import ceph from charmhelpers.core.hookenv import ( @@ -39,27 +38,17 @@ from charmhelpers.core.host import ( lsb_release, restart_on_change, ) -from charmhelpers.contrib.hahelpers.cluster import ( - determine_apache_port, -) -from utils import ( - render_template, - enable_pocket, - is_apache_24, - CEPHRG_HA_RES, - register_configs, - REQUIRED_INTERFACES, - check_optional_relations, -) from charmhelpers.payload.execd import execd_preinstall from charmhelpers.core.host import ( cmp_pkgrevno, mkdir, ) - from charmhelpers.contrib.network.ip import ( + format_ipv6_addr, + get_ipv6_addr, get_iface_for_address, get_netmask_for_address, + is_ipv6, ) from charmhelpers.contrib.openstack.ip import ( canonical_url, @@ -72,18 +61,17 @@ from charmhelpers.contrib.storage.linux.ceph import ( send_request_if_needed, is_request_complete, ) - -APACHE_PORTS_CONF = '/etc/apache2/ports.conf' +from utils import ( + enable_pocket, + CEPHRG_HA_RES, + register_configs, + REQUIRED_INTERFACES, + check_optional_relations, + setup_ipv6, +) hooks = Hooks() CONFIGS = register_configs() - - -def install_www_scripts(): - for x in glob.glob('files/www/*'): - shutil.copy(x, '/var/www/') - - NSS_DIR = '/var/lib/ceph/nss' @@ -145,43 +133,6 @@ def install(): os.makedirs('/etc/ceph') -def emit_apacheconf(): - apachecontext = { - "hostname": unit_get('private-address'), - "port": determine_apache_port(config('port'), singlenode_mode=True) - } - site_conf = '/etc/apache2/sites-available/rgw' - if is_apache_24(): - site_conf = '/etc/apache2/sites-available/rgw.conf' - with open(site_conf, 'w') as apacheconf: - apacheconf.write(render_template('rgw', apachecontext)) - - -def apache_sites(): - if is_apache_24(): - subprocess.check_call(['a2dissite', '000-default']) - else: - subprocess.check_call(['a2dissite', 'default']) - subprocess.check_call(['a2ensite', 'rgw']) - - -def apache_modules(): - subprocess.check_call(['a2enmod', 'fastcgi']) - subprocess.check_call(['a2enmod', 'rewrite']) - - -def apache_reload(): - subprocess.call(['service', 'apache2', 'reload']) - - -def apache_ports(): - portscontext = { - "port": determine_apache_port(config('port'), singlenode_mode=True) - } - with open(APACHE_PORTS_CONF, 'w') as portsconf: - portsconf.write(render_template('ports.conf', portscontext)) - - def setup_keystone_certs(unit=None, rid=None): """ Get CA and signing certs from Keystone used to decrypt revoked token list. @@ -213,6 +164,9 @@ def setup_keystone_certs(unit=None, rid=None): for key in required_keys: settings[key] = rdata.get(key) + if is_ipv6(settings.get('auth_host')): + settings['auth_host'] = format_ipv6_addr(settings.get('auth_host')) + if not all(settings.values()): log("Missing relation settings (%s) - skipping cert setup" % (', '.join([k for k in settings.keys() if not settings[k]])), @@ -288,19 +242,29 @@ def setup_keystone_certs(unit=None, rid=None): '/etc/haproxy/haproxy.cfg': ['haproxy']}) def config_changed(): install_packages() - CONFIGS.write_all() - if not config('use-embedded-webserver'): - status_set('maintenance', 'configuring apache') - emit_apacheconf() - install_www_scripts() - apache_sites() - apache_modules() - apache_ports() - apache_reload() + + if config('prefer-ipv6'): + status_set('maintenance', 'configuring ipv6') + setup_ipv6() for r_id in relation_ids('identity-service'): identity_changed(relid=r_id) + for r_id in relation_ids('cluster'): + cluster_joined(rid=r_id) + + CONFIGS.write_all() + + if not config('use-embedded-webserver'): + try: + subprocess.check_call(['a2ensite', 'rgw']) + except subprocess.CalledProcessError as e: + log("Error enabling apache module 'rgw' - %s" % e, level=WARNING) + + # Ensure started but do a soft reload + subprocess.call(['service', 'apache2', 'start']) + subprocess.call(['service', 'apache2', 'reload']) + @hooks.hook('mon-relation-departed', 'mon-relation-changed') @@ -373,8 +337,18 @@ def identity_changed(relid=None): restart() -@hooks.hook('cluster-relation-changed', - 'cluster-relation-joined') +@hooks.hook('cluster-relation-joined') +@restart_on_change({'/etc/haproxy/haproxy.cfg': ['haproxy']}) +def cluster_joined(rid=None): + settings = {} + if config('prefer-ipv6'): + private_addr = get_ipv6_addr(exc_list=[config('vip')])[0] + settings['private-address'] = private_addr + + relation_set(relation_id=rid, **settings) + + +@hooks.hook('cluster-relation-changed') @restart_on_change({'/etc/haproxy/haproxy.cfg': ['haproxy']}) def cluster_changed(): CONFIGS.write_all() @@ -384,17 +358,12 @@ def cluster_changed(): @hooks.hook('ha-relation-joined') def ha_relation_joined(): - # Obtain the config values necessary for the cluster config. These - # include multicast port and interface to bind to. - corosync_bindiface = config('ha-bindiface') - corosync_mcastport = config('ha-mcastport') vip = config('vip') if not vip: - log('Unable to configure hacluster as vip not provided', - level=ERROR) + log('Unable to configure hacluster as vip not provided', level=ERROR) sys.exit(1) + # Obtain resources - # SWIFT_HA_RES = 'grp_swift_vips' resources = { 'res_cephrg_haproxy': 'lsb:haproxy' } @@ -404,15 +373,25 @@ def ha_relation_joined(): vip_group = [] for vip in vip.split(): + if is_ipv6(vip): + res_rgw_vip = 'ocf:heartbeat:IPv6addr' + vip_params = 'ipv6addr' + else: + res_rgw_vip = 'ocf:heartbeat:IPaddr2' + vip_params = 'ip' + iface = get_iface_for_address(vip) + netmask = get_netmask_for_address(vip) + if iface is not None: vip_key = 'res_cephrg_{}_vip'.format(iface) - resources[vip_key] = 'ocf:heartbeat:IPaddr2' + resources[vip_key] = res_rgw_vip resource_params[vip_key] = ( - 'params ip="{vip}" cidr_netmask="{netmask}"' - ' nic="{iface}"'.format(vip=vip, + 'params {ip}="{vip}" cidr_netmask="{netmask}"' + ' nic="{iface}"'.format(ip=vip_params, + vip=vip, iface=iface, - netmask=get_netmask_for_address(vip)) + netmask=netmask) ) vip_group.append(vip_key) @@ -426,6 +405,11 @@ def ha_relation_joined(): 'cl_cephrg_haproxy': 'res_cephrg_haproxy' } + # Obtain the config values necessary for the cluster config. These + # include multicast port and interface to bind to. + corosync_bindiface = config('ha-bindiface') + corosync_mcastport = config('ha-mcastport') + relation_set(init_services=init_services, corosync_bindiface=corosync_bindiface, corosync_mcastport=corosync_mcastport, diff --git a/hooks/utils.py b/hooks/utils.py index d14c6ecb..9d6413c9 100644 --- a/hooks/utils.py +++ b/hooks/utils.py @@ -1,27 +1,45 @@ # -# Copyright 2012 Canonical Ltd. +# Copyright 2016 Canonical Ltd. # # Authors: # James Page # Paul Collins +# Edward Hope-Morley # -import socket -import re import os -import dns.resolver +import re import jinja2 + from copy import deepcopy from collections import OrderedDict -from charmhelpers.core.hookenv import unit_get, relation_ids, status_get -from charmhelpers.contrib.openstack import context, templating -from charmhelpers.contrib.openstack.utils import set_os_workload_status -from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config -from charmhelpers.core.host import cmp_pkgrevno -from charmhelpers.fetch import filter_installed_packages import ceph_radosgw_context +from charmhelpers.core.hookenv import ( + relation_ids, + status_get, +) +from charmhelpers.contrib.openstack import ( + context, + templating, +) +from charmhelpers.contrib.openstack.utils import ( + os_release, + set_os_workload_status, +) +from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config +from charmhelpers.core.host import ( + cmp_pkgrevno, + lsb_release, +) +from charmhelpers.fetch import ( + apt_install, + apt_update, + add_source, + filter_installed_packages, +) + # The interface is said to be satisfied if anyone of the interfaces in the # list has a complete context. REQUIRED_INTERFACES = { @@ -32,6 +50,9 @@ TEMPLATES_DIR = 'templates' TEMPLATES = 'templates/' HAPROXY_CONF = '/etc/haproxy/haproxy.cfg' CEPH_CONF = '/etc/ceph/ceph.conf' +APACHE_CONF = '/etc/apache2/sites-available/rgw' +APACHE_24_CONF = '/etc/apache2/sites-available/rgw.conf' +APACHE_PORTS_CONF = '/etc/apache2/ports.conf' BASE_RESOURCE_MAP = OrderedDict([ (HAPROXY_CONF, { @@ -39,6 +60,18 @@ BASE_RESOURCE_MAP = OrderedDict([ ceph_radosgw_context.HAProxyContext()], 'services': ['haproxy'], }), + (APACHE_CONF, { + 'contexts': [ceph_radosgw_context.ApacheContext()], + 'services': ['apache2'], + }), + (APACHE_24_CONF, { + 'contexts': [ceph_radosgw_context.ApacheContext()], + 'services': ['apache2'], + }), + (APACHE_PORTS_CONF, { + 'contexts': [ceph_radosgw_context.ApacheContext()], + 'services': ['apache2'], + }), (CEPH_CONF, { 'contexts': [ceph_radosgw_context.MonContext()], 'services': ['radosgw'], @@ -51,6 +84,11 @@ def resource_map(): Dynamically generate a map of resources that will be managed for a single hook execution. ''' + if os.path.exists('/etc/apache2/conf-available'): + BASE_RESOURCE_MAP.pop(APACHE_CONF) + else: + BASE_RESOURCE_MAP.pop(APACHE_24_CONF) + resource_map = deepcopy(BASE_RESOURCE_MAP) return resource_map @@ -92,28 +130,6 @@ def enable_pocket(pocket): sources.write(line) -def get_host_ip(hostname=None): - try: - if not hostname: - hostname = unit_get('private-address') - # Test to see if already an IPv4 address - socket.inet_aton(hostname) - return hostname - except socket.error: - # This may throw an NXDOMAIN exception; in which case - # things are badly broken so just let it kill the hook - answers = dns.resolver.query(hostname, 'A') - if answers: - return answers[0].address - - -def is_apache_24(): - if os.path.exists('/etc/apache2/conf-available'): - return True - else: - return False - - def check_optional_relations(configs): required_interfaces = {} if relation_ids('ha'): @@ -132,3 +148,18 @@ def check_optional_relations(configs): return status_get() else: return 'unknown', 'No optional relations' + + +def setup_ipv6(): + ubuntu_rel = lsb_release()['DISTRIB_CODENAME'].lower() + if ubuntu_rel < "trusty": + raise Exception("IPv6 is not supported in the charms for Ubuntu " + "versions less than Trusty 14.04") + + # Need haproxy >= 1.5.3 for ipv6 so for Trusty if we are <= Kilo we need to + # use trusty-backports otherwise we can use the UCA. + if ubuntu_rel == 'trusty' and os_release('ceph-common') < 'liberty': + add_source('deb http://archive.ubuntu.com/ubuntu trusty-backports ' + 'main') + apt_update(fatal=True) + apt_install('haproxy/trusty-backports', fatal=True) diff --git a/templates/ceph.conf b/templates/ceph.conf index af0fc43b..28efdeba 100644 --- a/templates/ceph.conf +++ b/templates/ceph.conf @@ -11,6 +11,9 @@ log to syslog = {{ use_syslog }} err to syslog = {{ use_syslog }} clog to syslog = {{ use_syslog }} debug rgw = {{ loglevel }}/5 +{% if ipv6 -%} +ms bind ipv6 = true +{% endif %} [client.radosgw.gateway] host = {{ hostname }} diff --git a/templates/rgw.conf b/templates/rgw.conf new file mode 100644 index 00000000..7a3e4724 --- /dev/null +++ b/templates/rgw.conf @@ -0,0 +1,25 @@ + + FastCgiExternalServer /var/www/s3gw.fcgi -socket /tmp/radosgw.sock + + + + ServerName {{ hostname }} + ServerAdmin ceph@ubuntu.com + DocumentRoot /var/www + RewriteEngine On + RewriteRule ^/([a-zA-Z0-9-_.]*)([/]?.*) /s3gw.fcgi?page=$1¶ms=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + + + Options +ExecCGI + AllowOverride All + SetHandler fastcgi-script + Order allow,deny + Allow from all + AuthBasicAuthoritative Off + + + AllowEncodedSlashes On + ErrorLog /var/log/apache2/error.log + CustomLog /var/log/apache2/access.log combined + ServerSignature Off + diff --git a/unit_tests/test_ceph_radosgw_context.py b/unit_tests/test_ceph_radosgw_context.py index 7c049afe..5071b671 100644 --- a/unit_tests/test_ceph_radosgw_context.py +++ b/unit_tests/test_ceph_radosgw_context.py @@ -13,6 +13,7 @@ TO_PATCH = [ 'related_units', 'cmp_pkgrevno', 'socket', + 'is_apache_24', ] @@ -147,8 +148,9 @@ class MonContextTest(CharmTestCase): super(MonContextTest, self).setUp(context, TO_PATCH) self.config.side_effect = self.test_config.get - def test_ctxt(self): - self.socket.gethostname.return_value = '10.0.0.10' + @patch.object(context, 'ensure_host_resolvable_v6') + def test_ctxt(self, mock_ensure_rsv_v6): + self.socket.gethostname.return_value = 'testhost' mon_ctxt = context.MonContext() addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3'] @@ -157,6 +159,7 @@ class MonContextTest(CharmTestCase): return addresses.pop() elif attr == 'auth': return 'cephx' + self.relation_get.side_effect = _relation_get self.relation_ids.return_value = ['mon:6'] self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2'] @@ -164,17 +167,26 @@ class MonContextTest(CharmTestCase): 'auth_supported': 'cephx', 'embedded_webserver': False, 'disable_100_continue': True, - 'hostname': '10.0.0.10', + 'hostname': 'testhost', 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789', 'old_auth': False, 'use_syslog': 'false', 'loglevel': 1, - 'port': 70 + 'port': 70, + 'ipv6': False } self.assertEqual(expect, mon_ctxt()) + self.assertFalse(mock_ensure_rsv_v6.called) + + self.test_config.set('prefer-ipv6', True) + addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3'] + expect['ipv6'] = True + expect['port'] = "[::]:%s" % (70) + self.assertEqual(expect, mon_ctxt()) + self.assertTrue(mock_ensure_rsv_v6.called) def test_ctxt_missing_data(self): - self.socket.gethostname.return_value = '10.0.0.10' + self.socket.gethostname.return_value = 'testhost' mon_ctxt = context.MonContext() self.relation_get.return_value = None self.relation_ids.return_value = ['mon:6'] @@ -182,7 +194,7 @@ class MonContextTest(CharmTestCase): self.assertEqual({}, mon_ctxt()) def test_ctxt_inconsistent_auths(self): - self.socket.gethostname.return_value = '10.0.0.10' + self.socket.gethostname.return_value = 'testhost' mon_ctxt = context.MonContext() addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3'] auths = ['cephx', 'cephy', 'cephz'] @@ -199,17 +211,18 @@ class MonContextTest(CharmTestCase): 'auth_supported': 'none', 'embedded_webserver': False, 'disable_100_continue': True, - 'hostname': '10.0.0.10', + 'hostname': 'testhost', 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789', 'old_auth': False, 'use_syslog': 'false', 'loglevel': 1, - 'port': 70 + 'port': 70, + 'ipv6': False } self.assertEqual(expect, mon_ctxt()) def test_ctxt_consistent_auths(self): - self.socket.gethostname.return_value = '10.0.0.10' + self.socket.gethostname.return_value = 'testhost' mon_ctxt = context.MonContext() addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3'] auths = ['cephx', 'cephx', 'cephx'] @@ -226,11 +239,19 @@ class MonContextTest(CharmTestCase): 'auth_supported': 'cephx', 'embedded_webserver': False, 'disable_100_continue': True, - 'hostname': '10.0.0.10', + 'hostname': 'testhost', 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789', 'old_auth': False, 'use_syslog': 'false', 'loglevel': 1, - 'port': 70 + 'port': 70, + 'ipv6': False } self.assertEqual(expect, mon_ctxt()) + + +class ApacheContextTest(CharmTestCase): + + def setUp(self): + super(ApacheContextTest, self).setUp(context, TO_PATCH) + self.config.side_effect = self.test_config.get diff --git a/unit_tests/test_hooks.py b/unit_tests/test_hooks.py index 96cbf543..44fd7a87 100644 --- a/unit_tests/test_hooks.py +++ b/unit_tests/test_hooks.py @@ -6,7 +6,6 @@ from mock import ( from test_utils import ( CharmTestCase, - patch_open ) from charmhelpers.contrib.openstack.ip import PUBLIC @@ -34,8 +33,6 @@ TO_PATCH = [ 'enable_pocket', 'get_iface_for_address', 'get_netmask_for_address', - 'glob', - 'is_apache_24', 'log', 'lsb_release', 'open_port', @@ -44,8 +41,6 @@ TO_PATCH = [ 'relation_set', 'relation_get', 'related_units', - 'render_template', - 'shutil', 'status_set', 'subprocess', 'sys', @@ -62,11 +57,6 @@ class CephRadosGWTests(CharmTestCase): self.test_config.set('key', 'secretkey') self.test_config.set('use-syslog', False) - def test_install_www_scripts(self): - self.glob.glob.return_value = ['files/www/bob'] - ceph_hooks.install_www_scripts() - self.shutil.copy.assert_called_with('files/www/bob', '/var/www/') - def test_install_ceph_optimised_packages(self): self.lsb_release.return_value = {'DISTRIB_CODENAME': 'vivid'} fastcgi_source = ( @@ -122,69 +112,12 @@ class CephRadosGWTests(CharmTestCase): self.enable_pocket.assert_called_with('multiverse') self.os.makedirs.called_with('/var/lib/ceph/nss') - def test_emit_apacheconf(self): - self.is_apache_24.return_value = True - self.unit_get.return_value = '10.0.0.1' - apachecontext = { - "hostname": '10.0.0.1', - "port": 70, - } - vhost_file = '/etc/apache2/sites-available/rgw.conf' - with patch_open() as (_open, _file): - ceph_hooks.emit_apacheconf() - _open.assert_called_with(vhost_file, 'w') - self.render_template.assert_called_with('rgw', apachecontext) - - def test_apache_sites24(self): - self.is_apache_24.return_value = True - ceph_hooks.apache_sites() - calls = [ - call(['a2dissite', '000-default']), - call(['a2ensite', 'rgw']), - ] - self.subprocess.check_call.assert_has_calls(calls) - - def test_apache_sites22(self): - self.is_apache_24.return_value = False - ceph_hooks.apache_sites() - calls = [ - call(['a2dissite', 'default']), - call(['a2ensite', 'rgw']), - ] - self.subprocess.check_call.assert_has_calls(calls) - - def test_apache_modules(self): - ceph_hooks.apache_modules() - calls = [ - call(['a2enmod', 'fastcgi']), - call(['a2enmod', 'rewrite']), - ] - self.subprocess.check_call.assert_has_calls(calls) - - def test_apache_reload(self): - ceph_hooks.apache_reload() - calls = [ - call(['service', 'apache2', 'reload']), - ] - self.subprocess.call.assert_has_calls(calls) - - @patch.object(ceph_hooks, 'apache_ports', lambda *args: True) @patch.object(ceph_hooks, 'mkdir', lambda *args: None) def test_config_changed(self): _install_packages = self.patch('install_packages') - _emit_apacheconf = self.patch('emit_apacheconf') - _install_www_scripts = self.patch('install_www_scripts') - _apache_sites = self.patch('apache_sites') - _apache_modules = self.patch('apache_modules') - _apache_reload = self.patch('apache_reload') ceph_hooks.config_changed() self.assertTrue(_install_packages.called) self.CONFIGS.write_all.assert_called_with() - self.assertTrue(_emit_apacheconf.called) - self.assertTrue(_install_www_scripts.called) - self.assertTrue(_apache_sites.called) - self.assertTrue(_apache_modules.called) - self.assertTrue(_apache_reload.called) @patch.object(ceph_hooks, 'is_request_complete', lambda *args, **kwargs: True)