Merge lp:~ack/charms/trusty/keystone/pause-and-resume into lp:~openstack-charmers-archive/charms/trusty/keystone/next
- Trusty Tahr (14.04)
- pause-and-resume
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 173 |
Proposed branch: | lp:~ack/charms/trusty/keystone/pause-and-resume |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/keystone/next |
Diff against target: |
584 lines (+300/-48) 12 files modified
.coveragerc (+1/-0) actions.yaml (+11/-0) actions/actions.py (+56/-0) actions/git_reinstall.py (+3/-5) charm-helpers-hooks.yaml (+1/-1) hooks/keystone_utils.py (+11/-22) tests/basic_deployment.py (+33/-0) unit_tests/test_actions.py (+150/-0) unit_tests/test_actions_git_reinstall.py (+6/-4) unit_tests/test_keystone_contexts.py (+16/-6) unit_tests/test_keystone_hooks.py (+9/-9) unit_tests/test_keystone_utils.py (+3/-1) |
To merge this branch: | bzr merge lp:~ack/charms/trusty/keystone/pause-and-resume |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Billy Olsen | Approve | ||
Adam Collard (community) | Approve | ||
Ryan Beisner (community) | Approve | ||
Geoff Teale (community) | Approve | ||
OpenStack Charmers | Pending | ||
Review via email: mp+267931@code.launchpad.net |
Commit message
Description of the change
This branch adds pause/resume actions that can be used to pause the service for maintenance on a unit.
Alberto Donato (ack) wrote : | # |
Adam Collard (adam-collard) wrote : | # |
You should stop all of the services that are started by the charm - namely apache2 and haproxy - look at BASE_RESOURCE_MAP in keystone_utils.py
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #7984 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7398 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5776 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #7986 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7400 keystone-next for ack mp267931
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full unit test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5778 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7402 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #7989 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8040 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7451 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5784 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8041 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7452 keystone-next for ack mp267931
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full unit test output: http://
Build: http://
Alberto Donato (ack) wrote : | # |
> You should stop all of the services that are started by the charm - namely
> apache2 and haproxy - look at BASE_RESOURCE_MAP in keystone_utils.py
Good catch, it's fixed now.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8043 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7454 keystone-next for ack mp267931
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full unit test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5787 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5785 keystone-next for ack mp267931
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://
Build: http://
Ryan Beisner (1chb1n) wrote : | # |
Thank you for your work on this. These will be great test additions.
I'd like to see the added amulet tests and helpers land in basic_deployment.py (or charmhelpers where appropriate) so that we can maintain consistency across the os-charms in the way that we iterate ubuntu/openstack series/release.
This means adding new test_ methods in basic_deploymen
If there are OpenStack-specific, amulet-specific helpers which are useful in other charm tests, please land those in charmhelpers/
If there are non-OpenStack-
Often times, during test dev, I'll keep all of my helpers as local helpers in basic_deploymen
Feel free to holler with any questions. Thanks again!
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8192 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7594 keystone-next for ack mp267931
UNIT OK: passed
- 195. By Alberto Donato
-
Lint.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8193 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7595 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5838 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5839 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
- 196. By Alberto Donato
-
Move actions to action.py
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8338 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7735 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5881 keystone-next for ack mp267931
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://
Build: http://
- 197. By Alberto Donato
-
Fix mocking, again.
- 198. By Alberto Donato
-
Add missing files,
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8339 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7736 keystone-next for ack mp267931
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full unit test output: http://
Build: http://
- 199. By Alberto Donato
-
Fix unittest.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5882 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8340 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7737 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5883 keystone-next for ack mp267931
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://
Build: http://
- 200. By Alberto Donato
-
Fix docstrings.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8341 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7738 keystone-next for ack mp267931
UNIT OK: passed
- 201. By Alberto Donato
-
Add missing shebang.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5884 keystone-next for ack mp267931
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://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8342 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7739 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5885 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
Alberto Donato (ack) wrote : | # |
@Ryan, thanks for the feedback. I've aligned the changes in this branch with the swift-storage one.
It should be good for another round of review.
Adam Collard (adam-collard) wrote : | # |
5 inline comments below :)
- 202. By Alberto Donato
-
Merge from -next.
- 203. By Alberto Donato
-
Undo charm sync.
- 204. By Alberto Donato
-
Address review comments.
- 205. By Alberto Donato
-
Use right executable names.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8367 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7764 keystone-next for ack mp267931
UNIT OK: passed
Alberto Donato (ack) wrote : | # |
> 5 inline comments below :)
All comments addressed, thanks
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8368 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7765 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5910 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
Ryan Beisner (1chb1n) wrote : | # |
RE: Amulet tests
Thank you for your work on this.
Please do another charm-helper sync to pull in sparkiegeek's tests/charmhelpers/ system service status check and py3 drive-by fixes.
Otherwise, looks good to me.
- 206. By Alberto Donato
-
charmhelpers sync.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8483 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7874 keystone-next for ack mp267931
UNIT OK: passed
Ryan Beisner (1chb1n) wrote : | # |
Although the amulet job isn't done, I checked its status as of 019 vivid-kilo, and all passed.
All clear to merge as far as test perspective.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #5942 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
- 207. By Alberto Donato
-
Merge from next, fix conflict.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8647 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #7984 keystone-next for ack mp267931
UNIT OK: passed
Adam Collard (adam-collard) wrote : | # |
Thanks for your patience and work on getting this to match style of swift-storage. Looks good! +1
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #6012 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
Billy Olsen (billy-olsen) wrote : | # |
Thanks for the submission! I think this generally looks good and would be quite pleased to approve it for a single unit operation. However, in the case where keystone is scaled out and paired with the hacluster charm I think we want to do some cluster appropriate operations first (e.g. move resources off-node pre-emptively).
That's probably common code to be shared amongst other charms, but I think we definitely need to consider the scenario in which a service is paused/resumed in a cluster. If its paused and resources are moved away, does it need to be able to ensure that resources cannot be moved back to the node which may cause confusion.
Will mark the review as Needs Information for now while this is sorted.
Billy Olsen (billy-olsen) wrote : | # |
After discussion, the hacluster charm can handle the move of the VIP - which is probably an appropriate place to put it. It needs to move the vip off of this node and mark the cluster in maintenance mode so that services aren't moved around. That can be handled by the hacluster charm itself.
However, this would introduce a 2 step process for the user to be able to do things without service disruption. It would require they first run the pause action against the hacluster charm and then run the pause action against the keystone charm. It would be ideal if the charm could enforce this or invoke the hacluster pause action for the node, however that might be over complicating things for the basic building blocks here.
At a minimum I think we need some better docs describing this behavior in the actions.yaml file and possibly the consequences of not performing the node movement.
Thinking something along the lines of (though I'm sure there's better wordsmithing available):
Note: when pausing the keystone services when keystone is clustered using the hacluster charm, the hacluster unit on this node must first be paused as well. Not doing so may lead to an interruption of service.
- 208. By Alberto Donato
-
Fix actions description.
Alberto Donato (ack) wrote : | # |
@Billy thanks for the review and suggestion, I've expanded the actions description.
- 209. By Alberto Donato
-
Lint.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #8929 keystone-next for ack mp267931
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #8252 keystone-next for ack mp267931
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #6078 keystone-next for ack mp267931
AMULET OK: passed
Build: http://
Billy Olsen (billy-olsen) wrote : | # |
On further inspection, its not clear why the charmhelpers were moved out of the hooks directory to the root directory of the charm but the amulet tests continues to have its own charmhelpers installation. I'm not holding this merge proposal up based on this comment, but I also noticed the same in the swift storage charm (and likely glance, though I haven't looked there yet).
Thanks for the contribution Alberto!
Preview Diff
1 | === modified file '.coveragerc' |
2 | --- .coveragerc 2014-03-31 10:18:06 +0000 |
3 | +++ .coveragerc 2015-08-28 06:58:18 +0000 |
4 | @@ -4,3 +4,4 @@ |
5 | if __name__ == .__main__.: |
6 | include= |
7 | hooks/keystone_* |
8 | + actions/actions.py |
9 | |
10 | === modified file 'actions.yaml' |
11 | --- actions.yaml 2015-03-20 01:15:23 +0000 |
12 | +++ actions.yaml 2015-08-28 06:58:18 +0000 |
13 | @@ -1,2 +1,13 @@ |
14 | git-reinstall: |
15 | description: Reinstall keystone from the openstack-origin-git repositories. |
16 | +pause: |
17 | + description: | |
18 | + Pause keystone services. |
19 | + If the keystone deployment is clustered using the hacluster charm, the |
20 | + corresponding hacluster unit on the node must first be paused as well. |
21 | + Not doing so may lead to an interruption of service. |
22 | +resume: |
23 | + description: | |
24 | + Resume keystone services. |
25 | + If the keystone deployment is clustered using the hacluster charm, the |
26 | + corresponding hacluster unit on the node must be resumed as well. |
27 | |
28 | === added file 'actions/__init__.py' |
29 | === added file 'actions/actions.py' |
30 | --- actions/actions.py 1970-01-01 00:00:00 +0000 |
31 | +++ actions/actions.py 2015-08-28 06:58:18 +0000 |
32 | @@ -0,0 +1,56 @@ |
33 | +#!/usr/bin/python |
34 | + |
35 | +import sys |
36 | +import os |
37 | + |
38 | +from charmhelpers.core.host import service_pause, service_resume |
39 | +from charmhelpers.core.hookenv import action_fail, status_set |
40 | + |
41 | +from hooks.keystone_utils import services |
42 | + |
43 | + |
44 | +def pause(args): |
45 | + """Pause all the Keystone services. |
46 | + |
47 | + @raises Exception if any services fail to stop |
48 | + """ |
49 | + for service in services(): |
50 | + stopped = service_pause(service) |
51 | + if not stopped: |
52 | + raise Exception("{} didn't stop cleanly.".format(service)) |
53 | + status_set( |
54 | + "maintenance", "Paused. Use 'resume' action to resume normal service.") |
55 | + |
56 | + |
57 | +def resume(args): |
58 | + """Resume all the Keystone services. |
59 | + |
60 | + @raises Exception if any services fail to start |
61 | + """ |
62 | + for service in services(): |
63 | + started = service_resume(service) |
64 | + if not started: |
65 | + raise Exception("{} didn't start cleanly.".format(service)) |
66 | + status_set("active", "") |
67 | + |
68 | + |
69 | +# A dictionary of all the defined actions to callables (which take |
70 | +# parsed arguments). |
71 | +ACTIONS = {"pause": pause, "resume": resume} |
72 | + |
73 | + |
74 | +def main(args): |
75 | + action_name = os.path.basename(args[0]) |
76 | + try: |
77 | + action = ACTIONS[action_name] |
78 | + except KeyError: |
79 | + return "Action %s undefined" % action_name |
80 | + else: |
81 | + try: |
82 | + action(args) |
83 | + except Exception as e: |
84 | + action_fail(str(e)) |
85 | + |
86 | + |
87 | +if __name__ == "__main__": |
88 | + sys.exit(main(sys.argv)) |
89 | |
90 | === added symlink 'actions/charmhelpers' |
91 | === target is u'../charmhelpers' |
92 | === modified file 'actions/git_reinstall.py' |
93 | --- actions/git_reinstall.py 2015-04-15 16:33:30 +0000 |
94 | +++ actions/git_reinstall.py 2015-08-28 06:58:18 +0000 |
95 | @@ -1,9 +1,7 @@ |
96 | #!/usr/bin/python |
97 | -import sys |
98 | + |
99 | import traceback |
100 | |
101 | -sys.path.append('hooks/') |
102 | - |
103 | from charmhelpers.contrib.openstack.utils import ( |
104 | git_install_requested, |
105 | ) |
106 | @@ -14,11 +12,11 @@ |
107 | config, |
108 | ) |
109 | |
110 | -from keystone_utils import ( |
111 | +from hooks.keystone_utils import ( |
112 | git_install, |
113 | ) |
114 | |
115 | -from keystone_hooks import ( |
116 | +from hooks.keystone_hooks import ( |
117 | config_changed, |
118 | ) |
119 | |
120 | |
121 | === added symlink 'actions/hooks' |
122 | === target is u'../hooks' |
123 | === added symlink 'actions/pause' |
124 | === target is u'actions.py' |
125 | === added symlink 'actions/resume' |
126 | === target is u'actions.py' |
127 | === modified file 'charm-helpers-hooks.yaml' |
128 | --- charm-helpers-hooks.yaml 2015-07-31 13:10:52 +0000 |
129 | +++ charm-helpers-hooks.yaml 2015-08-28 06:58:18 +0000 |
130 | @@ -1,5 +1,5 @@ |
131 | branch: lp:charm-helpers |
132 | -destination: hooks/charmhelpers |
133 | +destination: charmhelpers |
134 | include: |
135 | - core |
136 | - cli |
137 | |
138 | === renamed directory 'hooks/charmhelpers' => 'charmhelpers' |
139 | === added file 'hooks/__init__.py' |
140 | === added symlink 'hooks/charmhelpers' |
141 | === target is u'../charmhelpers' |
142 | === modified file 'hooks/keystone_utils.py' |
143 | --- hooks/keystone_utils.py 2015-06-10 13:59:24 +0000 |
144 | +++ hooks/keystone_utils.py 2015-08-28 06:58:18 +0000 |
145 | @@ -14,6 +14,7 @@ |
146 | import urlparse |
147 | import uuid |
148 | |
149 | +from itertools import chain |
150 | from base64 import b64encode |
151 | from collections import OrderedDict |
152 | from copy import deepcopy |
153 | @@ -150,11 +151,6 @@ |
154 | 'keystone', |
155 | ] |
156 | |
157 | -API_PORTS = { |
158 | - 'keystone-admin': config('admin-port'), |
159 | - 'keystone-public': config('service-port') |
160 | -} |
161 | - |
162 | KEYSTONE_CONF = "/etc/keystone/keystone.conf" |
163 | KEYSTONE_LOGGER_CONF = "/etc/keystone/logging.conf" |
164 | KEYSTONE_CONF_DIR = os.path.dirname(KEYSTONE_CONF) |
165 | @@ -178,7 +174,6 @@ |
166 | CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' |
167 | SSL_SYNC_SEMAPHORE = threading.Semaphore() |
168 | SSL_DIRS = [SSL_DIR, APACHE_SSL_DIR, CA_CERT_PATH] |
169 | - |
170 | BASE_RESOURCE_MAP = OrderedDict([ |
171 | (KEYSTONE_CONF, { |
172 | 'services': BASE_SERVICES, |
173 | @@ -321,11 +316,8 @@ |
174 | |
175 | |
176 | def services(): |
177 | - """Returns a list of services associate with this charm""" |
178 | - _services = [] |
179 | - for v in restart_map().values(): |
180 | - _services = _services + v |
181 | - return list(set(_services)) |
182 | + """Returns a list of (unique) services associated with this charm""" |
183 | + return list(set(chain(*restart_map().values()))) |
184 | |
185 | |
186 | def determine_ports(): |
187 | @@ -335,23 +327,20 @@ |
188 | |
189 | |
190 | def api_port(service): |
191 | - return API_PORTS[service] |
192 | + return { |
193 | + 'keystone-admin': config('admin-port'), |
194 | + 'keystone-public': config('service-port') |
195 | + }[service] |
196 | |
197 | |
198 | def determine_packages(): |
199 | # currently all packages match service names |
200 | - packages = [] + BASE_PACKAGES |
201 | - for k, v in resource_map().iteritems(): |
202 | - packages.extend(v['services']) |
203 | - |
204 | + packages = set(services()).union(BASE_PACKAGES) |
205 | if git_install_requested(): |
206 | - packages.extend(BASE_GIT_PACKAGES) |
207 | - # don't include packages that will be installed from git |
208 | - packages = list(set(packages)) |
209 | - for p in GIT_PACKAGE_BLACKLIST: |
210 | - packages.remove(p) |
211 | + packages |= set(BASE_GIT_PACKAGES) |
212 | + packages -= set(GIT_PACKAGE_BLACKLIST) |
213 | |
214 | - return list(set(packages)) |
215 | + return sorted(packages) |
216 | |
217 | |
218 | def save_script_rc(): |
219 | |
220 | === modified file 'tests/basic_deployment.py' |
221 | --- tests/basic_deployment.py 2015-07-13 16:07:29 +0000 |
222 | +++ tests/basic_deployment.py 2015-08-28 06:58:18 +0000 |
223 | @@ -38,6 +38,21 @@ |
224 | self._deploy() |
225 | self._initialize_tests() |
226 | |
227 | + def _assert_services(self, should_run): |
228 | + u.get_unit_process_ids( |
229 | + {self.keystone_sentry: ("keystone-all", "apache2", "haproxy")}, |
230 | + expect_success=should_run) |
231 | + |
232 | + def get_service_overrides(self, unit): |
233 | + """ |
234 | + Return a dict mapping service names to a boolean indicating whether |
235 | + an override file exists for that service. |
236 | + """ |
237 | + init_contents = unit.directory_contents("/etc/init/") |
238 | + return { |
239 | + service: "{}.override".format(service) in init_contents["files"] |
240 | + for service in ("keystone", "apache2", "haproxy")} |
241 | + |
242 | def _add_services(self): |
243 | """Add services |
244 | |
245 | @@ -462,3 +477,21 @@ |
246 | sleep_time = 0 |
247 | |
248 | self.d.configure(juju_service, set_default) |
249 | + |
250 | + def test_901_pause_resume(self): |
251 | + """Test pause and resume actions.""" |
252 | + unit_name = "keystone/0" |
253 | + unit = self.d.sentry.unit[unit_name] |
254 | + self._assert_services(should_run=True) |
255 | + action_id = u.run_action(unit, "pause") |
256 | + assert u.wait_on_action(action_id), "Pause action failed." |
257 | + |
258 | + self._assert_services(should_run=False) |
259 | + assert all(self.get_service_overrides(unit).itervalues()), \ |
260 | + "Not all override files were created." |
261 | + |
262 | + action_id = u.run_action(unit, "resume") |
263 | + assert u.wait_on_action(action_id), "Resume action failed" |
264 | + assert not any(self.get_service_overrides(unit).itervalues()), \ |
265 | + "Not all override files were removed." |
266 | + self._assert_services(should_run=True) |
267 | |
268 | === added file 'unit_tests/test_actions.py' |
269 | --- unit_tests/test_actions.py 1970-01-01 00:00:00 +0000 |
270 | +++ unit_tests/test_actions.py 2015-08-28 06:58:18 +0000 |
271 | @@ -0,0 +1,150 @@ |
272 | +import mock |
273 | + |
274 | +from test_utils import CharmTestCase |
275 | + |
276 | +import actions.actions |
277 | + |
278 | + |
279 | +class PauseTestCase(CharmTestCase): |
280 | + |
281 | + def setUp(self): |
282 | + super(PauseTestCase, self).setUp( |
283 | + actions.actions, ["service_pause", "status_set"]) |
284 | + |
285 | + def test_pauses_services(self): |
286 | + """Pause action pauses all Keystone services.""" |
287 | + pause_calls = [] |
288 | + |
289 | + def fake_service_pause(svc): |
290 | + pause_calls.append(svc) |
291 | + return True |
292 | + |
293 | + self.service_pause.side_effect = fake_service_pause |
294 | + |
295 | + actions.actions.pause([]) |
296 | + self.assertEqual(pause_calls, ['haproxy', 'keystone', 'apache2']) |
297 | + |
298 | + def test_bails_out_early_on_error(self): |
299 | + """Pause action fails early if there are errors stopping a service.""" |
300 | + pause_calls = [] |
301 | + |
302 | + def maybe_kill(svc): |
303 | + if svc == "keystone": |
304 | + return False |
305 | + else: |
306 | + pause_calls.append(svc) |
307 | + return True |
308 | + |
309 | + self.service_pause.side_effect = maybe_kill |
310 | + self.assertRaisesRegexp( |
311 | + Exception, "keystone didn't stop cleanly.", |
312 | + actions.actions.pause, []) |
313 | + self.assertEqual(pause_calls, ['haproxy']) |
314 | + |
315 | + def test_status_mode(self): |
316 | + """Pause action sets the status to maintenance.""" |
317 | + status_calls = [] |
318 | + self.status_set.side_effect = lambda state, msg: status_calls.append( |
319 | + state) |
320 | + |
321 | + actions.actions.pause([]) |
322 | + self.assertEqual(status_calls, ["maintenance"]) |
323 | + |
324 | + def test_status_message(self): |
325 | + """Pause action sets a status message reflecting that it's paused.""" |
326 | + status_calls = [] |
327 | + self.status_set.side_effect = lambda state, msg: status_calls.append( |
328 | + msg) |
329 | + |
330 | + actions.actions.pause([]) |
331 | + self.assertEqual( |
332 | + status_calls, ["Paused. " |
333 | + "Use 'resume' action to resume normal service."]) |
334 | + |
335 | + |
336 | +class ResumeTestCase(CharmTestCase): |
337 | + |
338 | + def setUp(self): |
339 | + super(ResumeTestCase, self).setUp( |
340 | + actions.actions, ["service_resume", "status_set"]) |
341 | + |
342 | + def test_resumes_services(self): |
343 | + """Resume action resumes all Keystone services.""" |
344 | + resume_calls = [] |
345 | + |
346 | + def fake_service_resume(svc): |
347 | + resume_calls.append(svc) |
348 | + return True |
349 | + |
350 | + self.service_resume.side_effect = fake_service_resume |
351 | + actions.actions.resume([]) |
352 | + self.assertEqual(resume_calls, ['haproxy', 'keystone', 'apache2']) |
353 | + |
354 | + def test_bails_out_early_on_error(self): |
355 | + """Resume action fails early if there are errors starting a service.""" |
356 | + resume_calls = [] |
357 | + |
358 | + def maybe_kill(svc): |
359 | + if svc == "keystone": |
360 | + return False |
361 | + else: |
362 | + resume_calls.append(svc) |
363 | + return True |
364 | + |
365 | + self.service_resume.side_effect = maybe_kill |
366 | + self.assertRaisesRegexp( |
367 | + Exception, "keystone didn't start cleanly.", |
368 | + actions.actions.resume, []) |
369 | + self.assertEqual(resume_calls, ['haproxy']) |
370 | + |
371 | + def test_status_mode(self): |
372 | + """Resume action sets the status to maintenance.""" |
373 | + status_calls = [] |
374 | + self.status_set.side_effect = lambda state, msg: status_calls.append( |
375 | + state) |
376 | + |
377 | + actions.actions.resume([]) |
378 | + self.assertEqual(status_calls, ["active"]) |
379 | + |
380 | + def test_status_message(self): |
381 | + """Resume action sets an empty status message.""" |
382 | + status_calls = [] |
383 | + self.status_set.side_effect = lambda state, msg: status_calls.append( |
384 | + msg) |
385 | + |
386 | + actions.actions.resume([]) |
387 | + self.assertEqual(status_calls, [""]) |
388 | + |
389 | + |
390 | +class MainTestCase(CharmTestCase): |
391 | + |
392 | + def setUp(self): |
393 | + super(MainTestCase, self).setUp(actions.actions, ["action_fail"]) |
394 | + |
395 | + def test_invokes_action(self): |
396 | + dummy_calls = [] |
397 | + |
398 | + def dummy_action(args): |
399 | + dummy_calls.append(True) |
400 | + |
401 | + with mock.patch.dict(actions.actions.ACTIONS, {"foo": dummy_action}): |
402 | + actions.actions.main(["foo"]) |
403 | + self.assertEqual(dummy_calls, [True]) |
404 | + |
405 | + def test_unknown_action(self): |
406 | + """Unknown actions aren't a traceback.""" |
407 | + exit_string = actions.actions.main(["foo"]) |
408 | + self.assertEqual("Action foo undefined", exit_string) |
409 | + |
410 | + def test_failing_action(self): |
411 | + """Actions which traceback trigger action_fail() calls.""" |
412 | + dummy_calls = [] |
413 | + |
414 | + self.action_fail.side_effect = dummy_calls.append |
415 | + |
416 | + def dummy_action(args): |
417 | + raise ValueError("uh oh") |
418 | + |
419 | + with mock.patch.dict(actions.actions.ACTIONS, {"foo": dummy_action}): |
420 | + actions.actions.main(["foo"]) |
421 | + self.assertEqual(dummy_calls, ["uh oh"]) |
422 | |
423 | === modified file 'unit_tests/test_actions_git_reinstall.py' |
424 | --- unit_tests/test_actions_git_reinstall.py 2015-04-15 16:33:30 +0000 |
425 | +++ unit_tests/test_actions_git_reinstall.py 2015-08-28 06:58:18 +0000 |
426 | @@ -4,8 +4,8 @@ |
427 | config.return_value = 'keystone' |
428 | import keystone_utils as utils # noqa |
429 | |
430 | -with patch('keystone_utils.register_configs') as register_configs: |
431 | - import git_reinstall |
432 | + with patch('keystone_utils.register_configs') as register_configs: |
433 | + import git_reinstall |
434 | |
435 | from test_utils import ( |
436 | CharmTestCase |
437 | @@ -36,8 +36,10 @@ |
438 | @patch.object(git_reinstall, 'action_fail') |
439 | @patch.object(git_reinstall, 'git_install') |
440 | @patch.object(git_reinstall, 'config_changed') |
441 | - def test_git_reinstall(self, config_changed, git_install, action_fail, |
442 | - action_set): |
443 | + @patch('charmhelpers.contrib.openstack.utils.config') |
444 | + def test_git_reinstall(self, config, config_changed, git_install, |
445 | + action_fail, action_set): |
446 | + config.return_value = openstack_origin_git |
447 | self.test_config.set('openstack-origin-git', openstack_origin_git) |
448 | |
449 | git_reinstall.git_reinstall() |
450 | |
451 | === modified file 'unit_tests/test_keystone_contexts.py' |
452 | --- unit_tests/test_keystone_contexts.py 2015-03-18 13:48:33 +0000 |
453 | +++ unit_tests/test_keystone_contexts.py 2015-08-28 06:58:18 +0000 |
454 | @@ -1,3 +1,5 @@ |
455 | +import os |
456 | + |
457 | import keystone_context as context |
458 | from mock import patch, MagicMock |
459 | |
460 | @@ -45,6 +47,7 @@ |
461 | self.assertTrue(mock_ensure_permissions.called) |
462 | self.assertFalse(mock_get_ca.called) |
463 | |
464 | + @patch('keystone_utils.determine_ports') |
465 | @patch('keystone_utils.is_ssl_cert_master') |
466 | @patch('keystone_utils.is_ssl_enabled') |
467 | @patch('charmhelpers.contrib.openstack.context.config') |
468 | @@ -60,7 +63,8 @@ |
469 | mock_is_clustered, |
470 | mock_config, |
471 | mock_is_ssl_enabled, |
472 | - mock_is_ssl_cert_master): |
473 | + mock_is_ssl_cert_master, |
474 | + mock_determine_ports): |
475 | mock_is_ssl_enabled.return_value = True |
476 | mock_is_ssl_cert_master.return_value = True |
477 | mock_https.return_value = True |
478 | @@ -69,6 +73,7 @@ |
479 | mock_determine_apache_port.return_value = '34' |
480 | mock_is_clustered.return_value = False |
481 | mock_config.return_value = None |
482 | + mock_determine_ports.return_value = ['12'] |
483 | |
484 | ctxt = context.ApacheSSLContext() |
485 | ctxt.enable_modules = MagicMock() |
486 | @@ -83,6 +88,7 @@ |
487 | self.assertTrue(mock_https.called) |
488 | mock_unit_get.assert_called_with('private-address') |
489 | |
490 | + @patch('keystone_utils.api_port') |
491 | @patch('charmhelpers.contrib.openstack.context.get_netmask_for_address') |
492 | @patch('charmhelpers.contrib.openstack.context.get_address_in_network') |
493 | @patch('charmhelpers.contrib.openstack.context.config') |
494 | @@ -95,7 +101,10 @@ |
495 | def test_haproxy_context_service_enabled( |
496 | self, mock_open, mock_log, mock_relation_get, mock_related_units, |
497 | mock_unit_get, mock_relation_ids, mock_config, |
498 | - mock_get_address_in_network, mock_get_netmask_for_address): |
499 | + mock_get_address_in_network, mock_get_netmask_for_address, |
500 | + mock_api_port): |
501 | + os.environ['JUJU_UNIT_NAME'] = 'keystone' |
502 | + |
503 | mock_relation_ids.return_value = ['identity-service:0', ] |
504 | mock_unit_get.return_value = '1.2.3.4' |
505 | mock_relation_get.return_value = '10.0.0.0' |
506 | @@ -104,19 +113,20 @@ |
507 | mock_get_address_in_network.return_value = None |
508 | mock_get_netmask_for_address.return_value = '255.255.255.0' |
509 | self.determine_apache_port.return_value = '34' |
510 | + mock_api_port.return_value = '12' |
511 | |
512 | ctxt = context.HAProxyContext() |
513 | |
514 | self.maxDiff = None |
515 | self.assertEquals( |
516 | ctxt(), |
517 | - {'listen_ports': {'admin_port': 'keystone', |
518 | - 'public_port': 'keystone'}, |
519 | + {'listen_ports': {'admin_port': '12', |
520 | + 'public_port': '12'}, |
521 | 'local_host': '127.0.0.1', |
522 | 'haproxy_host': '0.0.0.0', |
523 | 'stat_port': ':8888', |
524 | - 'service_ports': {'admin-port': ['keystone', '34'], |
525 | - 'public-port': ['keystone', '34']}, |
526 | + 'service_ports': {'admin-port': ['12', '34'], |
527 | + 'public-port': ['12', '34']}, |
528 | 'default_backend': '1.2.3.4', |
529 | 'frontends': {'1.2.3.4': { |
530 | 'network': '1.2.3.4/255.255.255.0', |
531 | |
532 | === modified file 'unit_tests/test_keystone_hooks.py' |
533 | --- unit_tests/test_keystone_hooks.py 2015-07-21 13:44:57 +0000 |
534 | +++ unit_tests/test_keystone_hooks.py 2015-08-28 06:58:18 +0000 |
535 | @@ -92,9 +92,9 @@ |
536 | self.configure_installation_source.assert_called_with(repo) |
537 | self.assertTrue(self.apt_update.called) |
538 | self.apt_install.assert_called_with( |
539 | - ['haproxy', 'unison', 'python-keystoneclient', |
540 | - 'uuid', 'python-mysqldb', 'openssl', 'apache2', |
541 | - 'pwgen', 'python-six', 'keystone', 'python-psycopg2'], fatal=True) |
542 | + ['apache2', 'haproxy', 'keystone', 'openssl', 'pwgen', |
543 | + 'python-keystoneclient', 'python-mysqldb', 'python-psycopg2', |
544 | + 'python-six', 'unison', 'uuid'], fatal=True) |
545 | self.git_install.assert_called_with(None) |
546 | |
547 | @patch.object(utils, 'git_install_requested') |
548 | @@ -120,12 +120,12 @@ |
549 | self.configure_installation_source.assert_called_with(repo) |
550 | self.assertTrue(self.apt_update.called) |
551 | self.apt_install.assert_called_with( |
552 | - ['haproxy', 'unison', 'python-setuptools', 'python-keystoneclient', |
553 | - 'uuid', 'python-mysqldb', 'libmysqlclient-dev', 'libssl-dev', |
554 | - 'openssl', 'libffi-dev', 'apache2', 'python-pip', 'pwgen', |
555 | - 'python-six', 'libxslt1-dev', 'python-psycopg2', 'libyaml-dev', |
556 | - 'zlib1g-dev', 'python-dev', 'libxml2-dev'], |
557 | - fatal=True) |
558 | + ['apache2', 'haproxy', 'libffi-dev', 'libmysqlclient-dev', |
559 | + 'libssl-dev', 'libxml2-dev', 'libxslt1-dev', 'libyaml-dev', |
560 | + 'openssl', 'pwgen', 'python-dev', 'python-keystoneclient', |
561 | + 'python-mysqldb', 'python-pip', 'python-psycopg2', |
562 | + 'python-setuptools', 'python-six', 'unison', 'uuid', |
563 | + 'zlib1g-dev'], fatal=True) |
564 | self.git_install.assert_called_with(projects_yaml) |
565 | |
566 | mod_ch_openstack_utils = 'charmhelpers.contrib.openstack.utils' |
567 | |
568 | === modified file 'unit_tests/test_keystone_utils.py' |
569 | --- unit_tests/test_keystone_utils.py 2015-06-10 20:44:02 +0000 |
570 | +++ unit_tests/test_keystone_utils.py 2015-08-28 06:58:18 +0000 |
571 | @@ -281,11 +281,13 @@ |
572 | self.relation_set.assert_called_with(relation_id=relation_id, |
573 | **filtered) |
574 | |
575 | + @patch('charmhelpers.contrib.openstack.ip.config') |
576 | @patch.object(utils, 'ensure_valid_service') |
577 | @patch.object(utils, 'add_endpoint') |
578 | @patch.object(manager, 'KeystoneManager') |
579 | def test_add_service_to_keystone_nosubset( |
580 | - self, KeystoneManager, add_endpoint, ensure_valid_service): |
581 | + self, KeystoneManager, add_endpoint, ensure_valid_service, |
582 | + ip_config): |
583 | relation_id = 'identity-service:0' |
584 | remote_unit = 'unit/0' |
585 |
There's also a charmhelpers sync to pull fixes for service_ pause/resume.