650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
1 |
#!/usr/bin/env python
|
915.2.7
by seman.said at canonical
Updated comp-test per review suggestion. |
2 |
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
3 |
from argparse import ArgumentParser |
650.1.7
by Aaron Bentley
Start testing mixed environs. |
4 |
from contextlib import contextmanager |
1053.1.1
by Martin Packman
Refactor log collection to ensure local logs are only collected once |
5 |
import logging |
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
6 |
from textwrap import dedent |
678
by Aaron Bentley
Support retrying certain 1.18 operations with system juju. |
7 |
from subprocess import CalledProcessError |
1074.3.1
by seman.said at canonical
Added script to run client-server test on Windows. |
8 |
import sys |
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
9 |
|
1515.2.1
by Martin Packman
Move fake_juju_client and related code into a new top level fakejuju file |
10 |
from fakejuju import ( |
11 |
fake_juju_client, |
|
12 |
)
|
|
1485.1.1
by Martin
Switch all imports of local_charm_path to using jujucharm over utility |
13 |
from jujucharm import ( |
14 |
local_charm_path, |
|
15 |
)
|
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
16 |
from jujupy import ( |
1465.5.2
by Aaron Bentley
Implement client_from_config, delete by_version. |
17 |
client_from_config, |
1341.3.3
by Aaron Bentley
Get working. |
18 |
EnvJujuClient1X, |
1504.1.2
by Aaron Bentley
Handle JujuData incompatibility. |
19 |
IncompatibleConfigClass, |
663.1.9
by Aaron Bentley
Assess heterogenous-control supports --upload-tools. |
20 |
SimpleEnvironment, |
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
21 |
until_timeout, |
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
22 |
)
|
23 |
from deploy_stack import ( |
|
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
24 |
BootstrapManager, |
650.1.7
by Aaron Bentley
Start testing mixed environs. |
25 |
check_token, |
26 |
get_random_string, |
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
27 |
)
|
915.2.3
by seman.said at canonical
Updated code per review suggestion |
28 |
from jujuci import add_credential_args |
1345.1.3
by Seman
Deploy charm by path. |
29 |
from utility import ( |
30 |
configure_logging, |
|
31 |
)
|
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
32 |
|
33 |
||
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
34 |
def prepare_dummy_env(client): |
650.1.17
by Aaron Bentley
Clean up. |
35 |
"""Use a client to prepare a dummy environment."""
|
1345.1.3
by Seman
Deploy charm by path. |
36 |
charm_source = local_charm_path( |
37 |
charm='dummy-source', juju_ver=client.version) |
|
38 |
client.deploy(charm_source) |
|
39 |
charm_sink = local_charm_path(charm='dummy-sink', juju_ver=client.version) |
|
40 |
client.deploy(charm_sink) |
|
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
41 |
token = get_random_string() |
1239.1.1
by Aaron Bentley
Implement and use EnvJujuClient.set_config. |
42 |
client.set_config('dummy-source', {'token': token}) |
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
43 |
client.juju('add-relation', ('dummy-source', 'dummy-sink')) |
44 |
client.juju('expose', ('dummy-sink',)) |
|
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
45 |
return token |
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
46 |
|
47 |
||
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
48 |
def get_clients(initial, other, base_env, debug, agent_url): |
774.2.3
by Aaron Bentley
Support agent-url |
49 |
"""Return the clients to use for testing."""
|
1438.1.2
by Aaron Bentley
Support FAKE for assess_heterogeneous_control. |
50 |
if initial == 'FAKE': |
1465.5.2
by Aaron Bentley
Implement client_from_config, delete by_version. |
51 |
environment = SimpleEnvironment.from_config(base_env) |
1438.1.2
by Aaron Bentley
Support FAKE for assess_heterogeneous_control. |
52 |
client = fake_juju_client(env=environment) |
53 |
return client, client, client |
|
1465.5.2
by Aaron Bentley
Implement client_from_config, delete by_version. |
54 |
else: |
55 |
initial_client = client_from_config(base_env, initial, debug=debug) |
|
56 |
environment = initial_client.env |
|
57 |
if agent_url is None: |
|
1762.2.7
by Aaron Bentley
Remove config property. |
58 |
environment.discard_option('tools-metadata-url') |
1465.5.2
by Aaron Bentley
Implement client_from_config, delete by_version. |
59 |
other_client = initial_client.clone_path_cls(other) |
677
by Aaron Bentley
Use system juju for teardown and log dumping. |
60 |
# System juju is assumed to be released and the best choice for tearing
|
61 |
# down environments reliably. (For example, 1.18.x cannot tear down
|
|
62 |
# environments with alpha agent-versions.)
|
|
1504.1.2
by Aaron Bentley
Handle JujuData incompatibility. |
63 |
try: |
64 |
released_client = initial_client.clone_path_cls(None) |
|
65 |
except IncompatibleConfigClass: |
|
66 |
# If initial_client's config class is incompatible with the system
|
|
67 |
# juju, use initial client for teardown.
|
|
68 |
released_client = initial_client |
|
1341.3.3
by Aaron Bentley
Get working. |
69 |
# If released_client is a different major version, it cannot tear down
|
70 |
# initial client, so use initial client for teardown.
|
|
1363.5.22
by Aaron Bentley
Fix lint. |
71 |
if ( |
72 |
isinstance(released_client, EnvJujuClient1X) != |
|
73 |
isinstance(initial_client, EnvJujuClient1X) |
|
74 |
):
|
|
75 |
released_client = initial_client |
|
1341.3.3
by Aaron Bentley
Get working. |
76 |
else: |
77 |
# If system juju is used, ensure it has identical env to
|
|
78 |
# initial_client.
|
|
79 |
released_client.env = initial_client.env |
|
774.2.3
by Aaron Bentley
Support agent-url |
80 |
return initial_client, other_client, released_client |
81 |
||
82 |
||
83 |
def assess_heterogeneous(initial, other, base_env, environment_name, log_dir, |
|
1063.1.2
by Curtis Hovey
pass agent_stream and series to update_env. |
84 |
upload_tools, debug, agent_url, agent_stream, series): |
774.2.3
by Aaron Bentley
Support agent-url |
85 |
"""Top level function that prepares the clients and environment.
|
86 |
||
915.2.2
by seman.said at canonical
Added unit test and updated code to upload compatibility test results to S3 |
87 |
initial and other are paths to the binary used initially, and a binary
|
774.2.3
by Aaron Bentley
Support agent-url |
88 |
used later. base_env is the name of the environment to base the
|
89 |
environment on and environment_name is the new name for the environment.
|
|
90 |
"""
|
|
1305.1.1
by Aaron Bentley
assess_heterogeneous_control does not tear down with inappropriate client. |
91 |
initial_client, other_client, teardown_client = get_clients( |
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
92 |
initial, other, base_env, debug, agent_url) |
93 |
jes_enabled = initial_client.is_jes_enabled() |
|
94 |
bs_manager = BootstrapManager( |
|
1305.1.1
by Aaron Bentley
assess_heterogeneous_control does not tear down with inappropriate client. |
95 |
environment_name, initial_client, teardown_client, |
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
96 |
bootstrap_host=None, machines=[], series=series, agent_url=agent_url, |
97 |
agent_stream=agent_stream, region=None, log_dir=log_dir, |
|
98 |
keep_env=False, permanent=jes_enabled, jes_enabled=jes_enabled) |
|
99 |
test_control_heterogeneous(bs_manager, other_client, upload_tools) |
|
100 |
||
101 |
||
102 |
@contextmanager
|
|
103 |
def run_context(bs_manager, other, upload_tools): |
|
104 |
try: |
|
105 |
bs_manager.keep_env = True |
|
106 |
with bs_manager.booted_context(upload_tools): |
|
1341.3.3
by Aaron Bentley
Get working. |
107 |
if other.env.juju_home != bs_manager.client.env.juju_home: |
108 |
raise AssertionError('Juju home out of sync') |
|
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
109 |
yield
|
110 |
# Test clean shutdown of an environment.
|
|
1221.5.14
by Aaron Bentley
Fix destroy_environment for jes-enabled jujus. |
111 |
callback_with_fallback(other, bs_manager.tear_down_client, |
112 |
nice_tear_down) |
|
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
113 |
except: |
114 |
bs_manager.tear_down() |
|
115 |
raise
|
|
116 |
||
117 |
||
118 |
def test_control_heterogeneous(bs_manager, other, upload_tools): |
|
650.1.17
by Aaron Bentley
Clean up. |
119 |
"""Test if one binary can control an environment set up by the other."""
|
1162.2.27
by Aaron Bentley
Switch assess_heterogeneous_control to BootstrapManager. |
120 |
initial = bs_manager.client |
121 |
released = bs_manager.tear_down_client |
|
122 |
with run_context(bs_manager, other, upload_tools): |
|
663.1.9
by Aaron Bentley
Assess heterogenous-control supports --upload-tools. |
123 |
token = prepare_dummy_env(initial) |
650.1.19
by Aaron Bentley
Switch native/foreign terminology to initial/other/hetrogeneous. |
124 |
initial.wait_for_started() |
1341.3.3
by Aaron Bentley
Get working. |
125 |
if sys.platform != "win32": |
126 |
# Currently, juju ssh is not working on Windows.
|
|
127 |
check_token(initial, token) |
|
128 |
check_series(other) |
|
129 |
other.juju('run', ('--all', 'uname -a')) |
|
130 |
other.get_config('dummy-source') |
|
131 |
other.get_model_config() |
|
132 |
other.juju('remove-relation', ('dummy-source', 'dummy-sink')) |
|
133 |
status = other.get_status() |
|
134 |
other.juju('unexpose', ('dummy-sink',)) |
|
135 |
status = other.get_status() |
|
1420.2.1
by Aaron Bentley
Update tests to use applications, not services. |
136 |
if status.get_applications()['dummy-sink']['exposed']: |
1341.3.3
by Aaron Bentley
Get working. |
137 |
raise AssertionError('dummy-sink is still exposed') |
138 |
status = other.get_status() |
|
139 |
charm_path = local_charm_path( |
|
140 |
charm='dummy-sink', juju_ver=other.version) |
|
141 |
juju_with_fallback(other, released, 'deploy', |
|
142 |
(charm_path, 'sink2')) |
|
143 |
other.wait_for_started() |
|
144 |
other.juju('add-relation', ('dummy-source', 'sink2')) |
|
145 |
status = other.get_status() |
|
146 |
other.juju('expose', ('sink2',)) |
|
147 |
status = other.get_status() |
|
1420.2.1
by Aaron Bentley
Update tests to use applications, not services. |
148 |
if 'sink2' not in status.get_applications(): |
1341.3.3
by Aaron Bentley
Get working. |
149 |
raise AssertionError('Sink2 missing') |
150 |
other.remove_service('sink2') |
|
151 |
for ignored in until_timeout(30): |
|
152 |
status = other.get_status() |
|
1420.2.1
by Aaron Bentley
Update tests to use applications, not services. |
153 |
if 'sink2' not in status.get_applications(): |
1341.3.3
by Aaron Bentley
Get working. |
154 |
break
|
155 |
else: |
|
156 |
raise AssertionError('Sink2 not destroyed') |
|
157 |
other.juju('add-relation', ('dummy-source', 'dummy-sink')) |
|
158 |
status = other.get_status() |
|
1420.2.1
by Aaron Bentley
Update tests to use applications, not services. |
159 |
relations = status.get_applications()['dummy-sink']['relations'] |
1341.3.3
by Aaron Bentley
Get working. |
160 |
if not relations['source'] == ['dummy-source']: |
161 |
raise AssertionError('source is not dummy-source.') |
|
162 |
other.juju('expose', ('dummy-sink',)) |
|
163 |
status = other.get_status() |
|
1420.2.1
by Aaron Bentley
Update tests to use applications, not services. |
164 |
if not status.get_applications()['dummy-sink']['exposed']: |
1341.3.3
by Aaron Bentley
Get working. |
165 |
raise AssertionError('dummy-sink is not exposed') |
166 |
other.juju('add-unit', ('dummy-sink',)) |
|
167 |
if not has_agent(other, 'dummy-sink/1'): |
|
168 |
raise AssertionError('dummy-sink/1 was not added.') |
|
169 |
other.juju('remove-unit', ('dummy-sink/1',)) |
|
170 |
status = other.get_status() |
|
171 |
if has_agent(other, 'dummy-sink/1'): |
|
172 |
raise AssertionError('dummy-sink/1 was not removed.') |
|
173 |
container_type = other.preferred_container() |
|
1341.3.1
by Aaron Bentley
Initial work on assess-heterogeneous-control. |
174 |
other.juju('add-machine', (container_type,)) |
175 |
status = other.get_status() |
|
176 |
container_machine, = set(k for k, v in status.agent_items() if |
|
177 |
k.endswith('/{}/0'.format(container_type))) |
|
178 |
container_holder = container_machine.split('/')[0] |
|
179 |
other.juju('remove-machine', (container_machine,)) |
|
180 |
wait_until_removed(other, container_machine) |
|
181 |
other.juju('remove-machine', (container_holder,)) |
|
182 |
wait_until_removed(other, container_holder) |
|
678
by Aaron Bentley
Support retrying certain 1.18 operations with system juju. |
183 |
|
1173.1.3
by Aaron Bentley
Prevent nosetests from running test_control_heterogeneous directly. |
184 |
# suppress nosetests
|
185 |
test_control_heterogeneous.__test__ = False |
|
186 |
||
678
by Aaron Bentley
Support retrying certain 1.18 operations with system juju. |
187 |
|
188 |
def juju_with_fallback(other, released, command, args, include_e=True): |
|
189 |
"""Fallback to released juju when 1.18 fails.
|
|
190 |
||
191 |
Get as much test coverage of 1.18 as we can, by falling back to a released
|
|
192 |
juju for commands that we expect to fail (due to unsupported agent version
|
|
193 |
format).
|
|
194 |
"""
|
|
1221.5.14
by Aaron Bentley
Fix destroy_environment for jes-enabled jujus. |
195 |
def call_juju(client): |
196 |
client.juju(command, args, include_e=include_e) |
|
197 |
return callback_with_fallback(other, released, call_juju) |
|
198 |
||
199 |
||
200 |
def callback_with_fallback(other, released, callback): |
|
679
by Aaron Bentley
Rewrite juju_with_fallback so there is only one EnvJujuClient invocation. |
201 |
for client in [other, released]: |
202 |
try: |
|
1221.5.14
by Aaron Bentley
Fix destroy_environment for jes-enabled jujus. |
203 |
callback(client) |
679
by Aaron Bentley
Rewrite juju_with_fallback so there is only one EnvJujuClient invocation. |
204 |
except CalledProcessError: |
205 |
if not client.version.startswith('1.18.'): |
|
206 |
raise
|
|
207 |
else: |
|
208 |
break
|
|
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
209 |
|
210 |
||
1221.5.14
by Aaron Bentley
Fix destroy_environment for jes-enabled jujus. |
211 |
def nice_tear_down(client): |
212 |
if client.is_jes_enabled(): |
|
213 |
client.kill_controller() |
|
214 |
else: |
|
215 |
if client.destroy_environment(force=False) != 0: |
|
216 |
raise CalledProcessError(1, 'juju destroy-environment') |
|
217 |
||
218 |
||
650.1.20
by Aaron Bentley
Test outcomes better. |
219 |
def has_agent(client, agent_id): |
220 |
return bool(agent_id in dict(client.get_status().agent_items())) |
|
221 |
||
222 |
||
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
223 |
def wait_until_removed(client, agent_id): |
650.1.17
by Aaron Bentley
Clean up. |
224 |
"""Wait for an agent to be removed from the environment."""
|
650.1.20
by Aaron Bentley
Test outcomes better. |
225 |
for ignored in until_timeout(240): |
226 |
if not has_agent(client, agent_id): |
|
227 |
return
|
|
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
228 |
else: |
650.1.20
by Aaron Bentley
Test outcomes better. |
229 |
raise AssertionError('Machine not destroyed: {}.'.format(agent_id)) |
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
230 |
|
231 |
||
1357.2.2
by Seman
Added assess_multi_series_charms. |
232 |
def check_series(client, machine='0', series=None): |
650.1.17
by Aaron Bentley
Clean up. |
233 |
"""Use 'juju ssh' to check that the deployed series meets expectations."""
|
1357.2.2
by Seman
Added assess_multi_series_charms. |
234 |
result = client.get_juju_output('ssh', machine, 'lsb_release', '-c') |
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
235 |
label, codename = result.rstrip().split('\t') |
236 |
if label != 'Codename:': |
|
237 |
raise AssertionError() |
|
1357.2.2
by Seman
Added assess_multi_series_charms. |
238 |
if series: |
239 |
expected_codename = series |
|
240 |
else: |
|
1699.1.2
by Aaron Bentley
Convert direct config access to get_option. |
241 |
expected_codename = client.env.get_option('default-series') |
650.1.8
by Aaron Bentley
Implement most compatibility testing. |
242 |
if codename != expected_codename: |
243 |
raise AssertionError( |
|
244 |
'Series is {}, not {}'.format(codename, expected_codename)) |
|
650.1.7
by Aaron Bentley
Start testing mixed environs. |
245 |
|
246 |
||
774.2.3
by Aaron Bentley
Support agent-url |
247 |
def parse_args(argv=None): |
650.1.12
by Aaron Bentley
Rename to assess-foreign, update to use EnvJujuClient. |
248 |
parser = ArgumentParser(description=dedent("""\ |
249 |
Determine whether one juju version can control an environment created
|
|
250 |
by another version.
|
|
251 |
""")) |
|
650.1.19
by Aaron Bentley
Switch native/foreign terminology to initial/other/hetrogeneous. |
252 |
parser.add_argument('initial', help='The initial juju binary.') |
253 |
parser.add_argument('other', help='A different juju binary.') |
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
254 |
parser.add_argument('base_environment', help='The environment to base on.') |
255 |
parser.add_argument('environment_name', help='The new environment name.') |
|
650.1.10
by Aaron Bentley
Stop dumping logs in cwd. |
256 |
parser.add_argument('log_dir', help='The directory to dump logs to.') |
663.1.7
by Aaron Bentley
Add --upload-tools to assess-heterogeneous-control. |
257 |
parser.add_argument( |
258 |
'--upload-tools', action='store_true', default=False, |
|
259 |
help='Upload local version of tools before bootstrapping.') |
|
260 |
parser.add_argument('--debug', help='Run juju with --debug', |
|
261 |
action='store_true', default=False) |
|
774.2.3
by Aaron Bentley
Support agent-url |
262 |
parser.add_argument('--agent-url', default=None) |
1063.1.4
by Curtis Hovey
Remove redundant args |
263 |
parser.add_argument('--agent-stream', action='store', |
1063.1.1
by Curtis Hovey
Added --agent-steam and --series. |
264 |
help='URL for retrieving agent binaries.') |
1063.1.4
by Curtis Hovey
Remove redundant args |
265 |
parser.add_argument('--series', action='store', |
1063.1.1
by Curtis Hovey
Added --agent-steam and --series. |
266 |
help='Name of the Ubuntu series to use.') |
915.2.3
by seman.said at canonical
Updated code per review suggestion |
267 |
add_credential_args(parser) |
774.2.3
by Aaron Bentley
Support agent-url |
268 |
return parser.parse_args(argv) |
269 |
||
270 |
||
271 |
def main(): |
|
272 |
args = parse_args() |
|
1053.1.1
by Martin Packman
Refactor log collection to ensure local logs are only collected once |
273 |
configure_logging(logging.INFO) |
650.1.19
by Aaron Bentley
Switch native/foreign terminology to initial/other/hetrogeneous. |
274 |
assess_heterogeneous(args.initial, args.other, args.base_environment, |
663.1.7
by Aaron Bentley
Add --upload-tools to assess-heterogeneous-control. |
275 |
args.environment_name, args.log_dir, |
1063.1.2
by Curtis Hovey
pass agent_stream and series to update_env. |
276 |
args.upload_tools, args.debug, args.agent_url, |
277 |
args.agent_stream, args.series) |
|
650.1.3
by Aaron Bentley
Begin implementing compatibility-test. |
278 |
|
279 |
||
280 |
if __name__ == '__main__': |
|
281 |
main() |