1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
1 |
#!/usr/bin/env python
|
2 |
from __future__ import print_function |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
3 |
from argparse import ArgumentParser |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
4 |
import re |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
5 |
import sys |
6 |
from textwrap import dedent |
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
7 |
|
8 |
from utility import ( |
|
9 |
add_basic_testing_arguments, |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
10 |
configure_logging, |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
11 |
)
|
12 |
from deploy_stack import ( |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
13 |
BootstrapManager, |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
14 |
)
|
15 |
from assess_container_networking import ( |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
16 |
cleaned_bootstrap_context, |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
17 |
ssh, |
18 |
)
|
|
19 |
||
20 |
__metaclass__ = type |
|
21 |
||
22 |
||
23 |
def parse_args(argv=None): |
|
24 |
"""Parse all arguments."""
|
|
25 |
||
26 |
description = dedent("""\ |
|
27 |
Test container address allocation.
|
|
28 |
For LXC and KVM, create machines of each type and test the network
|
|
29 |
between LXC <--> LXC, KVM <--> KVM and LXC <--> KVM. Also test machine
|
|
30 |
to outside world, DNS and that these tests still pass after a reboot. In
|
|
31 |
case of failure pull logs and configuration files from the machine that
|
|
32 |
we detected a problem on for later analysis.
|
|
33 |
""") |
|
34 |
parser = add_basic_testing_arguments(ArgumentParser( |
|
35 |
description=description |
|
36 |
))
|
|
37 |
parser.add_argument( |
|
38 |
'--clean-environment', action='store_true', help=dedent("""\ |
|
39 |
Attempts to re-use an existing environment rather than destroying it
|
|
40 |
and creating a new one.
|
|
41 |
||
42 |
On launch, if an environment exists, clean out services and machines
|
|
43 |
from it rather than destroying it. If an environment doesn't exist,
|
|
44 |
create one and use it.
|
|
45 |
||
46 |
At termination, clean out services and machines from the environment
|
|
47 |
rather than destroying it.""")) |
|
48 |
return parser.parse_args(argv) |
|
49 |
||
50 |
||
51 |
def assess_spaces_subnets(client): |
|
1091.6.3
by James Tunnicliffe
Added a bit of documentation. |
52 |
"""Check that space and subnet functionality works as expected
|
53 |
:param client: EnvJujuClient
|
|
54 |
"""
|
|
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
55 |
network_config = { |
56 |
'default': ['subnet-0fb97566', 'subnet-d27d91a9'], |
|
57 |
'dmz': ['subnet-604dcd09', 'subnet-882d8cf3'], |
|
58 |
'apps': ['subnet-c13fbfa8', 'subnet-53da7a28'], |
|
59 |
'backend': ['subnet-5e4dcd37', 'subnet-7c2c8d07'], |
|
60 |
}
|
|
61 |
||
62 |
charms_to_space = { |
|
63 |
'haproxy': {'space': 'dmz'}, |
|
64 |
'mediawiki': {'space': 'apps'}, |
|
65 |
'memcached': {'space': 'apps'}, |
|
66 |
'mysql': {'space': 'backend'}, |
|
67 |
'mysql-slave': { |
|
68 |
'space': 'backend', |
|
69 |
'charm': 'mysql', |
|
70 |
},
|
|
71 |
}
|
|
72 |
||
73 |
_assess_spaces_subnets(client, network_config, charms_to_space) |
|
74 |
||
75 |
||
76 |
def _assess_spaces_subnets(client, network_config, charms_to_space): |
|
1091.6.3
by James Tunnicliffe
Added a bit of documentation. |
77 |
"""Check that space and subnet functionality works as expected
|
78 |
:param client: EnvJujuClient
|
|
79 |
:param network_config: Map of 'space name' to ['subnet', 'list']
|
|
80 |
:param charms_to_space: Map of 'unit name' to
|
|
81 |
{'space': 'space name', 'charm': 'charm name (if not same as unit)}
|
|
82 |
:return: None. Raises exception on failure.
|
|
83 |
"""
|
|
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
84 |
for space in sorted(network_config.keys()): |
1221.5.3
by Aaron Bentley
Extract EnvJujuClient.add_space. |
85 |
client.add_space(space) |
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
86 |
for subnet in network_config[space]: |
1221.5.5
by Aaron Bentley
Extract add_subnet. |
87 |
client.add_subnet(subnet, space) |
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
88 |
|
89 |
for name in sorted(charms_to_space.keys()): |
|
90 |
if 'charm' not in charms_to_space[name]: |
|
91 |
charms_to_space[name]['charm'] = name |
|
92 |
charm = charms_to_space[name]['charm'] |
|
93 |
space = charms_to_space[name]['space'] |
|
94 |
client.juju('deploy', |
|
95 |
(charm, name, '--constraints', 'spaces=' + space)) |
|
96 |
||
97 |
# Scale up. We don't specify constraints, but they should still be honored
|
|
98 |
# per charm.
|
|
99 |
client.juju('add-unit', 'mysql-slave') |
|
100 |
client.juju('add-unit', 'mediawiki') |
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
101 |
status = client.wait_for_started() |
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
102 |
|
1221.5.1
by Aaron Bentley
Extract EnvJujuClient.list_space. |
103 |
spaces = client.list_space() |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
104 |
|
105 |
unit_priv_address = {} |
|
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
106 |
units_found = 0 |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
107 |
for service in sorted(status.status['services'].values()): |
108 |
for unit_name, unit in service.get('units', {}).items(): |
|
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
109 |
units_found += 1 |
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
110 |
addrs = ssh(client, unit['machine'], 'ip -o addr') |
111 |
for addr in re.findall(r'^\d+:\s+(\w+)\s+inet\s+(\S+)', |
|
112 |
addrs, re.MULTILINE): |
|
113 |
if addr[0] != 'lo': |
|
114 |
unit_priv_address[unit_name] = addr[1] |
|
115 |
||
116 |
cidrs_in_space = {} |
|
117 |
for name, attrs in spaces['spaces'].iteritems(): |
|
118 |
cidrs_in_space[name] = [] |
|
119 |
for cidr in attrs: |
|
120 |
cidrs_in_space[name].append(cidr) |
|
121 |
||
122 |
units_checked = 0 |
|
123 |
for space, cidrs in cidrs_in_space.iteritems(): |
|
124 |
for cidr in cidrs: |
|
125 |
for unit, address in unit_priv_address.iteritems(): |
|
126 |
if ipv4_in_cidr(address, cidr): |
|
127 |
units_checked += 1 |
|
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
128 |
charm = unit.split('/')[0] |
129 |
if charms_to_space[charm]['space'] != space: |
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
130 |
raise ValueError("Found {} in {}, expected {}".format( |
1091.6.2
by James Tunnicliffe
Updated test to match planned demo. Now tests if units are added to the correct space after the first has been directed to one. |
131 |
unit, space, charms_to_space[charm]['space'])) |
132 |
||
133 |
if units_found != units_checked: |
|
134 |
raise ValueError("Could not find spaces for all units") |
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
135 |
|
136 |
return units_checked |
|
137 |
||
138 |
||
139 |
def ipv4_to_int(ipv4): |
|
1091.6.3
by James Tunnicliffe
Added a bit of documentation. |
140 |
"""Convert an IPv4 dotted decimal address to an integer"""
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
141 |
b = [int(b) for b in ipv4.split('.')] |
142 |
return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3] |
|
143 |
||
144 |
||
145 |
def ipv4_in_cidr(ipv4, cidr): |
|
1091.6.3
by James Tunnicliffe
Added a bit of documentation. |
146 |
"""Returns True if the given address is in the given CIDR"""
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
147 |
if '/' in ipv4: |
148 |
ipv4, _ = ipv4.split('/') |
|
149 |
ipv4 = ipv4_to_int(ipv4) |
|
150 |
value, bits = cidr.split('/') |
|
151 |
subnet = ipv4_to_int(value) |
|
152 |
mask = 0xFFFFFFFF & (0xFFFFFFFF << (32-int(bits))) |
|
153 |
return (ipv4 & mask) == subnet |
|
154 |
||
155 |
||
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
156 |
def main(argv=None): |
157 |
args = parse_args(argv) |
|
158 |
configure_logging(args.verbose) |
|
159 |
bs_manager = BootstrapManager.from_args(args) |
|
1263.1.1
by Martin Packman
Refactor how juju feature flags are handled with new enable_feature method |
160 |
bs_manager.client.enable_feature('address-allocation') |
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
161 |
with cleaned_bootstrap_context(bs_manager, args) as ctx: |
162 |
assess_spaces_subnets(bs_manager.client) |
|
163 |
return ctx.return_code |
|
1091.6.1
by James Tunnicliffe
Addded test for spaces and subnets. Currently only works with fixed subnets that exist in the Canonical EC2 account in the eu-central-1. |
164 |
|
165 |
||
166 |
if __name__ == '__main__': |
|
1226.1.1
by Martin Packman
Fix assess_spaces_subnets by adapting to new BootstrapManager code from container networking test |
167 |
sys.exit(main()) |