Merge lp:~hopem/charms/trusty/ceph-radosgw/lp1513524 into lp:~openstack-charmers-archive/charms/trusty/ceph-radosgw/next

Proposed by Edward Hope-Morley
Status: Rejected
Rejected by: James Page
Proposed branch: lp:~hopem/charms/trusty/ceph-radosgw/lp1513524
Merge into: lp:~openstack-charmers-archive/charms/trusty/ceph-radosgw/next
Diff against target: 892 lines (+320/-224)
8 files modified
config.yaml (+12/-0)
hooks/ceph_radosgw_context.py (+120/-27)
hooks/hooks.py (+70/-86)
hooks/utils.py (+58/-33)
templates/ceph.conf (+3/-0)
templates/rgw.conf (+25/-0)
unit_tests/test_ceph_radosgw_context.py (+32/-11)
unit_tests/test_hooks.py (+0/-67)
To merge this branch: bzr merge lp:~hopem/charms/trusty/ceph-radosgw/lp1513524
Reviewer Review Type Date Requested Status
Liam Young (community) Needs Fixing
OpenStack Charmers Pending
Chris Holcombe Pending
Review via email: mp+286474@code.launchpad.net

This proposal supersedes a proposal from 2016-02-11.

To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #574 ceph-radosgw-next for hopem mp285808
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/574/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #488 ceph-radosgw-next for hopem mp285808
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/488/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_amulet_test #235 ceph-radosgw-next for hopem mp285808
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/15073352/
Build: http://10.245.162.36:8080/job/charm_amulet_test/235/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #489 ceph-radosgw-next for hopem mp285808
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/489/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #575 ceph-radosgw-next for hopem mp285808
    LINT FAIL: lint-test failed

LINT Results (max last 2 lines):
make: *** [lint] Error 1
ERROR:root:Make target returned non-zero.

Full lint test output: http://paste.ubuntu.com/15074156/
Build: http://10.245.162.36:8080/job/charm_lint_check/575/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_amulet_test #236 ceph-radosgw-next for hopem mp285808
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/15074271/
Build: http://10.245.162.36:8080/job/charm_amulet_test/236/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #576 ceph-radosgw-next for hopem mp285808
    LINT FAIL: lint-test failed

LINT Results (max last 2 lines):
make: *** [lint] Error 1
ERROR:root:Make target returned non-zero.

Full lint test output: http://paste.ubuntu.com/15074967/
Build: http://10.245.162.36:8080/job/charm_lint_check/576/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #490 ceph-radosgw-next for hopem mp285808
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/490/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_amulet_test #237 ceph-radosgw-next for hopem mp285808
    AMULET OK: passed

Build: http://10.245.162.36:8080/job/charm_amulet_test/237/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #577 ceph-radosgw-next for hopem mp285808
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/577/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #491 ceph-radosgw-next for hopem mp285808
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/491/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_amulet_test #238 ceph-radosgw-next for hopem mp285808
    AMULET OK: passed

Build: http://10.245.162.36:8080/job/charm_amulet_test/238/

Revision history for this message
Chris Holcombe (xfactor973) wrote : Posted in a previous version of this proposal

Hey Ed thanks for writing this patch! This looks great. My only comments are just little nits about catching errors and what you would like to do with them. You could handle them locally or raise but it would be best to be explicit about it. Other than that this looks good and I'm looking forward to trying it out

review: Needs Fixing
Revision history for this message
Edward Hope-Morley (hopem) wrote : Posted in a previous version of this proposal

Thanks for the review Chris! I've fixed up based on your comments and added some inline responses.

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #820 ceph-radosgw-next for hopem mp286474
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/820/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #723 ceph-radosgw-next for hopem mp286474
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/723/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #320 ceph-radosgw-next for hopem mp286474
    AMULET OK: passed

Build: http://10.245.162.36:8080/job/charm_amulet_test/320/

Revision history for this message
Chris Holcombe (xfactor973) wrote : Posted in a previous version of this proposal

Cool. Lets get this merged!

review: Approve
67. By Edward Hope-Morley

sync /next

68. By Edward Hope-Morley

very minor edit

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #912 ceph-radosgw-next for hopem mp286474
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/912/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #813 ceph-radosgw-next for hopem mp286474
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/813/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #359 ceph-radosgw-next for hopem mp286474
    AMULET OK: passed

Build: http://10.245.162.36:8080/job/charm_amulet_test/359/

Revision history for this message
Liam Young (gnuoy) wrote :

See inline comment

review: Needs Fixing
Revision history for this message
Edward Hope-Morley (hopem) wrote :

Hey Liam, a good question and I responded inline.

69. By Edward Hope-Morley

only write /etc/hosts if hostname not v6 resolvable

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #1003 ceph-radosgw-next for hopem mp286474
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/1003/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #1167 ceph-radosgw-next for hopem mp286474
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/1167/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #447 ceph-radosgw-next for hopem mp286474
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/15171430/
Build: http://10.245.162.36:8080/job/charm_amulet_test/447/

70. By Edward Hope-Morley

fix logs

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #1169 ceph-radosgw-next for hopem mp286474
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/1169/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #1006 ceph-radosgw-next for hopem mp286474
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/1006/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #449 ceph-radosgw-next for hopem mp286474
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/15172636/
Build: http://10.245.162.36:8080/job/charm_amulet_test/449/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #462 ceph-radosgw-next for hopem mp286474
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/15175252/
Build: http://10.245.162.36:8080/job/charm_amulet_test/462/

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Please rebase your branch and push it back to get updated tests. Thank you.

71. By Edward Hope-Morley

sync /next

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #1296 ceph-radosgw-next for hopem mp286474
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/1296/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #1073 ceph-radosgw-next for hopem mp286474
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/1073/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #473 ceph-radosgw-next for hopem mp286474
    AMULET OK: passed

Build: http://10.245.162.36:8080/job/charm_amulet_test/473/

Revision history for this message
Edward Hope-Morley (hopem) wrote :

I've migrated this to review.openstack.org as per the new workflow - https://review.openstack.org/#/c/287162/

Unmerged revisions

71. By Edward Hope-Morley

sync /next

70. By Edward Hope-Morley

fix logs

69. By Edward Hope-Morley

only write /etc/hosts if hostname not v6 resolvable

68. By Edward Hope-Morley

very minor edit

67. By Edward Hope-Morley

sync /next

66. By Edward Hope-Morley

post-review fixups

65. By Edward Hope-Morley

fix lint error

64. By Edward Hope-Morley

fx amulet

63. By Edward Hope-Morley

fix amulet

62. By Edward Hope-Morley

[hopem,r=]

Add ipv6 support
Closes-Bug: 1513524

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2016-01-22 13:29:40 +0000
+++ config.yaml 2016-02-23 15:58:17 +0000
@@ -153,3 +153,15 @@
153 description: |153 description: |
154 Connect timeout configuration in ms for haproxy, used in HA154 Connect timeout configuration in ms for haproxy, used in HA
155 configurations. If not provided, default value of 5000ms is used.155 configurations. If not provided, default value of 5000ms is used.
156 prefer-ipv6:
157 type: boolean
158 default: False
159 description: |
160 If True enables IPv6 support. The charm will expect network interfaces
161 to be configured with an IPv6 address. If set to False (default) IPv4
162 is expected.
163 .
164 NOTE: these charms do not currently support IPv6 privacy extension. In
165 order for this charm to function correctly, the privacy extension must be
166 disabled and a non-temporary address must be configured/available on
167 your network interface.
156168
=== modified file 'hooks/ceph_radosgw_context.py'
--- hooks/ceph_radosgw_context.py 2016-01-11 12:21:07 +0000
+++ hooks/ceph_radosgw_context.py 2016-02-23 15:58:17 +0000
@@ -1,3 +1,11 @@
1import os
2import re
3import socket
4import tempfile
5import glob
6import shutil
7import subprocess
8
1from charmhelpers.contrib.openstack import context9from charmhelpers.contrib.openstack import context
2from charmhelpers.contrib.hahelpers.cluster import (10from charmhelpers.contrib.hahelpers.cluster import (
3 determine_api_port,11 determine_api_port,
@@ -5,17 +13,69 @@
5)13)
6from charmhelpers.core.host import cmp_pkgrevno14from charmhelpers.core.host import cmp_pkgrevno
7from charmhelpers.core.hookenv import (15from charmhelpers.core.hookenv import (
16 DEBUG,
8 WARNING,17 WARNING,
9 config,18 config,
10 log,19 log,
11 relation_ids,20 relation_ids,
12 related_units,21 related_units,
13 relation_get,22 relation_get,
14 unit_get,23 status_set,
15)24)
16import os25from charmhelpers.contrib.network.ip import (
17import socket26 format_ipv6_addr,
18import dns.resolver27 get_host_ip,
28 get_ipv6_addr,
29)
30
31
32def is_apache_24():
33 if os.path.exists('/etc/apache2/conf-available'):
34 return True
35 else:
36 return False
37
38
39class ApacheContext(context.OSContextGenerator):
40 interfaces = ['http']
41 service_namespace = 'ceph-radosgw'
42
43 def __call__(self):
44 ctxt = {}
45 if config('use-embedded-webserver'):
46 log("Skipping ApacheContext since we are using the embedded "
47 "webserver")
48 return {}
49
50 status_set('maintenance', 'configuring apache')
51
52 src = 'files/www/*'
53 dst = '/var/www/'
54 log("Installing www scripts", level=DEBUG)
55 try:
56 for x in glob.glob(src):
57 shutil.copy(x, dst)
58 except IOError as e:
59 log("Error copying files from '%s' to '%s': %s" % (src, dst, e),
60 level=WARNING)
61
62 try:
63 subprocess.check_call(['a2enmod', 'fastcgi'])
64 subprocess.check_call(['a2enmod', 'rewrite'])
65 except subprocess.CalledProcessError as e:
66 log("Error enabling apache modules - %s" % e, level=WARNING)
67
68 try:
69 if is_apache_24():
70 subprocess.check_call(['a2dissite', '000-default'])
71 else:
72 subprocess.check_call(['a2dissite', 'default'])
73 except subprocess.CalledProcessError as e:
74 log("Error disabling apache sites - %s" % e, level=WARNING)
75
76 ctxt['hostname'] = socket.gethostname()
77 ctxt['port'] = determine_api_port(config('port'), singlenode_mode=True)
78 return ctxt
1979
2080
21class HAProxyContext(context.HAProxyContext):81class HAProxyContext(context.HAProxyContext):
@@ -66,24 +126,60 @@
66 return {}126 return {}
67127
68128
129def ensure_host_resolvable_v6(hostname):
130 """Ensure that we can resolve our hostname to an IPv6 address by adding it
131 to /etc/hosts if it is not already resolvable.
132 """
133 try:
134 socket.getaddrinfo(hostname, None, socket.AF_INET6)
135 except socket.gaierror:
136 log("Host '%s' is not ipv6 resolvable - adding to /etc/hosts" %
137 hostname, level=DEBUG)
138 else:
139 log("Host '%s' appears to be ipv6 resolvable" % (hostname),
140 level=DEBUG)
141 return
142
143 # This must be the backend address used by haproxy
144 host_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
145 dtmp = tempfile.mkdtemp()
146 try:
147 tmp_hosts = os.path.join(dtmp, 'hosts')
148 shutil.copy('/etc/hosts', tmp_hosts)
149 with open(tmp_hosts, 'a+') as fd:
150 lines = fd.readlines()
151 for line in lines:
152 key = "^%s\s+" % (host_addr)
153 if re.search(key, line):
154 break
155 else:
156 fd.write("%s\t%s\n" % (host_addr, hostname))
157
158 os.rename(tmp_hosts, '/etc/hosts')
159 finally:
160 shutil.rmtree(dtmp)
161
162
69class MonContext(context.OSContextGenerator):163class MonContext(context.OSContextGenerator):
70 interfaces = ['ceph-radosgw']164 interfaces = ['ceph-radosgw']
71165
72 def __call__(self):166 def __call__(self):
73 if not relation_ids('mon'):167 if not relation_ids('mon'):
74 return {}168 return {}
75 hosts = []169 mon_hosts = []
76 auths = []170 auths = []
77 for relid in relation_ids('mon'):171 for relid in relation_ids('mon'):
78 for unit in related_units(relid):172 for unit in related_units(relid):
79 ceph_public_addr = relation_get('ceph-public-address', unit,173 ceph_public_addr = relation_get('ceph-public-address', unit,
80 relid)174 relid)
81 if ceph_public_addr:175 if ceph_public_addr:
82 host_ip = self.get_host_ip(ceph_public_addr)176 host_ip = format_ipv6_addr(ceph_public_addr) or \
83 hosts.append('{}:6789'.format(host_ip))177 get_host_ip(ceph_public_addr)
178 mon_hosts.append('{}:6789'.format(host_ip))
84 _auth = relation_get('auth', unit, relid)179 _auth = relation_get('auth', unit, relid)
85 if _auth:180 if _auth:
86 auths.append(_auth)181 auths.append(_auth)
182
87 if len(set(auths)) != 1:183 if len(set(auths)) != 1:
88 e = ("Inconsistent or absent auth returned by mon units. Setting "184 e = ("Inconsistent or absent auth returned by mon units. Setting "
89 "auth_supported to 'none'")185 "auth_supported to 'none'")
@@ -91,17 +187,28 @@
91 auth = 'none'187 auth = 'none'
92 else:188 else:
93 auth = auths[0]189 auth = auths[0]
94 hosts.sort()190
191 # /etc/init.d/radosgw mandates that a dns name is used for this
192 # parameter so ensure that address is resolvable
193 host = socket.gethostname()
194 if config('prefer-ipv6'):
195 ensure_host_resolvable_v6(host)
196
197 port = determine_apache_port(config('port'), singlenode_mode=True)
198 if config('prefer-ipv6'):
199 port = "[::]:%s" % (port)
200
201 mon_hosts.sort()
95 ctxt = {202 ctxt = {
96 'auth_supported': auth,203 'auth_supported': auth,
97 'mon_hosts': ' '.join(hosts),204 'mon_hosts': ' '.join(mon_hosts),
98 'hostname': socket.gethostname(),205 'hostname': host,
99 'old_auth': cmp_pkgrevno('radosgw', "0.51") < 0,206 'old_auth': cmp_pkgrevno('radosgw', "0.51") < 0,
100 'use_syslog': str(config('use-syslog')).lower(),207 'use_syslog': str(config('use-syslog')).lower(),
101 'embedded_webserver': config('use-embedded-webserver'),208 'embedded_webserver': config('use-embedded-webserver'),
102 'loglevel': config('loglevel'),209 'loglevel': config('loglevel'),
103 'port': determine_apache_port(config('port'),210 'port': port,
104 singlenode_mode=True)211 'ipv6': config('prefer-ipv6')
105 }212 }
106213
107 certs_path = '/var/lib/ceph/nss'214 certs_path = '/var/lib/ceph/nss'
@@ -121,17 +228,3 @@
121 return ctxt228 return ctxt
122229
123 return {}230 return {}
124
125 def get_host_ip(self, hostname=None):
126 try:
127 if not hostname:
128 hostname = unit_get('private-address')
129 # Test to see if already an IPv4 address
130 socket.inet_aton(hostname)
131 return hostname
132 except socket.error:
133 # This may throw an NXDOMAIN exception; in which case
134 # things are badly broken so just let it kill the hook
135 answers = dns.resolver.query(hostname, 'A')
136 if answers:
137 return answers[0].address
138231
=== modified file 'hooks/hooks.py'
--- hooks/hooks.py 2016-02-17 16:02:22 +0000
+++ hooks/hooks.py 2016-02-23 15:58:17 +0000
@@ -1,17 +1,16 @@
1#!/usr/bin/python1#!/usr/bin/python
2
3#2#
4# Copyright 2012 Canonical Ltd.3# Copyright 2016 Canonical Ltd.
5#4#
6# Authors:5# Authors:
7# James Page <james.page@ubuntu.com>6# James Page <james.page@ubuntu.com>
7# Edward Hope-Morley <edward.hope-morley@canonical.com>
8#8#
99
10import shutil10import os
11import subprocess11import subprocess
12import sys12import sys
13import glob13
14import os
15import ceph14import ceph
1615
17from charmhelpers.core.hookenv import (16from charmhelpers.core.hookenv import (
@@ -39,27 +38,17 @@
39 lsb_release,38 lsb_release,
40 restart_on_change,39 restart_on_change,
41)40)
42from charmhelpers.contrib.hahelpers.cluster import (
43 determine_apache_port,
44)
45from utils import (
46 render_template,
47 enable_pocket,
48 is_apache_24,
49 CEPHRG_HA_RES,
50 register_configs,
51 REQUIRED_INTERFACES,
52 check_optional_relations,
53)
54from charmhelpers.payload.execd import execd_preinstall41from charmhelpers.payload.execd import execd_preinstall
55from charmhelpers.core.host import (42from charmhelpers.core.host import (
56 cmp_pkgrevno,43 cmp_pkgrevno,
57 mkdir,44 mkdir,
58)45)
59
60from charmhelpers.contrib.network.ip import (46from charmhelpers.contrib.network.ip import (
47 format_ipv6_addr,
48 get_ipv6_addr,
61 get_iface_for_address,49 get_iface_for_address,
62 get_netmask_for_address,50 get_netmask_for_address,
51 is_ipv6,
63)52)
64from charmhelpers.contrib.openstack.ip import (53from charmhelpers.contrib.openstack.ip import (
65 canonical_url,54 canonical_url,
@@ -72,18 +61,17 @@
72 send_request_if_needed,61 send_request_if_needed,
73 is_request_complete,62 is_request_complete,
74)63)
7564from utils import (
76APACHE_PORTS_CONF = '/etc/apache2/ports.conf'65 enable_pocket,
66 CEPHRG_HA_RES,
67 register_configs,
68 REQUIRED_INTERFACES,
69 check_optional_relations,
70 setup_ipv6,
71)
7772
78hooks = Hooks()73hooks = Hooks()
79CONFIGS = register_configs()74CONFIGS = register_configs()
80
81
82def install_www_scripts():
83 for x in glob.glob('files/www/*'):
84 shutil.copy(x, '/var/www/')
85
86
87NSS_DIR = '/var/lib/ceph/nss'75NSS_DIR = '/var/lib/ceph/nss'
8876
8977
@@ -145,43 +133,6 @@
145 os.makedirs('/etc/ceph')133 os.makedirs('/etc/ceph')
146134
147135
148def emit_apacheconf():
149 apachecontext = {
150 "hostname": unit_get('private-address'),
151 "port": determine_apache_port(config('port'), singlenode_mode=True)
152 }
153 site_conf = '/etc/apache2/sites-available/rgw'
154 if is_apache_24():
155 site_conf = '/etc/apache2/sites-available/rgw.conf'
156 with open(site_conf, 'w') as apacheconf:
157 apacheconf.write(render_template('rgw', apachecontext))
158
159
160def apache_sites():
161 if is_apache_24():
162 subprocess.check_call(['a2dissite', '000-default'])
163 else:
164 subprocess.check_call(['a2dissite', 'default'])
165 subprocess.check_call(['a2ensite', 'rgw'])
166
167
168def apache_modules():
169 subprocess.check_call(['a2enmod', 'fastcgi'])
170 subprocess.check_call(['a2enmod', 'rewrite'])
171
172
173def apache_reload():
174 subprocess.call(['service', 'apache2', 'reload'])
175
176
177def apache_ports():
178 portscontext = {
179 "port": determine_apache_port(config('port'), singlenode_mode=True)
180 }
181 with open(APACHE_PORTS_CONF, 'w') as portsconf:
182 portsconf.write(render_template('ports.conf', portscontext))
183
184
185def setup_keystone_certs(unit=None, rid=None):136def setup_keystone_certs(unit=None, rid=None):
186 """137 """
187 Get CA and signing certs from Keystone used to decrypt revoked token list.138 Get CA and signing certs from Keystone used to decrypt revoked token list.
@@ -213,6 +164,9 @@
213 for key in required_keys:164 for key in required_keys:
214 settings[key] = rdata.get(key)165 settings[key] = rdata.get(key)
215166
167 if is_ipv6(settings.get('auth_host')):
168 settings['auth_host'] = format_ipv6_addr(settings.get('auth_host'))
169
216 if not all(settings.values()):170 if not all(settings.values()):
217 log("Missing relation settings (%s) - skipping cert setup" %171 log("Missing relation settings (%s) - skipping cert setup" %
218 (', '.join([k for k in settings.keys() if not settings[k]])),172 (', '.join([k for k in settings.keys() if not settings[k]])),
@@ -288,18 +242,28 @@
288 '/etc/haproxy/haproxy.cfg': ['haproxy']})242 '/etc/haproxy/haproxy.cfg': ['haproxy']})
289def config_changed():243def config_changed():
290 install_packages()244 install_packages()
245
246 if config('prefer-ipv6'):
247 status_set('maintenance', 'configuring ipv6')
248 setup_ipv6()
249
250 for r_id in relation_ids('identity-service'):
251 identity_changed(relid=r_id)
252
253 for r_id in relation_ids('cluster'):
254 cluster_joined(rid=r_id)
255
291 CONFIGS.write_all()256 CONFIGS.write_all()
257
292 if not config('use-embedded-webserver'):258 if not config('use-embedded-webserver'):
293 status_set('maintenance', 'configuring apache')259 try:
294 emit_apacheconf()260 subprocess.check_call(['a2ensite', 'rgw'])
295 install_www_scripts()261 except subprocess.CalledProcessError as e:
296 apache_sites()262 log("Error enabling apache module 'rgw' - %s" % e, level=WARNING)
297 apache_modules()
298 apache_ports()
299 apache_reload()
300263
301 for r_id in relation_ids('identity-service'):264 # Ensure started but do a soft reload
302 identity_changed(relid=r_id)265 subprocess.call(['service', 'apache2', 'start'])
266 subprocess.call(['service', 'apache2', 'reload'])
303267
304268
305@hooks.hook('mon-relation-departed',269@hooks.hook('mon-relation-departed',
@@ -373,8 +337,18 @@
373 restart()337 restart()
374338
375339
376@hooks.hook('cluster-relation-changed',340@hooks.hook('cluster-relation-joined')
377 'cluster-relation-joined')341@restart_on_change({'/etc/haproxy/haproxy.cfg': ['haproxy']})
342def cluster_joined(rid=None):
343 settings = {}
344 if config('prefer-ipv6'):
345 private_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
346 settings['private-address'] = private_addr
347
348 relation_set(relation_id=rid, **settings)
349
350
351@hooks.hook('cluster-relation-changed')
378@restart_on_change({'/etc/haproxy/haproxy.cfg': ['haproxy']})352@restart_on_change({'/etc/haproxy/haproxy.cfg': ['haproxy']})
379def cluster_changed():353def cluster_changed():
380 CONFIGS.write_all()354 CONFIGS.write_all()
@@ -384,17 +358,12 @@
384358
385@hooks.hook('ha-relation-joined')359@hooks.hook('ha-relation-joined')
386def ha_relation_joined():360def ha_relation_joined():
387 # Obtain the config values necessary for the cluster config. These
388 # include multicast port and interface to bind to.
389 corosync_bindiface = config('ha-bindiface')
390 corosync_mcastport = config('ha-mcastport')
391 vip = config('vip')361 vip = config('vip')
392 if not vip:362 if not vip:
393 log('Unable to configure hacluster as vip not provided',363 log('Unable to configure hacluster as vip not provided', level=ERROR)
394 level=ERROR)
395 sys.exit(1)364 sys.exit(1)
365
396 # Obtain resources366 # Obtain resources
397 # SWIFT_HA_RES = 'grp_swift_vips'
398 resources = {367 resources = {
399 'res_cephrg_haproxy': 'lsb:haproxy'368 'res_cephrg_haproxy': 'lsb:haproxy'
400 }369 }
@@ -404,15 +373,25 @@
404373
405 vip_group = []374 vip_group = []
406 for vip in vip.split():375 for vip in vip.split():
376 if is_ipv6(vip):
377 res_rgw_vip = 'ocf:heartbeat:IPv6addr'
378 vip_params = 'ipv6addr'
379 else:
380 res_rgw_vip = 'ocf:heartbeat:IPaddr2'
381 vip_params = 'ip'
382
407 iface = get_iface_for_address(vip)383 iface = get_iface_for_address(vip)
384 netmask = get_netmask_for_address(vip)
385
408 if iface is not None:386 if iface is not None:
409 vip_key = 'res_cephrg_{}_vip'.format(iface)387 vip_key = 'res_cephrg_{}_vip'.format(iface)
410 resources[vip_key] = 'ocf:heartbeat:IPaddr2'388 resources[vip_key] = res_rgw_vip
411 resource_params[vip_key] = (389 resource_params[vip_key] = (
412 'params ip="{vip}" cidr_netmask="{netmask}"'390 'params {ip}="{vip}" cidr_netmask="{netmask}"'
413 ' nic="{iface}"'.format(vip=vip,391 ' nic="{iface}"'.format(ip=vip_params,
392 vip=vip,
414 iface=iface,393 iface=iface,
415 netmask=get_netmask_for_address(vip))394 netmask=netmask)
416 )395 )
417 vip_group.append(vip_key)396 vip_group.append(vip_key)
418397
@@ -426,6 +405,11 @@
426 'cl_cephrg_haproxy': 'res_cephrg_haproxy'405 'cl_cephrg_haproxy': 'res_cephrg_haproxy'
427 }406 }
428407
408 # Obtain the config values necessary for the cluster config. These
409 # include multicast port and interface to bind to.
410 corosync_bindiface = config('ha-bindiface')
411 corosync_mcastport = config('ha-mcastport')
412
429 relation_set(init_services=init_services,413 relation_set(init_services=init_services,
430 corosync_bindiface=corosync_bindiface,414 corosync_bindiface=corosync_bindiface,
431 corosync_mcastport=corosync_mcastport,415 corosync_mcastport=corosync_mcastport,
432416
=== modified file 'hooks/utils.py'
--- hooks/utils.py 2015-10-12 10:56:01 +0000
+++ hooks/utils.py 2016-02-23 15:58:17 +0000
@@ -1,26 +1,43 @@
1#1#
2# Copyright 2012 Canonical Ltd.2# Copyright 2016 Canonical Ltd.
3#3#
4# Authors:4# Authors:
5# James Page <james.page@ubuntu.com>5# James Page <james.page@ubuntu.com>
6# Paul Collins <paul.collins@canonical.com>6# Paul Collins <paul.collins@canonical.com>
7# Edward Hope-Morley <edward.hope-morley@canonical.com>
7#8#
89
9import socket
10import re10import re
11import os
12import dns.resolver
13import jinja211import jinja2
12
14from copy import deepcopy13from copy import deepcopy
15from collections import OrderedDict14from collections import OrderedDict
16from charmhelpers.core.hookenv import unit_get, relation_ids, status_get15
17from charmhelpers.contrib.openstack import context, templating16import ceph_radosgw_context
18from charmhelpers.contrib.openstack.utils import set_os_workload_status17
18from charmhelpers.core.hookenv import (
19 relation_ids,
20 status_get,
21)
22from charmhelpers.contrib.openstack import (
23 context,
24 templating,
25)
26from charmhelpers.contrib.openstack.utils import (
27 os_release,
28 set_os_workload_status,
29)
19from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config30from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config
20from charmhelpers.core.host import cmp_pkgrevno31from charmhelpers.core.host import (
21from charmhelpers.fetch import filter_installed_packages32 cmp_pkgrevno,
2233 lsb_release,
23import ceph_radosgw_context34)
35from charmhelpers.fetch import (
36 apt_install,
37 apt_update,
38 add_source,
39 filter_installed_packages,
40)
2441
25# The interface is said to be satisfied if anyone of the interfaces in the42# The interface is said to be satisfied if anyone of the interfaces in the
26# list has a complete context.43# list has a complete context.
@@ -32,6 +49,9 @@
32TEMPLATES = 'templates/'49TEMPLATES = 'templates/'
33HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'50HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
34CEPH_CONF = '/etc/ceph/ceph.conf'51CEPH_CONF = '/etc/ceph/ceph.conf'
52APACHE_CONF = '/etc/apache2/sites-available/rgw'
53APACHE_24_CONF = '/etc/apache2/sites-available/rgw.conf'
54APACHE_PORTS_CONF = '/etc/apache2/ports.conf'
3555
36BASE_RESOURCE_MAP = OrderedDict([56BASE_RESOURCE_MAP = OrderedDict([
37 (HAPROXY_CONF, {57 (HAPROXY_CONF, {
@@ -39,6 +59,18 @@
39 ceph_radosgw_context.HAProxyContext()],59 ceph_radosgw_context.HAProxyContext()],
40 'services': ['haproxy'],60 'services': ['haproxy'],
41 }),61 }),
62 (APACHE_CONF, {
63 'contexts': [ceph_radosgw_context.ApacheContext()],
64 'services': ['apache2'],
65 }),
66 (APACHE_24_CONF, {
67 'contexts': [ceph_radosgw_context.ApacheContext()],
68 'services': ['apache2'],
69 }),
70 (APACHE_PORTS_CONF, {
71 'contexts': [ceph_radosgw_context.ApacheContext()],
72 'services': ['apache2'],
73 }),
42 (CEPH_CONF, {74 (CEPH_CONF, {
43 'contexts': [ceph_radosgw_context.MonContext()],75 'contexts': [ceph_radosgw_context.MonContext()],
44 'services': ['radosgw'],76 'services': ['radosgw'],
@@ -92,28 +124,6 @@
92 sources.write(line)124 sources.write(line)
93125
94126
95def get_host_ip(hostname=None):
96 try:
97 if not hostname:
98 hostname = unit_get('private-address')
99 # Test to see if already an IPv4 address
100 socket.inet_aton(hostname)
101 return hostname
102 except socket.error:
103 # This may throw an NXDOMAIN exception; in which case
104 # things are badly broken so just let it kill the hook
105 answers = dns.resolver.query(hostname, 'A')
106 if answers:
107 return answers[0].address
108
109
110def is_apache_24():
111 if os.path.exists('/etc/apache2/conf-available'):
112 return True
113 else:
114 return False
115
116
117def check_optional_relations(configs):127def check_optional_relations(configs):
118 required_interfaces = {}128 required_interfaces = {}
119 if relation_ids('ha'):129 if relation_ids('ha'):
@@ -132,3 +142,18 @@
132 return status_get()142 return status_get()
133 else:143 else:
134 return 'unknown', 'No optional relations'144 return 'unknown', 'No optional relations'
145
146
147def setup_ipv6():
148 ubuntu_rel = lsb_release()['DISTRIB_CODENAME'].lower()
149 if ubuntu_rel < "trusty":
150 raise Exception("IPv6 is not supported in the charms for Ubuntu "
151 "versions less than Trusty 14.04")
152
153 # Need haproxy >= 1.5.3 for ipv6 so for Trusty if we are <= Kilo we need to
154 # use trusty-backports otherwise we can use the UCA.
155 if ubuntu_rel == 'trusty' and os_release('ceph-common') < 'liberty':
156 add_source('deb http://archive.ubuntu.com/ubuntu trusty-backports '
157 'main')
158 apt_update()
159 apt_install('haproxy/trusty-backports', fatal=True)
135160
=== modified file 'templates/ceph.conf'
--- templates/ceph.conf 2016-01-11 12:21:07 +0000
+++ templates/ceph.conf 2016-02-23 15:58:17 +0000
@@ -11,6 +11,9 @@
11err to syslog = {{ use_syslog }}11err to syslog = {{ use_syslog }}
12clog to syslog = {{ use_syslog }}12clog to syslog = {{ use_syslog }}
13debug rgw = {{ loglevel }}/513debug rgw = {{ loglevel }}/5
14{% if ipv6 -%}
15ms bind ipv6 = true
16{% endif %}
1417
15[client.radosgw.gateway]18[client.radosgw.gateway]
16host = {{ hostname }}19host = {{ hostname }}
1720
=== added file 'templates/rgw.conf'
--- templates/rgw.conf 1970-01-01 00:00:00 +0000
+++ templates/rgw.conf 2016-02-23 15:58:17 +0000
@@ -0,0 +1,25 @@
1<IfModule mod_fastcgi.c>
2 FastCgiExternalServer /var/www/s3gw.fcgi -socket /tmp/radosgw.sock
3</IfModule>
4
5<VirtualHost *:{{ port }}>
6 ServerName {{ hostname }}
7 ServerAdmin ceph@ubuntu.com
8 DocumentRoot /var/www
9 RewriteEngine On
10 RewriteRule ^/([a-zA-Z0-9-_.]*)([/]?.*) /s3gw.fcgi?page=$1&params=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
11 <IfModule mod_fastcgi.c>
12 <Directory /var/www>
13 Options +ExecCGI
14 AllowOverride All
15 SetHandler fastcgi-script
16 Order allow,deny
17 Allow from all
18 AuthBasicAuthoritative Off
19 </Directory>
20 </IfModule>
21 AllowEncodedSlashes On
22 ErrorLog /var/log/apache2/error.log
23 CustomLog /var/log/apache2/access.log combined
24 ServerSignature Off
25</VirtualHost>
026
=== modified file 'unit_tests/test_ceph_radosgw_context.py'
--- unit_tests/test_ceph_radosgw_context.py 2016-02-17 22:46:07 +0000
+++ unit_tests/test_ceph_radosgw_context.py 2016-02-23 15:58:17 +0000
@@ -13,6 +13,7 @@
13 'related_units',13 'related_units',
14 'cmp_pkgrevno',14 'cmp_pkgrevno',
15 'socket',15 'socket',
16 'is_apache_24',
16]17]
1718
1819
@@ -147,8 +148,9 @@
147 super(MonContextTest, self).setUp(context, TO_PATCH)148 super(MonContextTest, self).setUp(context, TO_PATCH)
148 self.config.side_effect = self.test_config.get149 self.config.side_effect = self.test_config.get
149150
150 def test_ctxt(self):151 @patch.object(context, 'ensure_host_resolvable_v6')
151 self.socket.gethostname.return_value = '10.0.0.10'152 def test_ctxt(self, mock_ensure_rsv_v6):
153 self.socket.gethostname.return_value = 'testhost'
152 mon_ctxt = context.MonContext()154 mon_ctxt = context.MonContext()
153 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']155 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
154156
@@ -157,6 +159,7 @@
157 return addresses.pop()159 return addresses.pop()
158 elif attr == 'auth':160 elif attr == 'auth':
159 return 'cephx'161 return 'cephx'
162
160 self.relation_get.side_effect = _relation_get163 self.relation_get.side_effect = _relation_get
161 self.relation_ids.return_value = ['mon:6']164 self.relation_ids.return_value = ['mon:6']
162 self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']165 self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
@@ -164,17 +167,26 @@
164 'auth_supported': 'cephx',167 'auth_supported': 'cephx',
165 'embedded_webserver': False,168 'embedded_webserver': False,
166 'disable_100_continue': True,169 'disable_100_continue': True,
167 'hostname': '10.0.0.10',170 'hostname': 'testhost',
168 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',171 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',
169 'old_auth': False,172 'old_auth': False,
170 'use_syslog': 'false',173 'use_syslog': 'false',
171 'loglevel': 1,174 'loglevel': 1,
172 'port': 70175 'port': 70,
176 'ipv6': False
173 }177 }
174 self.assertEqual(expect, mon_ctxt())178 self.assertEqual(expect, mon_ctxt())
179 self.assertFalse(mock_ensure_rsv_v6.called)
180
181 self.test_config.set('prefer-ipv6', True)
182 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
183 expect['ipv6'] = True
184 expect['port'] = "[::]:%s" % (70)
185 self.assertEqual(expect, mon_ctxt())
186 self.assertTrue(mock_ensure_rsv_v6.called)
175187
176 def test_ctxt_missing_data(self):188 def test_ctxt_missing_data(self):
177 self.socket.gethostname.return_value = '10.0.0.10'189 self.socket.gethostname.return_value = 'testhost'
178 mon_ctxt = context.MonContext()190 mon_ctxt = context.MonContext()
179 self.relation_get.return_value = None191 self.relation_get.return_value = None
180 self.relation_ids.return_value = ['mon:6']192 self.relation_ids.return_value = ['mon:6']
@@ -182,7 +194,7 @@
182 self.assertEqual({}, mon_ctxt())194 self.assertEqual({}, mon_ctxt())
183195
184 def test_ctxt_inconsistent_auths(self):196 def test_ctxt_inconsistent_auths(self):
185 self.socket.gethostname.return_value = '10.0.0.10'197 self.socket.gethostname.return_value = 'testhost'
186 mon_ctxt = context.MonContext()198 mon_ctxt = context.MonContext()
187 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']199 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
188 auths = ['cephx', 'cephy', 'cephz']200 auths = ['cephx', 'cephy', 'cephz']
@@ -199,17 +211,18 @@
199 'auth_supported': 'none',211 'auth_supported': 'none',
200 'embedded_webserver': False,212 'embedded_webserver': False,
201 'disable_100_continue': True,213 'disable_100_continue': True,
202 'hostname': '10.0.0.10',214 'hostname': 'testhost',
203 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',215 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',
204 'old_auth': False,216 'old_auth': False,
205 'use_syslog': 'false',217 'use_syslog': 'false',
206 'loglevel': 1,218 'loglevel': 1,
207 'port': 70219 'port': 70,
220 'ipv6': False
208 }221 }
209 self.assertEqual(expect, mon_ctxt())222 self.assertEqual(expect, mon_ctxt())
210223
211 def test_ctxt_consistent_auths(self):224 def test_ctxt_consistent_auths(self):
212 self.socket.gethostname.return_value = '10.0.0.10'225 self.socket.gethostname.return_value = 'testhost'
213 mon_ctxt = context.MonContext()226 mon_ctxt = context.MonContext()
214 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']227 addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
215 auths = ['cephx', 'cephx', 'cephx']228 auths = ['cephx', 'cephx', 'cephx']
@@ -226,11 +239,19 @@
226 'auth_supported': 'cephx',239 'auth_supported': 'cephx',
227 'embedded_webserver': False,240 'embedded_webserver': False,
228 'disable_100_continue': True,241 'disable_100_continue': True,
229 'hostname': '10.0.0.10',242 'hostname': 'testhost',
230 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',243 'mon_hosts': '10.5.4.1:6789 10.5.4.2:6789 10.5.4.3:6789',
231 'old_auth': False,244 'old_auth': False,
232 'use_syslog': 'false',245 'use_syslog': 'false',
233 'loglevel': 1,246 'loglevel': 1,
234 'port': 70247 'port': 70,
248 'ipv6': False
235 }249 }
236 self.assertEqual(expect, mon_ctxt())250 self.assertEqual(expect, mon_ctxt())
251
252
253class ApacheContextTest(CharmTestCase):
254
255 def setUp(self):
256 super(ApacheContextTest, self).setUp(context, TO_PATCH)
257 self.config.side_effect = self.test_config.get
237258
=== modified file 'unit_tests/test_hooks.py'
--- unit_tests/test_hooks.py 2016-01-22 13:29:40 +0000
+++ unit_tests/test_hooks.py 2016-02-23 15:58:17 +0000
@@ -6,7 +6,6 @@
66
7from test_utils import (7from test_utils import (
8 CharmTestCase,8 CharmTestCase,
9 patch_open
10)9)
11from charmhelpers.contrib.openstack.ip import PUBLIC10from charmhelpers.contrib.openstack.ip import PUBLIC
1211
@@ -34,8 +33,6 @@
34 'enable_pocket',33 'enable_pocket',
35 'get_iface_for_address',34 'get_iface_for_address',
36 'get_netmask_for_address',35 'get_netmask_for_address',
37 'glob',
38 'is_apache_24',
39 'log',36 'log',
40 'lsb_release',37 'lsb_release',
41 'open_port',38 'open_port',
@@ -44,8 +41,6 @@
44 'relation_set',41 'relation_set',
45 'relation_get',42 'relation_get',
46 'related_units',43 'related_units',
47 'render_template',
48 'shutil',
49 'status_set',44 'status_set',
50 'subprocess',45 'subprocess',
51 'sys',46 'sys',
@@ -62,11 +57,6 @@
62 self.test_config.set('key', 'secretkey')57 self.test_config.set('key', 'secretkey')
63 self.test_config.set('use-syslog', False)58 self.test_config.set('use-syslog', False)
6459
65 def test_install_www_scripts(self):
66 self.glob.glob.return_value = ['files/www/bob']
67 ceph_hooks.install_www_scripts()
68 self.shutil.copy.assert_called_with('files/www/bob', '/var/www/')
69
70 def test_install_ceph_optimised_packages(self):60 def test_install_ceph_optimised_packages(self):
71 self.lsb_release.return_value = {'DISTRIB_CODENAME': 'vivid'}61 self.lsb_release.return_value = {'DISTRIB_CODENAME': 'vivid'}
72 fastcgi_source = (62 fastcgi_source = (
@@ -122,69 +112,12 @@
122 self.enable_pocket.assert_called_with('multiverse')112 self.enable_pocket.assert_called_with('multiverse')
123 self.os.makedirs.called_with('/var/lib/ceph/nss')113 self.os.makedirs.called_with('/var/lib/ceph/nss')
124114
125 def test_emit_apacheconf(self):
126 self.is_apache_24.return_value = True
127 self.unit_get.return_value = '10.0.0.1'
128 apachecontext = {
129 "hostname": '10.0.0.1',
130 "port": 70,
131 }
132 vhost_file = '/etc/apache2/sites-available/rgw.conf'
133 with patch_open() as (_open, _file):
134 ceph_hooks.emit_apacheconf()
135 _open.assert_called_with(vhost_file, 'w')
136 self.render_template.assert_called_with('rgw', apachecontext)
137
138 def test_apache_sites24(self):
139 self.is_apache_24.return_value = True
140 ceph_hooks.apache_sites()
141 calls = [
142 call(['a2dissite', '000-default']),
143 call(['a2ensite', 'rgw']),
144 ]
145 self.subprocess.check_call.assert_has_calls(calls)
146
147 def test_apache_sites22(self):
148 self.is_apache_24.return_value = False
149 ceph_hooks.apache_sites()
150 calls = [
151 call(['a2dissite', 'default']),
152 call(['a2ensite', 'rgw']),
153 ]
154 self.subprocess.check_call.assert_has_calls(calls)
155
156 def test_apache_modules(self):
157 ceph_hooks.apache_modules()
158 calls = [
159 call(['a2enmod', 'fastcgi']),
160 call(['a2enmod', 'rewrite']),
161 ]
162 self.subprocess.check_call.assert_has_calls(calls)
163
164 def test_apache_reload(self):
165 ceph_hooks.apache_reload()
166 calls = [
167 call(['service', 'apache2', 'reload']),
168 ]
169 self.subprocess.call.assert_has_calls(calls)
170
171 @patch.object(ceph_hooks, 'apache_ports', lambda *args: True)
172 @patch.object(ceph_hooks, 'mkdir', lambda *args: None)115 @patch.object(ceph_hooks, 'mkdir', lambda *args: None)
173 def test_config_changed(self):116 def test_config_changed(self):
174 _install_packages = self.patch('install_packages')117 _install_packages = self.patch('install_packages')
175 _emit_apacheconf = self.patch('emit_apacheconf')
176 _install_www_scripts = self.patch('install_www_scripts')
177 _apache_sites = self.patch('apache_sites')
178 _apache_modules = self.patch('apache_modules')
179 _apache_reload = self.patch('apache_reload')
180 ceph_hooks.config_changed()118 ceph_hooks.config_changed()
181 self.assertTrue(_install_packages.called)119 self.assertTrue(_install_packages.called)
182 self.CONFIGS.write_all.assert_called_with()120 self.CONFIGS.write_all.assert_called_with()
183 self.assertTrue(_emit_apacheconf.called)
184 self.assertTrue(_install_www_scripts.called)
185 self.assertTrue(_apache_sites.called)
186 self.assertTrue(_apache_modules.called)
187 self.assertTrue(_apache_reload.called)
188121
189 @patch.object(ceph_hooks, 'is_request_complete',122 @patch.object(ceph_hooks, 'is_request_complete',
190 lambda *args, **kwargs: True)123 lambda *args, **kwargs: True)

Subscribers

People subscribed via source and target branches