Merge lp:~free.ekanayaka/landscape-charm/handle-config-changes into lp:~landscape/landscape-charm/trunk

Proposed by Free Ekanayaka
Status: Merged
Approved by: Free Ekanayaka
Approved revision: 278
Merged at revision: 275
Proposed branch: lp:~free.ekanayaka/landscape-charm/handle-config-changes
Merge into: lp:~landscape/landscape-charm/trunk
Diff against target: 550 lines (+185/-74)
14 files modified
Makefile (+2/-2)
hooks/config-changed (+2/-2)
lib/callbacks/apt.py (+6/-9)
lib/callbacks/scripts.py (+17/-0)
lib/callbacks/tests/test_apt.py (+11/-27)
lib/callbacks/tests/test_scripts.py (+30/-2)
lib/services.py (+26/-5)
lib/tests/sample.py (+7/-2)
lib/tests/test_services.py (+33/-5)
tests/02-sslcert (+0/-16)
tests/assets.py (+14/-1)
tests/basic/test_sslcert.py (+3/-3)
tests/helpers.py (+16/-0)
tests/layers.py (+18/-0)
To merge this branch: bzr merge lp:~free.ekanayaka/landscape-charm/handle-config-changes
Reviewer Review Type Date Requested Status
🤖 Landscape Builder test results Approve
Adam Collard (community) Approve
Данило Шеган (community) Approve
Review via email: mp+259034@code.launchpad.net

Commit message

This branch turns the config-changed hook into a regular hook managed by the service framework, meaning that if configuration values get changed, then proper actions will be taken (such as rewriting configuration files and/or restarting services).

The code of the former config-changed hook that used to handle changes in the APT source has basically become a regular callback (under lib/callbacks/apt.py).

There also a couple of special cases:

1) if the only config value that has changed is the APT source, there's no need to restart services

2) if the SSL certificate config changes we want to notify the haproxy service and retrigger the HAProxyProvider

Finally, the standalone tests/02-sslcert test has been merged into the regular tests/01-basic test, since all we need is to set the SSL configuration and make sure it's correctly propagated to haproxy.

Description of the change

This branch turns the config-changed hook into a regular hook managed by the service framework, meaning that if configuration values get changed, then proper actions will be taken (such as rewriting configuration files and/or restarting services).

The code of the former config-changed hook that used to handle changes in the APT source has basically become a regular callback (under lib/callbacks/apt.py).

There also a couple of special cases:

1) if the only config value that has changed is the APT source, there's no need to restart services

2) if the SSL certificate config changes we want to notify the haproxy service and retrigger the HAProxyProvider

Finally, the standalone tests/02-sslcert test has been merged into the regular tests/01-basic test, since all we need is to set the SSL configuration and make sure it's correctly propagated to haproxy. This is enough to test the integration point between the haproxy charm and the landscape-server charm (iow there's now no need to bootstrap a separate environment in order to exercise this behavior).

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make ci-test
Result: Success
Revno: 276
Branch: lp:~free.ekanayaka/landscape-charm/handle-config-changes
Jenkins: https://ci.lscape.net/job/latch-test/932/

review: Approve (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

Looks great and works as advertised.

While I am happy that you just went ahead and made these 2 integration tests a single one (I was about to do the same, since there was no sense in testing our canonical deployment with two separate tests), it would be better if it was a separate branch.

review: Approve
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make ci-test
Result: Success
Revno: 277
Branch: lp:~free.ekanayaka/landscape-charm/handle-config-changes
Jenkins: https://ci.lscape.net/job/latch-test/935/

review: Approve (test results)
Revision history for this message
Adam Collard (adam-collard) wrote :

Agree with Danilo that this would have been better as two separate branches.

5 nitpicks below whilst I test the behaviour for real

Revision history for this message
Adam Collard (adam-collard) :
review: Approve
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

Thanks Danilo and Adam.

I was unsure whether to include the change in the SSL integration tests, however since they do exercise the somehow tricky code that this branch introduces (i.e. updating the haproxy relation on SSL config changed by manually kicking the data provider) I thought it made sense to have them here.

Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make ci-test
Result: Success
Revno: 278
Branch: lp:~free.ekanayaka/landscape-charm/handle-config-changes
Jenkins: https://ci.lscape.net/job/latch-test/939/

review: Approve (test results)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2015-05-12 19:57:04 +0000
3+++ Makefile 2015-05-14 14:52:22 +0000
4@@ -43,11 +43,11 @@
5 integration-test: test-depends
6 juju test --set-e -p SKIP_SLOW_TESTS,LS_CHARM_SOURCE,JUJU_HOME,JUJU_ENV,PG_MANUAL_TUNING -v --timeout 3000s
7
8-integration-test-dense-maas: test-depends
9+integration-test-dense-maas:
10 DEPLOYER_TARGET=landscape-dense-maas make integration-test
11
12 # Run integration tests using the LDS package from the lds-trunk PPA
13-integration-test-trunk: test-depends secrets
14+integration-test-trunk: secrets
15 LS_CHARM_SOURCE=lds-trunk-ppa make integration-test
16
17 deploy-dense-maas: bundles
18
19=== modified file 'hooks/config-changed'
20--- hooks/config-changed 2015-02-03 10:00:55 +0000
21+++ hooks/config-changed 2015-05-14 14:52:22 +0000
22@@ -1,9 +1,9 @@
23 #!/usr/bin/python
24 import sys
25
26-from lib.config import ConfigHook
27+from lib.services import ServicesHook
28
29
30 if __name__ == "__main__":
31- hook = ConfigHook()
32+ hook = ServicesHook()
33 sys.exit(hook())
34
35=== renamed file 'lib/config.py' => 'lib/callbacks/apt.py'
36--- lib/config.py 2015-05-12 16:02:54 +0000
37+++ lib/callbacks/apt.py 2015-05-14 14:52:22 +0000
38@@ -2,25 +2,22 @@
39
40 from charmhelpers import fetch
41 from charmhelpers.core import hookenv
42+from charmhelpers.core.services.base import ManagerCallback
43
44-from lib.hook import Hook
45 from lib.apt import Apt
46
47
48-class ConfigHook(Hook):
49- """Execute config-changed hook logic."""
50+class SetAPTSources(ManagerCallback):
51+ """Set APT sources and refresh them if needed."""
52
53 def __init__(self, hookenv=hookenv, fetch=fetch, subprocess=subprocess):
54- super(ConfigHook, self).__init__(hookenv=hookenv)
55+ self._hookenv = hookenv
56 self._fetch = fetch
57 self._subprocess = subprocess
58
59- def _run(self):
60- # Re-set APT sources, if the have changed.
61+ def __call__(self, manager, service_name, event_name):
62+ # Re-set APT sources, if they have changed.
63 apt = Apt(
64 hookenv=self._hookenv, fetch=self._fetch,
65 subprocess=self._subprocess)
66 apt.set_sources()
67-
68- config = self._hookenv.config()
69- config.save()
70
71=== modified file 'lib/callbacks/scripts.py'
72--- lib/callbacks/scripts.py 2015-05-07 10:26:45 +0000
73+++ lib/callbacks/scripts.py 2015-05-14 14:52:22 +0000
74@@ -1,5 +1,6 @@
75 import subprocess
76
77+from charmhelpers.core import hookenv
78 from charmhelpers.core.services.base import ManagerCallback
79
80 from lib.paths import LSCTL
81@@ -32,6 +33,10 @@
82 class LSCtl(ScriptCallback):
83 """Call the lsctl script to start or stop services."""
84
85+ def __init__(self, subprocess=subprocess, hookenv=hookenv):
86+ super(LSCtl, self).__init__(subprocess=subprocess)
87+ self._hookenv = hookenv
88+
89 def __call__(self, manager, service_name, event_name):
90 action = event_name
91 if event_name == "start":
92@@ -39,4 +44,16 @@
93 # config changes have been applied and its semantics actually
94 # maps to a 'restart' action.
95 action = "restart"
96+
97+ # In case we're reacting to config changes, we don't always want to
98+ # restart the processes (for example if only the APT source changed).
99+ if self._hookenv.hook_name() == "config-changed":
100+ config = self._hookenv.config()
101+ changed = set()
102+ for key in config.keys():
103+ if config.changed(key):
104+ changed.add(key)
105+ if changed.issubset({"source", "key"}):
106+ return
107+
108 self._run(LSCTL, (action,))
109
110=== renamed file 'lib/tests/test_config.py' => 'lib/callbacks/tests/test_apt.py'
111--- lib/tests/test_config.py 2015-05-13 09:22:49 +0000
112+++ lib/callbacks/tests/test_apt.py 2015-05-14 14:52:22 +0000
113@@ -1,41 +1,25 @@
114 from lib.tests.helpers import HookenvTest
115 from lib.tests.stubs import FetchStub, SubprocessStub
116-from lib.config import ConfigHook
117-
118-
119-class ConfigHookTest(HookenvTest):
120+from lib.callbacks.apt import SetAPTSources
121+
122+
123+class SetAPTSourcesTest(HookenvTest):
124
125 def setUp(self):
126- super(ConfigHookTest, self).setUp()
127+ super(SetAPTSourcesTest, self).setUp()
128 self.fetch = FetchStub()
129 self.subprocess = SubprocessStub()
130- self.hook = ConfigHook(
131+ self.callback = SetAPTSources(
132 hookenv=self.hookenv, fetch=self.fetch, subprocess=self.subprocess)
133
134 def test_run(self):
135 """
136- The L{ConfigHook} re-configures APT sources if they have changed.
137+ The SetAPTSources callback re-configures APT sources if they have
138+ changed.
139 """
140 config = self.hookenv.config()
141 config["source"] = "ppa:landscape/14.10"
142 config.save()
143- config.load_previous()
144- config["source"] = "ppa:landscape/15.01"
145- self.assertEqual(0, self.hook())
146- self.assertTrue(len(self.fetch.sources) == 1)
147-
148- def test_save_after_change(self):
149- """
150- The L{ConfigHook} saves previous config values when called.
151- """
152- config = self.hookenv.config()
153- config["source"] = "ppa:landscape/14.10"
154- self.assertIsNone(config.previous("source"))
155- self.hook()
156- config.load_previous()
157- self.assertEqual("ppa:landscape/14.10", config.previous("source"))
158-
159- config["source"] = "ppa:landscape/15.01"
160- self.hook()
161- config.load_previous()
162- self.assertEqual("ppa:landscape/15.01", config.previous("source"))
163+ config["source"] = "ppa:landscape/15.01"
164+ self.callback(None, None, None)
165+ self.assertEqual(1, len(self.fetch.sources), repr(self.fetch.sources))
166
167=== modified file 'lib/callbacks/tests/test_scripts.py'
168--- lib/callbacks/tests/test_scripts.py 2015-04-07 13:56:21 +0000
169+++ lib/callbacks/tests/test_scripts.py 2015-05-14 14:52:22 +0000
170@@ -1,6 +1,7 @@
171 from fixtures import TestWithFixtures
172
173 from lib.callbacks.scripts import SchemaBootstrap, LSCtl
174+from lib.tests.helpers import HookenvTest
175 from lib.tests.stubs import SubprocessStub
176
177
178@@ -21,12 +22,12 @@
179 self.subprocess.calls[0][0])
180
181
182-class LSCtlTest(TestWithFixtures):
183+class LSCtlTest(HookenvTest):
184
185 def setUp(self):
186 super(LSCtlTest, self).setUp()
187 self.subprocess = SubprocessStub()
188- self.callback = LSCtl(subprocess=self.subprocess)
189+ self.callback = LSCtl(subprocess=self.subprocess, hookenv=self.hookenv)
190
191 def test_start(self):
192 """
193@@ -45,3 +46,30 @@
194 self.callback(None, None, "stop")
195 self.assertEqual(
196 ["/usr/bin/lsctl", "stop"], self.subprocess.calls[0][0])
197+
198+ def test_config_changed_only_apt(self):
199+ """
200+ The 'lsctl' script is not invoked if only the APT source has changed.
201+ """
202+ self.hookenv.hook = "config-changed"
203+ config = self.hookenv.config()
204+ config["source"] = "ppa:landscape/14.10"
205+ config.save()
206+ config["source"] = "ppa:landscape/15.01"
207+ self.callback(None, None, "start")
208+ self.assertEqual([], self.subprocess.calls)
209+
210+ def test_config_changed_not_only_apt(self):
211+ """
212+ The 'lsctl' script is invoked if not only the APT source has changed.
213+ """
214+ self.hookenv.hook = "config-changed"
215+ config = self.hookenv.config()
216+ config["source"] = "ppa:landscape/14.10"
217+ config["license-file"] = "<old data>"
218+ config.save()
219+ config["source"] = "ppa:landscape/15.01"
220+ config["license-file"] = "<new data>"
221+ self.callback(None, None, "start")
222+ self.assertEqual(
223+ ["/usr/bin/lsctl", "restart"], self.subprocess.calls[0][0])
224
225=== modified file 'lib/services.py'
226--- lib/services.py 2015-05-13 07:05:26 +0000
227+++ lib/services.py 2015-05-14 14:52:22 +0000
228@@ -1,5 +1,6 @@
229 import subprocess
230
231+from charmhelpers import fetch
232 from charmhelpers.core import hookenv
233 from charmhelpers.core import host
234 from charmhelpers.core.services.base import ServiceManager
235@@ -18,6 +19,7 @@
236 from lib.callbacks.scripts import SchemaBootstrap, LSCtl
237 from lib.callbacks.filesystem import (
238 EnsureConfigDir, WriteCustomSSLCertificate, WriteLicenseFile)
239+from lib.callbacks.apt import SetAPTSources
240
241
242 SERVICE_COUNTS = {
243@@ -34,13 +36,14 @@
244 proceed with the configuration if ready.
245 """
246 def __init__(self, hookenv=hookenv, cluster=cluster, host=host,
247- subprocess=subprocess, paths=default_paths):
248+ subprocess=subprocess, paths=default_paths, fetch=fetch):
249 super(ServicesHook, self).__init__(hookenv=hookenv)
250 self._hookenv = hookenv
251 self._cluster = cluster
252 self._host = host
253 self._paths = paths
254 self._subprocess = subprocess
255+ self._fetch = fetch
256
257 def _run(self):
258 leader_context = None
259@@ -49,13 +52,15 @@
260 leader_context = LandscapeLeaderContext(
261 host=self._host, hookenv=self._hookenv)
262
263- manager = ServiceManager([{
264+ haproxy_provider = HAProxyProvider(
265+ SERVICE_COUNTS, paths=self._paths, is_leader=is_leader)
266+
267+ manager = ServiceManager(services=[{
268 "service": "landscape",
269 "ports": [],
270 "provided_data": [
271 LandscapeProvider(leader_context),
272- HAProxyProvider(SERVICE_COUNTS, paths=self._paths,
273- is_leader=is_leader),
274+ haproxy_provider,
275 RabbitMQProvider(),
276 ],
277 # Required data is available to the render_template calls below.
278@@ -77,11 +82,27 @@
279 owner="landscape", group="root", perms=0o640,
280 source="landscape-server",
281 target=self._paths.default_file()),
282+ SetAPTSources(
283+ hookenv=self._hookenv, fetch=self._fetch,
284+ subprocess=self._subprocess),
285 EnsureConfigDir(paths=self._paths),
286 WriteCustomSSLCertificate(paths=self._paths),
287 SchemaBootstrap(subprocess=self._subprocess),
288 WriteLicenseFile(host=self._host, paths=self._paths),
289 ],
290- "start": LSCtl(subprocess=self._subprocess),
291+ "start": LSCtl(subprocess=self._subprocess, hookenv=self._hookenv),
292 }])
293+
294+ # XXX The services framework only triggers data providers within the
295+ # context of relation joined/changed hooks, however we also
296+ # want to trigger the haproxy provider if the SSL certificate
297+ # has changed.
298+ if self._hookenv.hook_name() == "config-changed":
299+ config = self._hookenv.config()
300+ if config.changed("ssl-cert") or config.changed("ssl-key"):
301+ relation_ids = self._hookenv.relation_ids(HAProxyProvider.name)
302+ data = haproxy_provider.provide_data()
303+ for relation_id in relation_ids:
304+ self._hookenv.relation_set(relation_id, data)
305+
306 manager.manage()
307
308=== modified file 'lib/tests/sample.py'
309--- lib/tests/sample.py 2015-05-06 09:57:45 +0000
310+++ lib/tests/sample.py 2015-05-14 14:52:22 +0000
311@@ -27,10 +27,15 @@
312 "password": "guessme",
313 }
314
315-SAMPLE_CONFIG_OPENID_DATA = {
316+SAMPLE_CONFIG = {
317+ "source": "ppa:landscape/14.10"
318+}
319+
320+SAMPLE_CONFIG_OPENID_DATA = SAMPLE_CONFIG.copy()
321+SAMPLE_CONFIG_OPENID_DATA.update({
322 "openid-provider-url": "http://openid-host/",
323 "openid-logout-url": "http://openid-host/logout",
324-}
325+})
326
327 SAMPLE_CONFIG_LICENSE_DATA = {
328 "license-file": base64.b64encode("license data"),
329
330=== modified file 'lib/tests/test_services.py'
331--- lib/tests/test_services.py 2015-05-06 10:47:36 +0000
332+++ lib/tests/test_services.py 2015-05-14 14:52:22 +0000
333@@ -1,13 +1,15 @@
334 import os
335+import base64
336+import yaml
337
338 from charmhelpers.core import templating
339
340 from lib.tests.helpers import HookenvTest
341-from lib.tests.stubs import ClusterStub, HostStub, SubprocessStub
342+from lib.tests.stubs import ClusterStub, HostStub, SubprocessStub, FetchStub
343 from lib.tests.sample import (
344 SAMPLE_DB_UNIT_DATA, SAMPLE_LEADER_CONTEXT_DATA, SAMPLE_AMQP_UNIT_DATA,
345 SAMPLE_CONFIG_LICENSE_DATA, SAMPLE_CONFIG_OPENID_DATA, SAMPLE_HOSTED_DATA,
346- SAMPLE_SERVICE_COUNT_DATA, SAMPLE_WEBSITE_UNIT_DATA)
347+ SAMPLE_SERVICE_COUNT_DATA, SAMPLE_WEBSITE_UNIT_DATA, SAMPLE_CONFIG)
348 from lib.services import ServicesHook
349 from lib.tests.rootdir import RootDir
350
351@@ -24,9 +26,10 @@
352 self.root_dir = self.useFixture(RootDir())
353 self.paths = self.root_dir.paths
354 self.root_dir = self.useFixture(RootDir())
355+ self.fetch = FetchStub()
356 self.hook = ServicesHook(
357 hookenv=self.hookenv, cluster=self.cluster, host=self.host,
358- subprocess=self.subprocess, paths=self.paths)
359+ subprocess=self.subprocess, paths=self.paths, fetch=self.fetch)
360
361 # XXX Monkey patch the templating API, charmhelpers doesn't sport
362 # any dependency injection here as well.
363@@ -34,7 +37,7 @@
364 self.addCleanup(setattr, templating, "render", templating.render)
365 templating.render = lambda *args: self.renders.append(args)
366
367- # Setup sample relation data for the "common" happy case (an LDS
368+ # Setup sample data for the "common" happy case (an LDS
369 # deployment with postgresql, haproxy and rabbitmq-server).
370 self.hookenv.relations = {
371 "db": {
372@@ -53,6 +56,7 @@
373 },
374 },
375 }
376+ self.hookenv.config().update(SAMPLE_CONFIG)
377
378 def test_db_relation_not_ready(self):
379 """
380@@ -100,7 +104,7 @@
381 "amqp": [SAMPLE_AMQP_UNIT_DATA],
382 "website": [SAMPLE_WEBSITE_UNIT_DATA],
383 "hosted": [SAMPLE_HOSTED_DATA],
384- "config": {},
385+ "config": SAMPLE_CONFIG,
386 "is_leader": True,
387 "service_counts": SAMPLE_SERVICE_COUNT_DATA,
388 }
389@@ -205,3 +209,27 @@
390 [("write_file", (self.paths.license_file(), "license data"),
391 {"owner": "landscape", "group": "root", "perms": 0o640})],
392 self.host.calls)
393+
394+ def test_apt_source(self):
395+ """
396+ If the source config changes, APT sources are refreshed.
397+ """
398+ config = self.hookenv.config()
399+ config["source"] = "ppa:landscape/14.10"
400+ config.save()
401+ config["source"] = "ppa:landscape/15.01"
402+ self.hook()
403+ self.assertTrue(len(self.fetch.sources) == 1)
404+
405+ def test_ssl_cert_changed(self):
406+ """
407+ If the SSL certificate changes, the relation with haproxy gets updated.
408+ """
409+ self.hookenv.hook = "config-changed"
410+ config = self.hookenv.config()
411+ config.save()
412+ config["ssl-cert"] = base64.b64encode(b"<cert>")
413+ config["ssl-key"] = base64.b64encode(b"<key>")
414+ self.hook()
415+ data = yaml.load(self.hookenv.relations["website:1"]["services"])
416+ self.assertIsNotNone(data)
417
418=== removed file 'tests/02-sslcert'
419--- tests/02-sslcert 2015-05-12 14:29:51 +0000
420+++ tests/02-sslcert 1970-01-01 00:00:00 +0000
421@@ -1,16 +0,0 @@
422-#!/usr/bin/python3
423-import base64
424-
425-from helpers import main
426-from sslcert.assets import CERT_FILE, KEY_FILE
427-
428-if __name__ == "__main__":
429- with open(CERT_FILE, "rb") as fd:
430- ssl_cert = fd.read()
431- with open(KEY_FILE, "rb") as fd:
432- ssl_key = fd.read()
433- config = {
434- "landscape": {
435- "ssl-cert": base64.b64encode(ssl_cert).decode("utf-8"),
436- "ssl-key": base64.b64encode(ssl_key).decode("utf-8")}}
437- main(config=config)
438
439=== renamed file 'tests/sslcert/assets.py' => 'tests/assets.py'
440--- tests/sslcert/assets.py 2015-05-12 14:29:51 +0000
441+++ tests/assets.py 2015-05-14 14:52:22 +0000
442@@ -1,5 +1,18 @@
443 import os
444+import base64
445
446-TEST_DIR = os.path.dirname(os.path.dirname(__file__))
447+TEST_DIR = os.path.dirname(__file__)
448 CERT_FILE = os.path.join(TEST_DIR, "sslcert", "server.crt")
449 KEY_FILE = os.path.join(TEST_DIR, "sslcert", "server.key")
450+
451+
452+def b64_ssl_cert():
453+ with open(CERT_FILE, "rb") as fd:
454+ ssl_cert = fd.read()
455+ return base64.b64encode(ssl_cert).decode("utf-8")
456+
457+
458+def b64_ssl_key():
459+ with open(KEY_FILE, "rb") as fd:
460+ ssl_key = fd.read()
461+ return base64.b64encode(ssl_key).decode("utf-8")
462
463=== renamed file 'tests/sslcert/test_config.py' => 'tests/basic/test_sslcert.py'
464--- tests/sslcert/test_config.py 2015-05-13 10:18:14 +0000
465+++ tests/basic/test_sslcert.py 2015-05-14 14:52:22 +0000
466@@ -5,14 +5,14 @@
467 a charm config option).
468 """
469
470-from sslcert.assets import CERT_FILE
471+from assets import CERT_FILE
472 from helpers import IntegrationTest, get_ssl_certificate_over_wire
473-from layers import OneLandscapeUnitLayer
474+from layers import OneLandscapeUnitCustomSSLCertificateLayer
475
476
477 class SSLConfigurationTest(IntegrationTest):
478
479- layer = OneLandscapeUnitLayer
480+ layer = OneLandscapeUnitCustomSSLCertificateLayer
481
482 def test_certificate_is_what_we_expect(self):
483 """
484
485=== modified file 'tests/helpers.py'
486--- tests/helpers.py 2015-05-13 10:21:31 +0000
487+++ tests/helpers.py 2015-05-14 14:52:22 +0000
488@@ -152,6 +152,17 @@
489 """Start the given Landscape service on the given unit."""
490 self._control_landscape_service("start", service, unit)
491
492+ def configure_ssl(self, cert, key):
493+ """Start the given Landscape service on the given unit."""
494+ self._deployment.configure(
495+ "landscape-server", {"ssl-cert": cert, "ssl-key": key})
496+ # Wait for initial landscape-server hooks to fire
497+ self._deployment.sentry.wait()
498+ # Wait for haproxy hooks to fire
499+ self._deployment.sentry.wait()
500+ # Wait for landscape-server hooks triggered by the haproxy ones to fire
501+ self._deployment.sentry.wait()
502+
503 def _get_charm_dir(self):
504 """Get the path to the root of the charm directory."""
505 return os.path.join(os.path.dirname(__file__), "..")
506@@ -257,6 +268,11 @@
507 global _config
508 _config = config
509
510+ # XXX This will force zope.testrunner to write to stderr, since stdout is
511+ # not being printed synchronously by "juju test", see also the call to
512+ # subprocess in charmtools.test.Orchestra.perform().
513+ sys.stdout = sys.stderr
514+
515 # Figure out the package holding the test files to use and run them.
516 path = os.path.join(os.getcwd(), "tests")
517 module = os.path.basename(sys.argv[0]).split("-")[1]
518
519=== modified file 'tests/layers.py'
520--- tests/layers.py 2015-05-13 10:18:14 +0000
521+++ tests/layers.py 2015-05-14 14:52:22 +0000
522@@ -1,4 +1,5 @@
523 from helpers import EnvironmentFixture, get_config
524+from assets import b64_ssl_cert, b64_ssl_key
525
526
527 class OneLandscapeUnitLayer(object):
528@@ -16,3 +17,20 @@
529 @classmethod
530 def tearDown(cls):
531 cls.environment.cleanUp()
532+
533+
534+class OneLandscapeUnitCustomSSLCertificateLayer(OneLandscapeUnitLayer):
535+ """Layer for all tests needing a deployment with a custom SSL certificate.
536+
537+ The deployment has the same structure as OneLandscapeUnitLayer, but a
538+ custom SSL certificate will be set on the landscape-service service, using
539+ the ssl-cert and ssl-key configuration options.
540+ """
541+
542+ @classmethod
543+ def setUp(cls):
544+ cls.environment.configure_ssl(b64_ssl_cert(), b64_ssl_key())
545+
546+ @classmethod
547+ def tearDown(cls):
548+ cls.environment.configure_ssl("", "")
549
550=== removed file 'tests/sslcert/__init__.py'

Subscribers

People subscribed via source and target branches