Merge lp:~1chb1n/charms/trusty/percona-cluster/next-amulet-initial into lp:~openstack-charmers-archive/charms/trusty/percona-cluster/next
- Trusty Tahr (14.04)
- next-amulet-initial
- Merge into next
Proposed by
Ryan Beisner
Status: | Work in progress |
---|---|
Proposed branch: | lp:~1chb1n/charms/trusty/percona-cluster/next-amulet-initial |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/percona-cluster/next |
Diff against target: |
608 lines (+317/-48) 20 files modified
Makefile (+5/-7) hooks/charmhelpers/contrib/charmsupport/nrpe.py (+3/-1) hooks/charmhelpers/contrib/database/mysql.py (+2/-2) hooks/charmhelpers/core/hookenv.py (+40/-1) hooks/charmhelpers/core/host.py (+5/-1) hooks/charmhelpers/core/services/helpers.py (+2/-2) hooks/charmhelpers/core/strutils.py (+2/-2) hooks/charmhelpers/core/unitdata.py (+1/-1) tests/00-setup.sh (+23/-21) tests/015-basic-trusty-icehouse (+9/-0) tests/016-basic-trusty-juno (+11/-0) tests/017-basic-trusty-kilo (+11/-0) tests/018-basic-utopic-juno (+9/-0) tests/019-basic-vivid-kilo (+9/-0) tests/100-deploy_test.py (+1/-1) tests/110-broken-mysqld.py (+1/-1) tests/120-kill-9-mysqld.py (+1/-1) tests/basic_deployment.py (+159/-0) tests/charmhelpers/contrib/amulet/utils.py (+8/-1) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+15/-6) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/percona-cluster/next-amulet-initial |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenStack Charmers | Pending | ||
Review via email: mp+257198@code.launchpad.net |
Commit message
Description of the change
Add initial openstack amulet tests; sync charmhelpers; keep existing tests disabled, pending validation (http://
To post a comment you must log in.
Unmerged revisions
- 63. By Ryan Beisner
-
amulet tests - add for openstack supported releases; disable existing tests, pending validation
- 62. By Ryan Beisner
-
amulet tests - update 00-setup, remove precise definition, mark existing tests non-executable until validated.
- 61. By Ryan Beisner
-
amulet tests - separate existing tests
- 60. By Ryan Beisner
-
amulet tests - add supported series/release definitions
- 59. By Ryan Beisner
-
amulet tests - rename existing
- 58. By Ryan Beisner
-
update makefile
- 57. By Ryan Beisner
-
sync charmhelpers
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Makefile' | |||
2 | --- Makefile 2015-04-20 10:53:43 +0000 | |||
3 | +++ Makefile 2015-04-22 21:53:21 +0000 | |||
4 | @@ -3,18 +3,16 @@ | |||
5 | 3 | export PYTHONPATH := hooks | 3 | export PYTHONPATH := hooks |
6 | 4 | 4 | ||
7 | 5 | lint: | 5 | lint: |
9 | 6 | @flake8 --exclude hooks/charmhelpers hooks | 6 | @flake8 --exclude hooks/charmhelpers hooks unit_tests tests |
10 | 7 | @charm proof | 7 | @charm proof |
11 | 8 | 8 | ||
12 | 9 | unit_test: | 9 | unit_test: |
13 | 10 | @$(PYTHON) /usr/bin/nosetests --nologcapture unit_tests | 10 | @$(PYTHON) /usr/bin/nosetests --nologcapture unit_tests |
14 | 11 | 11 | ||
21 | 12 | test: | 12 | functional_test: |
22 | 13 | @echo Starting amulet tests... | 13 | @echo Starting Amulet tests... |
23 | 14 | #NOTE(beisner): can remove -v after bug 1320357 is fixed | 14 | @juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700 |
24 | 15 | # https://bugs.launchpad.net/amulet/+bug/1320357 | 15 | # Previous tests disabled; http://pad.lv/1446169 |
19 | 16 | # @juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700 | ||
20 | 17 | echo "Tests disables; http://pad.lv/1446169" | ||
25 | 18 | 16 | ||
26 | 19 | bin/charm_helpers_sync.py: | 17 | bin/charm_helpers_sync.py: |
27 | 20 | @mkdir -p bin | 18 | @mkdir -p bin |
28 | 21 | 19 | ||
29 | === modified file 'hooks/charmhelpers/contrib/charmsupport/nrpe.py' | |||
30 | --- hooks/charmhelpers/contrib/charmsupport/nrpe.py 2015-02-20 00:30:39 +0000 | |||
31 | +++ hooks/charmhelpers/contrib/charmsupport/nrpe.py 2015-04-22 21:53:21 +0000 | |||
32 | @@ -247,7 +247,9 @@ | |||
33 | 247 | 247 | ||
34 | 248 | service('restart', 'nagios-nrpe-server') | 248 | service('restart', 'nagios-nrpe-server') |
35 | 249 | 249 | ||
37 | 250 | for rid in relation_ids("local-monitors"): | 250 | monitor_ids = relation_ids("local-monitors") + \ |
38 | 251 | relation_ids("nrpe-external-master") | ||
39 | 252 | for rid in monitor_ids: | ||
40 | 251 | relation_set(relation_id=rid, monitors=yaml.dump(monitors)) | 253 | relation_set(relation_id=rid, monitors=yaml.dump(monitors)) |
41 | 252 | 254 | ||
42 | 253 | 255 | ||
43 | 254 | 256 | ||
44 | === modified file 'hooks/charmhelpers/contrib/database/mysql.py' | |||
45 | --- hooks/charmhelpers/contrib/database/mysql.py 2015-04-21 09:29:08 +0000 | |||
46 | +++ hooks/charmhelpers/contrib/database/mysql.py 2015-04-22 21:53:21 +0000 | |||
47 | @@ -6,7 +6,7 @@ | |||
48 | 6 | import os | 6 | import os |
49 | 7 | import glob | 7 | import glob |
50 | 8 | 8 | ||
52 | 9 | from string import upper | 9 | # from string import upper |
53 | 10 | 10 | ||
54 | 11 | from charmhelpers.core.host import ( | 11 | from charmhelpers.core.host import ( |
55 | 12 | mkdir, | 12 | mkdir, |
56 | @@ -348,7 +348,7 @@ | |||
57 | 348 | key, mem = line.split(':', 2) | 348 | key, mem = line.split(':', 2) |
58 | 349 | if key == 'MemTotal': | 349 | if key == 'MemTotal': |
59 | 350 | mtot, modifier = mem.strip().split(' ') | 350 | mtot, modifier = mem.strip().split(' ') |
61 | 351 | return '%s%s' % (mtot, upper(modifier[0])) | 351 | return '%s%s' % (mtot, modifier[0].upper()) |
62 | 352 | 352 | ||
63 | 353 | def parse_config(self): | 353 | def parse_config(self): |
64 | 354 | """Parse charm configuration and calculate values for config files.""" | 354 | """Parse charm configuration and calculate values for config files.""" |
65 | 355 | 355 | ||
66 | === modified file 'hooks/charmhelpers/core/hookenv.py' | |||
67 | --- hooks/charmhelpers/core/hookenv.py 2015-02-04 18:56:00 +0000 | |||
68 | +++ hooks/charmhelpers/core/hookenv.py 2015-04-22 21:53:21 +0000 | |||
69 | @@ -20,11 +20,13 @@ | |||
70 | 20 | # Authors: | 20 | # Authors: |
71 | 21 | # Charm Helpers Developers <juju@lists.ubuntu.com> | 21 | # Charm Helpers Developers <juju@lists.ubuntu.com> |
72 | 22 | 22 | ||
73 | 23 | from __future__ import print_function | ||
74 | 23 | import os | 24 | import os |
75 | 24 | import json | 25 | import json |
76 | 25 | import yaml | 26 | import yaml |
77 | 26 | import subprocess | 27 | import subprocess |
78 | 27 | import sys | 28 | import sys |
79 | 29 | import errno | ||
80 | 28 | from subprocess import CalledProcessError | 30 | from subprocess import CalledProcessError |
81 | 29 | 31 | ||
82 | 30 | import six | 32 | import six |
83 | @@ -87,7 +89,18 @@ | |||
84 | 87 | if not isinstance(message, six.string_types): | 89 | if not isinstance(message, six.string_types): |
85 | 88 | message = repr(message) | 90 | message = repr(message) |
86 | 89 | command += [message] | 91 | command += [message] |
88 | 90 | subprocess.call(command) | 92 | # Missing juju-log should not cause failures in unit tests |
89 | 93 | # Send log output to stderr | ||
90 | 94 | try: | ||
91 | 95 | subprocess.call(command) | ||
92 | 96 | except OSError as e: | ||
93 | 97 | if e.errno == errno.ENOENT: | ||
94 | 98 | if level: | ||
95 | 99 | message = "{}: {}".format(level, message) | ||
96 | 100 | message = "juju-log: {}".format(message) | ||
97 | 101 | print(message, file=sys.stderr) | ||
98 | 102 | else: | ||
99 | 103 | raise | ||
100 | 91 | 104 | ||
101 | 92 | 105 | ||
102 | 93 | class Serializable(UserDict): | 106 | class Serializable(UserDict): |
103 | @@ -566,3 +579,29 @@ | |||
104 | 566 | def charm_dir(): | 579 | def charm_dir(): |
105 | 567 | """Return the root directory of the current charm""" | 580 | """Return the root directory of the current charm""" |
106 | 568 | return os.environ.get('CHARM_DIR') | 581 | return os.environ.get('CHARM_DIR') |
107 | 582 | |||
108 | 583 | |||
109 | 584 | @cached | ||
110 | 585 | def action_get(key=None): | ||
111 | 586 | """Gets the value of an action parameter, or all key/value param pairs""" | ||
112 | 587 | cmd = ['action-get'] | ||
113 | 588 | if key is not None: | ||
114 | 589 | cmd.append(key) | ||
115 | 590 | cmd.append('--format=json') | ||
116 | 591 | action_data = json.loads(subprocess.check_output(cmd).decode('UTF-8')) | ||
117 | 592 | return action_data | ||
118 | 593 | |||
119 | 594 | |||
120 | 595 | def action_set(values): | ||
121 | 596 | """Sets the values to be returned after the action finishes""" | ||
122 | 597 | cmd = ['action-set'] | ||
123 | 598 | for k, v in list(values.items()): | ||
124 | 599 | cmd.append('{}={}'.format(k, v)) | ||
125 | 600 | subprocess.check_call(cmd) | ||
126 | 601 | |||
127 | 602 | |||
128 | 603 | def action_fail(message): | ||
129 | 604 | """Sets the action status to failed and sets the error message. | ||
130 | 605 | |||
131 | 606 | The results set by action_set are preserved.""" | ||
132 | 607 | subprocess.check_call(['action-fail', message]) | ||
133 | 569 | 608 | ||
134 | === modified file 'hooks/charmhelpers/core/host.py' | |||
135 | --- hooks/charmhelpers/core/host.py 2015-03-03 02:26:12 +0000 | |||
136 | +++ hooks/charmhelpers/core/host.py 2015-04-22 21:53:21 +0000 | |||
137 | @@ -339,12 +339,16 @@ | |||
138 | 339 | def pwgen(length=None): | 339 | def pwgen(length=None): |
139 | 340 | """Generate a random pasword.""" | 340 | """Generate a random pasword.""" |
140 | 341 | if length is None: | 341 | if length is None: |
141 | 342 | # A random length is ok to use a weak PRNG | ||
142 | 342 | length = random.choice(range(35, 45)) | 343 | length = random.choice(range(35, 45)) |
143 | 343 | alphanumeric_chars = [ | 344 | alphanumeric_chars = [ |
144 | 344 | l for l in (string.ascii_letters + string.digits) | 345 | l for l in (string.ascii_letters + string.digits) |
145 | 345 | if l not in 'l0QD1vAEIOUaeiou'] | 346 | if l not in 'l0QD1vAEIOUaeiou'] |
146 | 347 | # Use a crypto-friendly PRNG (e.g. /dev/urandom) for making the | ||
147 | 348 | # actual password | ||
148 | 349 | random_generator = random.SystemRandom() | ||
149 | 346 | random_chars = [ | 350 | random_chars = [ |
151 | 347 | random.choice(alphanumeric_chars) for _ in range(length)] | 351 | random_generator.choice(alphanumeric_chars) for _ in range(length)] |
152 | 348 | return(''.join(random_chars)) | 352 | return(''.join(random_chars)) |
153 | 349 | 353 | ||
154 | 350 | 354 | ||
155 | 351 | 355 | ||
156 | === modified file 'hooks/charmhelpers/core/services/helpers.py' | |||
157 | --- hooks/charmhelpers/core/services/helpers.py 2015-03-03 02:26:12 +0000 | |||
158 | +++ hooks/charmhelpers/core/services/helpers.py 2015-04-22 21:53:21 +0000 | |||
159 | @@ -139,7 +139,7 @@ | |||
160 | 139 | 139 | ||
161 | 140 | def __init__(self, *args, **kwargs): | 140 | def __init__(self, *args, **kwargs): |
162 | 141 | self.required_keys = ['host', 'user', 'password', 'database'] | 141 | self.required_keys = ['host', 'user', 'password', 'database'] |
164 | 142 | super(HttpRelation).__init__(self, *args, **kwargs) | 142 | RelationContext.__init__(self, *args, **kwargs) |
165 | 143 | 143 | ||
166 | 144 | 144 | ||
167 | 145 | class HttpRelation(RelationContext): | 145 | class HttpRelation(RelationContext): |
168 | @@ -154,7 +154,7 @@ | |||
169 | 154 | 154 | ||
170 | 155 | def __init__(self, *args, **kwargs): | 155 | def __init__(self, *args, **kwargs): |
171 | 156 | self.required_keys = ['host', 'port'] | 156 | self.required_keys = ['host', 'port'] |
173 | 157 | super(HttpRelation).__init__(self, *args, **kwargs) | 157 | RelationContext.__init__(self, *args, **kwargs) |
174 | 158 | 158 | ||
175 | 159 | def provide_data(self): | 159 | def provide_data(self): |
176 | 160 | return { | 160 | return { |
177 | 161 | 161 | ||
178 | === modified file 'hooks/charmhelpers/core/strutils.py' | |||
179 | --- hooks/charmhelpers/core/strutils.py 2015-02-25 17:29:36 +0000 | |||
180 | +++ hooks/charmhelpers/core/strutils.py 2015-04-22 21:53:21 +0000 | |||
181 | @@ -33,9 +33,9 @@ | |||
182 | 33 | 33 | ||
183 | 34 | value = value.strip().lower() | 34 | value = value.strip().lower() |
184 | 35 | 35 | ||
186 | 36 | if value in ['y', 'yes', 'true', 't']: | 36 | if value in ['y', 'yes', 'true', 't', 'on']: |
187 | 37 | return True | 37 | return True |
189 | 38 | elif value in ['n', 'no', 'false', 'f']: | 38 | elif value in ['n', 'no', 'false', 'f', 'off']: |
190 | 39 | return False | 39 | return False |
191 | 40 | 40 | ||
192 | 41 | msg = "Unable to interpret string value '%s' as boolean" % (value) | 41 | msg = "Unable to interpret string value '%s' as boolean" % (value) |
193 | 42 | 42 | ||
194 | === modified file 'hooks/charmhelpers/core/unitdata.py' | |||
195 | --- hooks/charmhelpers/core/unitdata.py 2015-02-25 17:29:36 +0000 | |||
196 | +++ hooks/charmhelpers/core/unitdata.py 2015-04-22 21:53:21 +0000 | |||
197 | @@ -443,7 +443,7 @@ | |||
198 | 443 | data = hookenv.execution_environment() | 443 | data = hookenv.execution_environment() |
199 | 444 | self.conf = conf_delta = self.kv.delta(data['conf'], 'config') | 444 | self.conf = conf_delta = self.kv.delta(data['conf'], 'config') |
200 | 445 | self.rels = rels_delta = self.kv.delta(data['rels'], 'rels') | 445 | self.rels = rels_delta = self.kv.delta(data['rels'], 'rels') |
202 | 446 | self.kv.set('env', data['env']) | 446 | self.kv.set('env', dict(data['env'])) |
203 | 447 | self.kv.set('unit', data['unit']) | 447 | self.kv.set('unit', data['unit']) |
204 | 448 | self.kv.set('relid', data.get('relid')) | 448 | self.kv.set('relid', data.get('relid')) |
205 | 449 | return conf_delta, rels_delta | 449 | return conf_delta, rels_delta |
206 | 450 | 450 | ||
207 | === modified file 'tests/00-setup.sh' | |||
208 | --- tests/00-setup.sh 2015-04-15 12:11:46 +0000 | |||
209 | +++ tests/00-setup.sh 2015-04-22 21:53:21 +0000 | |||
210 | @@ -1,24 +1,26 @@ | |||
232 | 1 | #!/bin/bash -x | 1 | #!/bin/bash |
233 | 2 | # The script installs amulet and other tools needed for the amulet tests. | 2 | |
234 | 3 | 3 | set -ex | |
235 | 4 | # Get the status of the amulet package, this returns 0 of package is installed. | 4 | |
236 | 5 | dpkg -s amulet | 5 | sudo add-apt-repository --yes ppa:juju/stable |
237 | 6 | if [ $? -ne 0 ]; then | 6 | sudo apt-get update --yes |
238 | 7 | # Install the Amulet testing harness. | 7 | sudo apt-get install --yes python-amulet \ |
239 | 8 | sudo add-apt-repository -y ppa:juju/stable | 8 | python3 \ |
240 | 9 | sudo apt-get update | 9 | python3-yaml \ |
241 | 10 | sudo apt-get install -y -q amulet juju-core charm-tools | 10 | python3-pip \ |
242 | 11 | fi | 11 | python-keystoneclient |
243 | 12 | 12 | ||
244 | 13 | 13 | # Enable http proxy if AMULET_HTTP_PROXY is set | |
245 | 14 | PACKAGES="python3 python3-yaml" | 14 | #if [[ -n "$AMULET_HTTP_PROXY" ]]; then |
246 | 15 | for pkg in $PACKAGES; do | 15 | # export HTTP_PROXY=$AMULET_HTTP_PROXY |
247 | 16 | dpkg -s python3 | 16 | # export HTTPS_PROXY=$(echo $AMULET_HTTP_PROXY | sed 's/http/https/g') |
248 | 17 | if [ $? -ne 0 ]; then | 17 | # export http_proxy=$HTTP_PROXY |
249 | 18 | sudo apt-get install -y -q $pkg | 18 | # export https_proxy=$HTTPS_PROXY |
250 | 19 | fi | 19 | # env | egrep "proxy|PROXY" |
251 | 20 | done | 20 | #fi |
252 | 21 | 21 | ||
253 | 22 | # Setup for generic mysql amulet test (Not in main < Vivid, pip it instead) | ||
254 | 23 | #sudo -E pip3 install PyMySQL | ||
255 | 22 | 24 | ||
256 | 23 | #if [ ! -f "$(dirname $0)/../local.yaml" ]; then | 25 | #if [ ! -f "$(dirname $0)/../local.yaml" ]; then |
257 | 24 | # echo "To run these amulet tests a vip is needed, create a file called \ | 26 | # echo "To run these amulet tests a vip is needed, create a file called \ |
258 | 25 | 27 | ||
259 | === added file 'tests/015-basic-trusty-icehouse' | |||
260 | --- tests/015-basic-trusty-icehouse 1970-01-01 00:00:00 +0000 | |||
261 | +++ tests/015-basic-trusty-icehouse 2015-04-22 21:53:21 +0000 | |||
262 | @@ -0,0 +1,9 @@ | |||
263 | 1 | #!/usr/bin/python | ||
264 | 2 | |||
265 | 3 | """Amulet tests on a basic mysql deployment on trusty-icehouse.""" | ||
266 | 4 | |||
267 | 5 | from basic_deployment import PerconaClusterBasicDeployment | ||
268 | 6 | |||
269 | 7 | if __name__ == '__main__': | ||
270 | 8 | deployment = PerconaClusterBasicDeployment(series='trusty') | ||
271 | 9 | deployment.run_tests() | ||
272 | 0 | 10 | ||
273 | === added file 'tests/016-basic-trusty-juno' | |||
274 | --- tests/016-basic-trusty-juno 1970-01-01 00:00:00 +0000 | |||
275 | +++ tests/016-basic-trusty-juno 2015-04-22 21:53:21 +0000 | |||
276 | @@ -0,0 +1,11 @@ | |||
277 | 1 | #!/usr/bin/python | ||
278 | 2 | |||
279 | 3 | """Amulet tests on a basic mysql deployment on trusty-juno.""" | ||
280 | 4 | |||
281 | 5 | from basic_deployment import PerconaClusterBasicDeployment | ||
282 | 6 | |||
283 | 7 | if __name__ == '__main__': | ||
284 | 8 | deployment = PerconaClusterBasicDeployment(series='trusty', | ||
285 | 9 | openstack='cloud:trusty-juno', | ||
286 | 10 | source='cloud:trusty-updates/juno') | ||
287 | 11 | deployment.run_tests() | ||
288 | 0 | 12 | ||
289 | === added file 'tests/017-basic-trusty-kilo' | |||
290 | --- tests/017-basic-trusty-kilo 1970-01-01 00:00:00 +0000 | |||
291 | +++ tests/017-basic-trusty-kilo 2015-04-22 21:53:21 +0000 | |||
292 | @@ -0,0 +1,11 @@ | |||
293 | 1 | #!/usr/bin/python | ||
294 | 2 | |||
295 | 3 | """Amulet tests on a basic mysql deployment on trusty-kilo.""" | ||
296 | 4 | |||
297 | 5 | from basic_deployment import PerconaClusterBasicDeployment | ||
298 | 6 | |||
299 | 7 | if __name__ == '__main__': | ||
300 | 8 | deployment = PerconaClusterBasicDeployment(series='trusty', | ||
301 | 9 | openstack='cloud:trusty-kilo', | ||
302 | 10 | source='cloud:trusty-updates/kilo') | ||
303 | 11 | deployment.run_tests() | ||
304 | 0 | 12 | ||
305 | === added file 'tests/018-basic-utopic-juno' | |||
306 | --- tests/018-basic-utopic-juno 1970-01-01 00:00:00 +0000 | |||
307 | +++ tests/018-basic-utopic-juno 2015-04-22 21:53:21 +0000 | |||
308 | @@ -0,0 +1,9 @@ | |||
309 | 1 | #!/usr/bin/python | ||
310 | 2 | |||
311 | 3 | """Amulet tests on a basic mysql deployment on utopic-juno.""" | ||
312 | 4 | |||
313 | 5 | from basic_deployment import PerconaClusterBasicDeployment | ||
314 | 6 | |||
315 | 7 | if __name__ == '__main__': | ||
316 | 8 | deployment = PerconaClusterBasicDeployment(series='utopic') | ||
317 | 9 | deployment.run_tests() | ||
318 | 0 | 10 | ||
319 | === added file 'tests/019-basic-vivid-kilo' | |||
320 | --- tests/019-basic-vivid-kilo 1970-01-01 00:00:00 +0000 | |||
321 | +++ tests/019-basic-vivid-kilo 2015-04-22 21:53:21 +0000 | |||
322 | @@ -0,0 +1,9 @@ | |||
323 | 1 | #!/usr/bin/python | ||
324 | 2 | |||
325 | 3 | """Amulet tests on a basic mysql deployment on vivid-kilo.""" | ||
326 | 4 | |||
327 | 5 | from basic_deployment import PerconaClusterBasicDeployment | ||
328 | 6 | |||
329 | 7 | if __name__ == '__main__': | ||
330 | 8 | deployment = PerconaClusterBasicDeployment(series='vivid') | ||
331 | 9 | deployment.run_tests() | ||
332 | 0 | 10 | ||
333 | === renamed file 'tests/10-deploy_test.py' => 'tests/100-deploy_test.py' (properties changed: +x to -x) | |||
334 | --- tests/10-deploy_test.py 2015-03-06 15:35:01 +0000 | |||
335 | +++ tests/100-deploy_test.py 2015-04-22 21:53:21 +0000 | |||
336 | @@ -1,7 +1,7 @@ | |||
337 | 1 | #!/usr/bin/python3 | 1 | #!/usr/bin/python3 |
338 | 2 | # test percona-cluster (3 nodes) | 2 | # test percona-cluster (3 nodes) |
339 | 3 | 3 | ||
341 | 4 | import basic_deployment | 4 | import 1xx_basic_deployment |
342 | 5 | import time | 5 | import time |
343 | 6 | 6 | ||
344 | 7 | 7 | ||
345 | 8 | 8 | ||
346 | === renamed file 'tests/20-broken-mysqld.py' => 'tests/110-broken-mysqld.py' (properties changed: +x to -x) | |||
347 | --- tests/20-broken-mysqld.py 2015-03-06 15:35:01 +0000 | |||
348 | +++ tests/110-broken-mysqld.py 2015-04-22 21:53:21 +0000 | |||
349 | @@ -1,7 +1,7 @@ | |||
350 | 1 | #!/usr/bin/python3 | 1 | #!/usr/bin/python3 |
351 | 2 | # test percona-cluster (3 nodes) | 2 | # test percona-cluster (3 nodes) |
352 | 3 | 3 | ||
354 | 4 | import basic_deployment | 4 | import 1xx_basic_deployment |
355 | 5 | import time | 5 | import time |
356 | 6 | 6 | ||
357 | 7 | 7 | ||
358 | 8 | 8 | ||
359 | === renamed file 'tests/30-kill-9-mysqld.py' => 'tests/120-kill-9-mysqld.py' (properties changed: +x to -x) | |||
360 | --- tests/30-kill-9-mysqld.py 2015-04-15 14:24:59 +0000 | |||
361 | +++ tests/120-kill-9-mysqld.py 2015-04-22 21:53:21 +0000 | |||
362 | @@ -1,7 +1,7 @@ | |||
363 | 1 | #!/usr/bin/python3 | 1 | #!/usr/bin/python3 |
364 | 2 | # test percona-cluster (3 nodes) | 2 | # test percona-cluster (3 nodes) |
365 | 3 | 3 | ||
367 | 4 | import basic_deployment | 4 | import 1xx_basic_deployment |
368 | 5 | import time | 5 | import time |
369 | 6 | 6 | ||
370 | 7 | 7 | ||
371 | 8 | 8 | ||
372 | === renamed file 'tests/basic_deployment.py' => 'tests/1xx_basic_deployment.py' | |||
373 | === added file 'tests/basic_deployment.py' | |||
374 | --- tests/basic_deployment.py 1970-01-01 00:00:00 +0000 | |||
375 | +++ tests/basic_deployment.py 2015-04-22 21:53:21 +0000 | |||
376 | @@ -0,0 +1,159 @@ | |||
377 | 1 | #!/usr/bin/python | ||
378 | 2 | |||
379 | 3 | import amulet | ||
380 | 4 | |||
381 | 5 | from charmhelpers.contrib.openstack.amulet.deployment import ( | ||
382 | 6 | OpenStackAmuletDeployment | ||
383 | 7 | ) | ||
384 | 8 | |||
385 | 9 | from charmhelpers.contrib.openstack.amulet.utils import ( # noqa | ||
386 | 10 | OpenStackAmuletUtils, | ||
387 | 11 | DEBUG, | ||
388 | 12 | ERROR | ||
389 | 13 | ) | ||
390 | 14 | |||
391 | 15 | # Use DEBUG to turn on debug logging | ||
392 | 16 | u = OpenStackAmuletUtils(DEBUG) | ||
393 | 17 | |||
394 | 18 | |||
395 | 19 | class PerconaClusterBasicDeployment(OpenStackAmuletDeployment): | ||
396 | 20 | """Amulet tests on a basic percona-cluster deployment.""" | ||
397 | 21 | |||
398 | 22 | def __init__(self, series=None, openstack=None, source=None, | ||
399 | 23 | git=False, stable=False): | ||
400 | 24 | """Deploy the test environment.""" | ||
401 | 25 | super(PerconaClusterBasicDeployment, self).__init__(series, openstack, | ||
402 | 26 | source, stable) | ||
403 | 27 | self.git = git | ||
404 | 28 | self._add_services() | ||
405 | 29 | self._add_relations() | ||
406 | 30 | self._configure_services() | ||
407 | 31 | self._deploy() | ||
408 | 32 | self._initialize_tests() | ||
409 | 33 | |||
410 | 34 | def _add_services(self): | ||
411 | 35 | """Add services | ||
412 | 36 | |||
413 | 37 | Add the services that we're testing, where MySQL is local, | ||
414 | 38 | and the rest of the service are from lp branches that are | ||
415 | 39 | compatible with the local charm (e.g. stable or next). | ||
416 | 40 | """ | ||
417 | 41 | this_service = {'name': 'mysql'} | ||
418 | 42 | other_services = [{'name': 'keystone'}] | ||
419 | 43 | super(PerconaClusterBasicDeployment, self)._add_services(this_service, | ||
420 | 44 | other_services) | ||
421 | 45 | |||
422 | 46 | def _add_relations(self): | ||
423 | 47 | """Add all of the relations for the services.""" | ||
424 | 48 | relations = {'mysql:shared-db': 'keystone:shared-db'} | ||
425 | 49 | super(PerconaClusterBasicDeployment, self)._add_relations(relations) | ||
426 | 50 | |||
427 | 51 | def _configure_services(self): | ||
428 | 52 | """Configure all of the services.""" | ||
429 | 53 | |||
430 | 54 | mysql_config = {} | ||
431 | 55 | keystone_config = {'admin-password': 'openstack', | ||
432 | 56 | 'admin-token': 'ubuntutesting'} | ||
433 | 57 | |||
434 | 58 | configs = {'mysql': mysql_config, | ||
435 | 59 | 'keystone': keystone_config} | ||
436 | 60 | super(PerconaClusterBasicDeployment, self)._configure_services(configs) | ||
437 | 61 | |||
438 | 62 | def _initialize_tests(self): | ||
439 | 63 | """Perform final initialization before tests get run.""" | ||
440 | 64 | # Access the sentries for inspecting service units | ||
441 | 65 | self.mysql_sentry = self.d.sentry.unit['mysql/0'] | ||
442 | 66 | self.keystone_sentry = self.d.sentry.unit['keystone/0'] | ||
443 | 67 | |||
444 | 68 | # Authenticate keystone admin | ||
445 | 69 | self.keystone = u.authenticate_keystone_admin(self.keystone_sentry, | ||
446 | 70 | user='admin', | ||
447 | 71 | password='openstack', | ||
448 | 72 | tenant='admin') | ||
449 | 73 | |||
450 | 74 | def test_100_services(self): | ||
451 | 75 | """Verify the expected services are running on the corresponding | ||
452 | 76 | service units.""" | ||
453 | 77 | commands = { | ||
454 | 78 | self.mysql_sentry: ['status mysql'], | ||
455 | 79 | self.keystone_sentry: ['status keystone'] | ||
456 | 80 | } | ||
457 | 81 | ret = u.validate_services(commands) | ||
458 | 82 | if ret: | ||
459 | 83 | amulet.raise_status(amulet.FAIL, msg=ret) | ||
460 | 84 | |||
461 | 85 | def test_120_pxc_keystone_database_query(self): | ||
462 | 86 | """Verify that the user table in the keystone mysql database | ||
463 | 87 | contains an admin user with a specific email address.""" | ||
464 | 88 | |||
465 | 89 | cmd = ("export FOO=$(sudo cat /var/lib/mysql/mysql.passwd);" | ||
466 | 90 | "mysql -u root -p$FOO -e " | ||
467 | 91 | "\"SELECT extra FROM keystone.user WHERE name='admin';\"") | ||
468 | 92 | |||
469 | 93 | output, retcode = self.mysql_sentry.run(cmd) | ||
470 | 94 | u.log.debug('command: `{}` returned {}'.format(cmd, retcode)) | ||
471 | 95 | u.log.debug('output:\n{}'.format(output)) | ||
472 | 96 | |||
473 | 97 | if retcode: | ||
474 | 98 | msg = "command `{}` returned {}".format(cmd, str(retcode)) | ||
475 | 99 | amulet.raise_status(amulet.FAIL, msg=msg) | ||
476 | 100 | |||
477 | 101 | if "juju@localhost" not in output: | ||
478 | 102 | msg = ("keystone mysql database query produced " | ||
479 | 103 | "unexpected data:\n{}".format(output)) | ||
480 | 104 | amulet.raise_status(amulet.FAIL, msg=msg) | ||
481 | 105 | |||
482 | 106 | def test_150_pxc_shared_db_relation(self): | ||
483 | 107 | """Verify the mysql shared-db relation data""" | ||
484 | 108 | unit = self.mysql_sentry | ||
485 | 109 | relation = ['shared-db', 'keystone:shared-db'] | ||
486 | 110 | expected_data = { | ||
487 | 111 | 'allowed_units': 'keystone/0', | ||
488 | 112 | 'private-address': u.valid_ip, | ||
489 | 113 | 'password': u.not_null, | ||
490 | 114 | 'db_host': u.valid_ip | ||
491 | 115 | } | ||
492 | 116 | ret = u.validate_relation_data(unit, relation, expected_data) | ||
493 | 117 | if ret: | ||
494 | 118 | message = u.relation_error('mysql shared-db', ret) | ||
495 | 119 | amulet.raise_status(amulet.FAIL, msg=message) | ||
496 | 120 | |||
497 | 121 | def test_200_pxc_default_config(self): | ||
498 | 122 | """Verify some important confg data in the mysql config file's | ||
499 | 123 | mysqld section.""" | ||
500 | 124 | unit = self.mysql_sentry | ||
501 | 125 | conf = '/etc/mysql/my.cnf' | ||
502 | 126 | relation = unit.relation('shared-db', 'keystone:shared-db') | ||
503 | 127 | u.log.debug('relation: {}'.format(relation)) | ||
504 | 128 | expected = {'user': 'mysql', | ||
505 | 129 | 'socket': '/var/run/mysqld/mysqld.sock', | ||
506 | 130 | 'port': '3306', | ||
507 | 131 | 'basedir': '/usr', | ||
508 | 132 | 'datadir': '/var/lib/mysql', | ||
509 | 133 | 'myisam-recover': 'BACKUP', | ||
510 | 134 | 'query_cache_size': '0', | ||
511 | 135 | 'query_cache_type': '0', | ||
512 | 136 | 'tmpdir': '/tmp', | ||
513 | 137 | 'bind-address': '0.0.0.0', | ||
514 | 138 | 'log_error': '/var/log/mysql/error.log', | ||
515 | 139 | 'character-set-server': 'utf8'} | ||
516 | 140 | |||
517 | 141 | ret = u.validate_config_data(unit, conf, 'mysqld', expected) | ||
518 | 142 | if ret: | ||
519 | 143 | message = "mysql config error: {}".format(ret) | ||
520 | 144 | amulet.raise_status(amulet.FAIL, msg=message) | ||
521 | 145 | |||
522 | 146 | def test_900_restart_on_config_change(self): | ||
523 | 147 | """Verify that mysql is restarted when the config is changed.""" | ||
524 | 148 | |||
525 | 149 | logging.debug("Changing config on mysql...") | ||
526 | 150 | self.d.configure('mysql', {'dataset-size': '50%'}) | ||
527 | 151 | |||
528 | 152 | logging.debug("Checking that the service has restarted...") | ||
529 | 153 | if not u.service_restarted(self.mysql_sentry, 'mysql', | ||
530 | 154 | '/etc/mysql/my.cnf', | ||
531 | 155 | sleep_time=30): | ||
532 | 156 | self.d.configure('mysql', {'dataset-size': '80%'}) | ||
533 | 157 | message = "mysql service didn't restart after config change" | ||
534 | 158 | amulet.raise_status(amulet.FAIL, msg=message) | ||
535 | 159 | self.d.configure('mysql', {'dataset-size': '80%'}) | ||
536 | 0 | 160 | ||
537 | === modified file 'tests/charmhelpers/contrib/amulet/utils.py' | |||
538 | --- tests/charmhelpers/contrib/amulet/utils.py 2015-04-15 14:23:37 +0000 | |||
539 | +++ tests/charmhelpers/contrib/amulet/utils.py 2015-04-22 21:53:21 +0000 | |||
540 | @@ -79,6 +79,9 @@ | |||
541 | 79 | for k, v in six.iteritems(commands): | 79 | for k, v in six.iteritems(commands): |
542 | 80 | for cmd in v: | 80 | for cmd in v: |
543 | 81 | output, code = k.run(cmd) | 81 | output, code = k.run(cmd) |
544 | 82 | self.log.debug('{} `{}` returned ' | ||
545 | 83 | '{}'.format(k.info['unit_name'], | ||
546 | 84 | cmd, code)) | ||
547 | 82 | if code != 0: | 85 | if code != 0: |
548 | 83 | return "command `{}` returned {}".format(cmd, str(code)) | 86 | return "command `{}` returned {}".format(cmd, str(code)) |
549 | 84 | return None | 87 | return None |
550 | @@ -86,7 +89,11 @@ | |||
551 | 86 | def _get_config(self, unit, filename): | 89 | def _get_config(self, unit, filename): |
552 | 87 | """Get a ConfigParser object for parsing a unit's config file.""" | 90 | """Get a ConfigParser object for parsing a unit's config file.""" |
553 | 88 | file_contents = unit.file_contents(filename) | 91 | file_contents = unit.file_contents(filename) |
555 | 89 | config = ConfigParser.ConfigParser() | 92 | |
556 | 93 | # NOTE(beisner): by default, ConfigParser does not handle options | ||
557 | 94 | # with no value, such as the flags used in the mysql my.cnf file. | ||
558 | 95 | # https://bugs.python.org/issue7005 | ||
559 | 96 | config = ConfigParser.ConfigParser(allow_no_value=True) | ||
560 | 90 | config.readfp(io.StringIO(file_contents)) | 97 | config.readfp(io.StringIO(file_contents)) |
561 | 91 | return config | 98 | return config |
562 | 92 | 99 | ||
563 | 93 | 100 | ||
564 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' | |||
565 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-17 10:04:59 +0000 | |||
566 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-22 21:53:21 +0000 | |||
567 | @@ -46,15 +46,22 @@ | |||
568 | 46 | stable or next branches for the other_services.""" | 46 | stable or next branches for the other_services.""" |
569 | 47 | base_charms = ['mysql', 'mongodb'] | 47 | base_charms = ['mysql', 'mongodb'] |
570 | 48 | 48 | ||
571 | 49 | if self.series in ['precise', 'trusty']: | ||
572 | 50 | base_series = self.series | ||
573 | 51 | else: | ||
574 | 52 | base_series = self.current_next | ||
575 | 53 | |||
576 | 49 | if self.stable: | 54 | if self.stable: |
577 | 50 | for svc in other_services: | 55 | for svc in other_services: |
580 | 51 | temp = 'lp:charms/{}' | 56 | temp = 'lp:charms/{}/{}' |
581 | 52 | svc['location'] = temp.format(svc['name']) | 57 | svc['location'] = temp.format(base_series, |
582 | 58 | svc['name']) | ||
583 | 53 | else: | 59 | else: |
584 | 54 | for svc in other_services: | 60 | for svc in other_services: |
585 | 55 | if svc['name'] in base_charms: | 61 | if svc['name'] in base_charms: |
588 | 56 | temp = 'lp:charms/{}' | 62 | temp = 'lp:charms/{}/{}' |
589 | 57 | svc['location'] = temp.format(svc['name']) | 63 | svc['location'] = temp.format(base_series, |
590 | 64 | svc['name']) | ||
591 | 58 | else: | 65 | else: |
592 | 59 | temp = 'lp:~openstack-charmers/charms/{}/{}/next' | 66 | temp = 'lp:~openstack-charmers/charms/{}/{}/next' |
593 | 60 | svc['location'] = temp.format(self.current_next, | 67 | svc['location'] = temp.format(self.current_next, |
594 | @@ -99,10 +106,12 @@ | |||
595 | 99 | Return an integer representing the enum value of the openstack | 106 | Return an integer representing the enum value of the openstack |
596 | 100 | release. | 107 | release. |
597 | 101 | """ | 108 | """ |
598 | 109 | # Must be ordered by OpenStack release (not by Ubuntu release): | ||
599 | 102 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, | 110 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, |
600 | 103 | self.precise_havana, self.precise_icehouse, | 111 | self.precise_havana, self.precise_icehouse, |
603 | 104 | self.trusty_icehouse, self.trusty_juno, self.trusty_kilo, | 112 | self.trusty_icehouse, self.trusty_juno, self.utopic_juno, |
604 | 105 | self.utopic_juno, self.vivid_kilo) = range(10) | 113 | self.trusty_kilo, self.vivid_kilo) = range(10) |
605 | 114 | |||
606 | 106 | releases = { | 115 | releases = { |
607 | 107 | ('precise', None): self.precise_essex, | 116 | ('precise', None): self.precise_essex, |
608 | 108 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, | 117 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, |