1091.3.1
by James Tunnicliffe
Supporting functions for testing networking between containers in a Juju environment. |
1 |
#!/usr/bin/env python
|
2 |
from __future__ import print_function |
|
1091.5.19
by Aaron Bentley
Fix imports |
3 |
from argparse import ArgumentParser |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
4 |
import contextlib |
1091.3.2
by James Tunnicliffe
clean_environment bails early if there is no environment to clean. |
5 |
from copy import ( |
6 |
copy, |
|
7 |
deepcopy, |
|
8 |
)
|
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
9 |
import logging |
10 |
import re |
|
11 |
import os |
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
12 |
import subprocess |
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
13 |
import sys |
1091.5.19
by Aaron Bentley
Fix imports |
14 |
import tempfile |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
15 |
from textwrap import dedent |
1091.5.19
by Aaron Bentley
Fix imports |
16 |
import time |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
17 |
|
1091.5.19
by Aaron Bentley
Fix imports |
18 |
from deploy_stack import ( |
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
19 |
BootstrapManager, |
20 |
get_random_string, |
|
1091.5.19
by Aaron Bentley
Fix imports |
21 |
update_env, |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
22 |
)
|
1341.2.1
by Aaron Bentley
Move container support knowledge to jujupy. |
23 |
from jujupy import ( |
24 |
KVM_MACHINE, |
|
25 |
LXC_MACHINE, |
|
26 |
LXD_MACHINE, |
|
27 |
)
|
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
28 |
from utility import ( |
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
29 |
add_basic_testing_arguments, |
30 |
configure_logging, |
|
1091.5.13
by James Tunnicliffe
Fixed up tests. |
31 |
wait_for_port, |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
32 |
)
|
1091.5.19
by Aaron Bentley
Fix imports |
33 |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
34 |
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
35 |
__metaclass__ = type |
36 |
||
1091.3.1
by James Tunnicliffe
Supporting functions for testing networking between containers in a Juju environment. |
37 |
|
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
38 |
log = logging.getLogger("assess_container_networking") |
39 |
||
40 |
||
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
41 |
def parse_args(argv=None): |
42 |
"""Parse all arguments."""
|
|
43 |
||
44 |
description = dedent("""\ |
|
45 |
Test container address allocation.
|
|
46 |
For LXC and KVM, create machines of each type and test the network
|
|
47 |
between LXC <--> LXC, KVM <--> KVM and LXC <--> KVM. Also test machine
|
|
48 |
to outside world, DNS and that these tests still pass after a reboot. In
|
|
49 |
case of failure pull logs and configuration files from the machine that
|
|
50 |
we detected a problem on for later analysis.
|
|
51 |
""") |
|
52 |
parser = add_basic_testing_arguments(ArgumentParser( |
|
53 |
description=description |
|
54 |
))
|
|
55 |
parser.add_argument( |
|
56 |
'--machine-type', |
|
57 |
help='Which virtual machine/container type to test. Defaults to all.', |
|
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
58 |
choices=[KVM_MACHINE, LXC_MACHINE, LXD_MACHINE]) |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
59 |
parser.add_argument( |
60 |
'--clean-environment', action='store_true', help=dedent("""\ |
|
61 |
Attempts to re-use an existing environment rather than destroying it
|
|
62 |
and creating a new one.
|
|
63 |
||
64 |
On launch, if an environment exists, clean out services and machines
|
|
65 |
from it rather than destroying it. If an environment doesn't exist,
|
|
66 |
create one and use it.
|
|
67 |
||
68 |
At termination, clean out services and machines from the environment
|
|
69 |
rather than destroying it.""")) |
|
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
70 |
args = parser.parse_args(argv) |
71 |
# Passing --clean-environment implies --keep-env
|
|
72 |
if args.clean_environment: |
|
73 |
args.keep_env = True |
|
74 |
return args |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
75 |
|
76 |
||
77 |
def ssh(client, machine, cmd): |
|
78 |
"""Convenience function: run a juju ssh command and get back the output
|
|
79 |
:param client: A Juju client
|
|
80 |
:param machine: ID of the machine on which to run a command
|
|
81 |
:param cmd: the command to run
|
|
82 |
:return: text output of the command
|
|
83 |
"""
|
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
84 |
back_off = 2 |
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
85 |
attempts = 4 |
86 |
for attempt in range(attempts): |
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
87 |
try: |
1357.1.1
by Curtis Hovey
Use --proxy when using ssh/scp and containers. |
88 |
return client.get_juju_output('ssh', '--proxy', machine, cmd) |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
89 |
except subprocess.CalledProcessError as e: |
90 |
# If the connection to the host failed, try again in a couple of
|
|
91 |
# seconds. This is usually due to heavy load.
|
|
1357.1.1
by Curtis Hovey
Use --proxy when using ssh/scp and containers. |
92 |
if(attempt < attempts - 1 and |
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
93 |
re.search('ssh_exchange_identification: ' |
94 |
'Connection closed by remote host', e.stderr)): |
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
95 |
time.sleep(back_off) |
96 |
back_off *= 2 |
|
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
97 |
else: |
98 |
raise
|
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
99 |
|
100 |
||
1091.3.1
by James Tunnicliffe
Supporting functions for testing networking between containers in a Juju environment. |
101 |
def clean_environment(client, services_only=False): |
102 |
"""Remove all the services and, optionally, machines from an environment.
|
|
103 |
||
104 |
Use as an alternative to destroying an environment and creating a new one
|
|
105 |
to save a bit of time.
|
|
106 |
||
107 |
:param client: a Juju client
|
|
108 |
"""
|
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
109 |
# A short timeout is used for get_status here because if we don't get a
|
110 |
# response from get_status quickly then the environment almost
|
|
111 |
# certainly doesn't exist or needs recreating.
|
|
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
112 |
try: |
113 |
status = client.get_status(5) |
|
114 |
except Exception as e: |
|
115 |
# TODO(gz): get_status should return a more specific error type.
|
|
116 |
log.info("Could not clean existing env: %s", e) |
|
117 |
return False |
|
1091.3.2
by James Tunnicliffe
clean_environment bails early if there is no environment to clean. |
118 |
|
1420.2.3
by Aaron Bentley
Use get_applications. |
119 |
for service in status.get_applications(): |
120 |
client.remove_service(service) |
|
1091.3.1
by James Tunnicliffe
Supporting functions for testing networking between containers in a Juju environment. |
121 |
|
122 |
if not services_only: |
|
123 |
# First remove all containers; we can't remove a machine that is
|
|
124 |
# hosting containers.
|
|
125 |
for m, _ in status.iter_machines(containers=True, machines=False): |
|
126 |
client.juju('remove-machine', m) |
|
127 |
||
128 |
client.wait_for('containers', 'none') |
|
129 |
||
130 |
for m, _ in status.iter_machines(containers=False, machines=True): |
|
131 |
if m != '0': |
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
132 |
try: |
133 |
client.juju('remove-machine', m) |
|
134 |
except subprocess.CalledProcessError: |
|
135 |
# Sometimes this fails because while we have asked Juju
|
|
136 |
# to remove a container and it says that it has, when we
|
|
137 |
# ask it to remove the host Juju thinks it still has
|
|
138 |
# containers on it. Normally a small pause and trying
|
|
139 |
# again is all that is needed to resolve this issue.
|
|
140 |
time.sleep(2) |
|
1162.1.3
by Aaron Bentley
Fix lint |
141 |
client.wait_for_started() |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
142 |
client.juju('remove-machine', m) |
1091.3.1
by James Tunnicliffe
Supporting functions for testing networking between containers in a Juju environment. |
143 |
|
144 |
client.wait_for('machines-not-0', 'none') |
|
145 |
||
146 |
client.wait_for_started() |
|
1091.3.2
by James Tunnicliffe
clean_environment bails early if there is no environment to clean. |
147 |
return True |
148 |
||
149 |
||
150 |
def make_machines(client, container_types): |
|
151 |
"""Make a test environment consisting of:
|
|
152 |
Two host machines.
|
|
153 |
Two of each container_type on one host machine.
|
|
154 |
One of each container_type on one host machine.
|
|
155 |
:param client: An EnvJujuClient
|
|
156 |
:param container_types: list of containers to create
|
|
157 |
:return: hosts (list), containers {container_type}{host}[containers]
|
|
158 |
"""
|
|
159 |
# Find existing host machines
|
|
160 |
old_hosts = client.get_status().status['machines'] |
|
161 |
machines_to_add = 2 - len(old_hosts) |
|
162 |
||
163 |
# Allocate more hosts as needed
|
|
164 |
if machines_to_add > 0: |
|
165 |
client.juju('add-machine', ('-n', str(machines_to_add))) |
|
166 |
status = client.wait_for_started() |
|
167 |
hosts = sorted(status.status['machines'].keys())[:2] |
|
168 |
||
169 |
# Find existing containers
|
|
170 |
required = dict(zip(hosts, [copy(container_types) for h in hosts])) |
|
171 |
required[hosts[0]] += container_types |
|
172 |
for c in status.iter_machines(containers=True, machines=False): |
|
173 |
host, type, id = c[0].split('/') |
|
174 |
if type in required[host]: |
|
175 |
required[host].remove(type) |
|
176 |
||
177 |
# Start any new containers we need
|
|
178 |
for host, containers in required.iteritems(): |
|
179 |
for container in containers: |
|
180 |
client.juju('add-machine', ('{}:{}'.format(container, host))) |
|
181 |
||
182 |
status = client.wait_for_started() |
|
183 |
||
184 |
# Build a list of containers, now they have all started
|
|
185 |
tmp = dict(zip(hosts, [[] for h in hosts])) |
|
186 |
containers = dict(zip(container_types, |
|
187 |
[deepcopy(tmp) for t in container_types])) |
|
188 |
for c in status.iter_machines(containers=True, machines=False): |
|
189 |
host, type, id = c[0].split('/') |
|
190 |
if type in containers and host in containers[type]: |
|
191 |
containers[type][host].append(c[0]) |
|
192 |
||
193 |
return hosts, containers |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
194 |
|
195 |
||
196 |
def find_network(client, machine, addr): |
|
197 |
"""Find a connected subnet containing the given address.
|
|
198 |
||
199 |
When using this to find the subnet of a container, don't use the container
|
|
200 |
as the machine to run the ip route show command on ("machine"), use a real
|
|
201 |
box because lxc will just send everything to its host machine, so it is on
|
|
202 |
a subnet containing itself. Not much use.
|
|
203 |
:param client: A Juju client
|
|
204 |
:param machine: ID of the machine on which to run a command
|
|
205 |
:param addr: find the connected subnet containing this address
|
|
206 |
:return: CIDR containing the address if found, else, None
|
|
207 |
"""
|
|
208 |
ip_cmd = ' '.join(['ip', 'route', 'show', 'to', 'match', addr]) |
|
209 |
routes = ssh(client, machine, ip_cmd) |
|
210 |
||
211 |
for route in re.findall(r'^(\S+).*[\d\.]+/\d+', routes, re.MULTILINE): |
|
212 |
if route != 'default': |
|
213 |
return route |
|
214 |
||
215 |
raise ValueError("Unable to find route to %r" % addr) |
|
216 |
||
217 |
||
218 |
def assess_network_traffic(client, targets): |
|
219 |
"""Test that all containers in target can talk to target[0]
|
|
220 |
:param client: Juju client
|
|
221 |
:param targets: machine IDs of machines to test
|
|
222 |
:return: None;
|
|
223 |
"""
|
|
1464.1.8
by Curtis Hovey
Changed per review and fix error test. |
224 |
status = client.wait_for_started().status |
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
225 |
log.info('Assessing network traffic.') |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
226 |
source = targets[0] |
227 |
dests = targets[1:] |
|
228 |
||
229 |
with tempfile.NamedTemporaryFile(delete=False) as f: |
|
230 |
f.write('tmux new-session -d -s test "nc -l 6778 > nc_listen.out"') |
|
1357.1.1
by Curtis Hovey
Use --proxy when using ssh/scp and containers. |
231 |
client.juju('scp', ('--proxy', f.name, source + ':/home/ubuntu/listen.sh')) |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
232 |
os.remove(f.name) |
233 |
||
234 |
# Containers are named 'x/type/y' where x is the host of the container. We
|
|
235 |
host = source.split('/')[0] |
|
236 |
address = status['machines'][host]['containers'][source]['dns-name'] |
|
237 |
||
238 |
for dest in dests: |
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
239 |
log.info('Assessing network traffic for {}.'.format(dest)) |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
240 |
msg = get_random_string() |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
241 |
ssh(client, source, 'rm nc_listen.out; bash ./listen.sh') |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
242 |
ssh(client, dest, |
243 |
'echo "{msg}" | nc {addr} 6778'.format(msg=msg, addr=address)) |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
244 |
result = ssh(client, source, 'more nc_listen.out') |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
245 |
if result.rstrip() != msg: |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
246 |
raise ValueError("Wrong or missing message: %r" % result.rstrip()) |
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
247 |
log.info('SUCCESS.') |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
248 |
|
249 |
||
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
250 |
def private_address(client, host): |
251 |
default_route = ssh(client, host, 'ip -4 -o route list 0/0') |
|
252 |
device = re.search(r'(\w+)\s*$', default_route).group(1) |
|
253 |
device_ip = ssh(client, host, 'ip -4 -o addr show {}'.format(device)) |
|
254 |
return re.search(r'inet\s+(\S+)/\d+\s', device_ip).group(1) |
|
255 |
||
256 |
||
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
257 |
def assess_address_range(client, targets): |
258 |
"""Test that two containers are in the same subnet as their host
|
|
259 |
:param client: Juju client
|
|
260 |
:param targets: machine IDs of machines to test
|
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
261 |
:return: None; raises ValueError on failure
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
262 |
"""
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
263 |
log.info('Assessing address range.') |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
264 |
status = client.wait_for_started().status |
265 |
||
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
266 |
host_subnet_cache = {} |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
267 |
|
268 |
for target in targets: |
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
269 |
log.info('Assessing address range for {}.'.format(target)) |
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
270 |
host = target.split('/')[0] |
271 |
||
272 |
if host in host_subnet_cache: |
|
273 |
host_subnet = host_subnet_cache[host] |
|
274 |
else: |
|
275 |
host_address = private_address(client, host) |
|
276 |
host_subnet = find_network(client, host, host_address) |
|
277 |
host_subnet_cache[host] = host_subnet |
|
278 |
||
279 |
addr = status['machines'][host]['containers'][target]['dns-name'] |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
280 |
subnet = find_network(client, host, addr) |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
281 |
if host_subnet != subnet: |
282 |
raise ValueError( |
|
283 |
'{} ({}) not on the same subnet as {} ({})'.format( |
|
284 |
target, subnet, host, host_subnet)) |
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
285 |
log.info('SUCCESS.') |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
286 |
|
287 |
||
288 |
def assess_internet_connection(client, targets): |
|
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
289 |
"""Test that targets can ping their default route
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
290 |
:param client: Juju client
|
291 |
:param targets: machine IDs of machines to test
|
|
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
292 |
:return: None; raises ValueError on failure
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
293 |
"""
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
294 |
log.info('Assessing internet connection.') |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
295 |
for target in targets: |
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
296 |
log.info("Assessing internet connection for {}".format(target)) |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
297 |
routes = ssh(client, target, 'ip route show') |
298 |
||
299 |
d = re.search(r'^default\s+via\s+([\d\.]+)\s+', routes, re.MULTILINE) |
|
300 |
if d: |
|
1357.1.1
by Curtis Hovey
Use --proxy when using ssh/scp and containers. |
301 |
rc = client.juju('ssh', ('--proxy', target, |
302 |
'ping -c1 -q ' + d.group(1)), check=False) |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
303 |
if rc != 0: |
304 |
raise ValueError('%s unable to ping default route' % target) |
|
305 |
else: |
|
306 |
raise ValueError("Default route not found") |
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
307 |
log.info("SUCCESS") |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
308 |
|
309 |
||
310 |
def _assessment_iteration(client, containers): |
|
311 |
"""Run the network tests on this collection of machines and containers
|
|
312 |
:param client: Juju client
|
|
313 |
:param hosts: list of hosts of containers
|
|
314 |
:param containers: list of containers to run tests between
|
|
315 |
:return: None
|
|
316 |
"""
|
|
317 |
assess_internet_connection(client, containers) |
|
318 |
assess_address_range(client, containers) |
|
319 |
assess_network_traffic(client, containers) |
|
320 |
||
321 |
||
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
322 |
def _assess_container_networking(client, types, hosts, containers): |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
323 |
"""Run _assessment_iteration on all useful combinations of containers
|
324 |
:param client: Juju client
|
|
325 |
:param args: Parsed command line arguments
|
|
326 |
:return: None
|
|
327 |
"""
|
|
328 |
for container_type in types: |
|
329 |
# Test with two containers on the same host
|
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
330 |
_assessment_iteration(client, containers[container_type][hosts[0]]) |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
331 |
|
332 |
# Now test with two containers on two different hosts
|
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
333 |
test_containers = [ |
334 |
containers[container_type][hosts[0]][0], |
|
335 |
containers[container_type][hosts[1]][0], |
|
336 |
]
|
|
337 |
_assessment_iteration(client, test_containers) |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
338 |
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
339 |
if KVM_MACHINE in types and LXC_MACHINE in types: |
340 |
test_containers = [ |
|
341 |
containers[LXC_MACHINE][hosts[0]][0], |
|
342 |
containers[KVM_MACHINE][hosts[0]][0], |
|
343 |
]
|
|
344 |
_assessment_iteration(client, test_containers) |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
345 |
|
346 |
# Test with an LXC and a KVM on different machines
|
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
347 |
test_containers = [ |
348 |
containers[LXC_MACHINE][hosts[0]][0], |
|
349 |
containers[KVM_MACHINE][hosts[1]][0], |
|
350 |
]
|
|
351 |
_assessment_iteration(client, test_containers) |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
352 |
|
353 |
||
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
354 |
def assess_container_networking(client, types): |
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
355 |
"""Runs _assess_address_allocation, reboots hosts, repeat.
|
356 |
:param client: Juju client
|
|
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
357 |
:param types: Container types to test
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
358 |
:return: None
|
359 |
"""
|
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
360 |
log.info("Setting up test.") |
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
361 |
hosts, containers = make_machines(client, types) |
1091.5.13
by James Tunnicliffe
Fixed up tests. |
362 |
status = client.wait_for_started().status |
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
363 |
log.info("Setup complete.") |
364 |
log.info("Test started.") |
|
1091.5.13
by James Tunnicliffe
Fixed up tests. |
365 |
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
366 |
_assess_container_networking(client, types, hosts, containers) |
1091.5.13
by James Tunnicliffe
Fixed up tests. |
367 |
|
1091.5.16
by James Tunnicliffe
Fixed up reboot ordering and waits. |
368 |
# Reboot all hosts apart from machine 0 because we use machine 0 to jump
|
369 |
# through for some hosts.
|
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
370 |
log.info("Instrumenting reboot of all machines.") |
1091.5.16
by James Tunnicliffe
Fixed up reboot ordering and waits. |
371 |
for host in hosts[1:]: |
1464.1.3
by Curtis Hovey
Remove 1 minute delay. |
372 |
ssh(client, host, 'sudo shutdown -r') |
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
373 |
|
1091.5.16
by James Tunnicliffe
Fixed up reboot ordering and waits. |
374 |
# Finally reboot machine 0
|
1464.1.3
by Curtis Hovey
Remove 1 minute delay. |
375 |
ssh(client, hosts[0], 'sudo shutdown -r') |
1091.5.16
by James Tunnicliffe
Fixed up reboot ordering and waits. |
376 |
|
377 |
# Wait for the state server to shut down. This prevents us from calling
|
|
378 |
# wait_for_started before machine 0 has shut down, which can cause us
|
|
379 |
# to think that we have finished rebooting before we actually have.
|
|
380 |
hostname = status['machines'][hosts[0]]['dns-name'] |
|
1464.1.5
by Curtis Hovey
Increased timeout. Do not collect interfaces. |
381 |
wait_for_port(hostname, 22, closed=True, timeout=600) |
1091.5.16
by James Tunnicliffe
Fixed up reboot ordering and waits. |
382 |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
383 |
client.wait_for_started() |
1091.5.6
by James Tunnicliffe
A bit more reliability hacking around ssh and reboots. |
384 |
|
1091.5.13
by James Tunnicliffe
Fixed up tests. |
385 |
# Once Juju is up it can take a little while before ssh responds.
|
386 |
for host in hosts: |
|
387 |
hostname = status['machines'][host]['dns-name'] |
|
388 |
wait_for_port(hostname, 22, timeout=240) |
|
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
389 |
log.info("Reboot complete and all hosts ready for retest.") |
1091.5.13
by James Tunnicliffe
Fixed up tests. |
390 |
|
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
391 |
_assess_container_networking(client, types, hosts, containers) |
1464.1.1
by Curtis Hovey
Add clear information about the progress of the container networking test. Fix reboot for xenial and trusty. |
392 |
log.info("PASS") |
1091.5.2
by James Tunnicliffe
retry ssh commands if they fail with code 255, which seems to happen on heavily loaded machines. |
393 |
|
394 |
||
1226.1.2
by Martin Packman
Make dedicated _CleanedContext object for mutability |
395 |
class _CleanedContext: |
396 |
||
397 |
def __init__(self, client): |
|
398 |
self.client = client |
|
399 |
self.return_code = None |
|
400 |
||
401 |
||
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
402 |
@contextlib.contextmanager |
403 |
def cleaned_bootstrap_context(bs_manager, args): |
|
1226.1.2
by Martin Packman
Make dedicated _CleanedContext object for mutability |
404 |
ctx = _CleanedContext(bs_manager.client) |
405 |
client = ctx.client |
|
1215.1.2
by Martin Packman
Fix clean-environment by making calling update_env early to switch to the temp env |
406 |
# TODO(gz): Having to manipulate client env state here to get the temp env
|
407 |
# is ugly, would ideally be captured in an explicit scope.
|
|
408 |
update_env(client.env, bs_manager.temp_env_name, series=bs_manager.series, |
|
409 |
agent_url=bs_manager.agent_url, |
|
410 |
agent_stream=bs_manager.agent_stream, region=bs_manager.region) |
|
411 |
with bs_manager.top_context() as machines: |
|
412 |
bootstrap_required = True |
|
413 |
if args.clean_environment and clean_environment(client): |
|
414 |
bootstrap_required = False |
|
415 |
if bootstrap_required: |
|
416 |
with bs_manager.bootstrap_context(machines): |
|
417 |
client.bootstrap(args.upload_tools) |
|
418 |
with bs_manager.runtime_context(machines): |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
419 |
yield ctx |
1226.1.2
by Martin Packman
Make dedicated _CleanedContext object for mutability |
420 |
ctx.return_code = 0 |
1215.1.2
by Martin Packman
Fix clean-environment by making calling update_env early to switch to the temp env |
421 |
if args.clean_environment and not clean_environment(client): |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
422 |
ctx.return_code = 1 |
423 |
||
424 |
||
1341.2.1
by Aaron Bentley
Move container support knowledge to jujupy. |
425 |
def _get_container_types(client, machine_type): |
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
426 |
"""
|
427 |
Give list of container types to run testing against.
|
|
428 |
||
429 |
If a machine_type was explictly specified, only test against those kind
|
|
430 |
of containers. Otherwise, test all possible containers for the given
|
|
431 |
juju version.
|
|
432 |
"""
|
|
433 |
if machine_type: |
|
1341.2.1
by Aaron Bentley
Move container support knowledge to jujupy. |
434 |
if machine_type not in client.supported_container_types: |
435 |
raise Exception( |
|
436 |
"no {} support on juju {}".format(machine_type, |
|
437 |
client.version)) |
|
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
438 |
return [machine_type] |
439 |
# TODO(gz): Only include LXC for 1.X clients
|
|
1341.2.1
by Aaron Bentley
Move container support knowledge to jujupy. |
440 |
types = list(client.supported_container_types) |
441 |
types.sort() |
|
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
442 |
return types |
443 |
||
444 |
||
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
445 |
def main(argv=None): |
446 |
args = parse_args(argv) |
|
447 |
configure_logging(args.verbose) |
|
448 |
bs_manager = BootstrapManager.from_args(args) |
|
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
449 |
client = bs_manager.client |
450 |
client.enable_feature('address-allocation') |
|
1341.2.1
by Aaron Bentley
Move container support knowledge to jujupy. |
451 |
machine_types = _get_container_types(client, args.machine_type) |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
452 |
with cleaned_bootstrap_context(bs_manager, args) as ctx: |
1319.1.1
by Martin Packman
Allow testing of lxd with assess_container_networking |
453 |
assess_container_networking(bs_manager.client, machine_types) |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
454 |
return ctx.return_code |
1091.5.4
by James Tunnicliffe
SSH wrapper now trying even harder to retry on connection errors. |
455 |
|
1091.5.1
by James Tunnicliffe
Test communication between containers and the wider network. |
456 |
|
457 |
if __name__ == '__main__': |
|
1215.1.1
by Martin Packman
Switch assess_container_networking to using BootstrapManager |
458 |
sys.exit(main()) |