Merge lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 into lp:~openstack-charmers-archive/charms/trusty/neutron-api/next
- Trusty Tahr (14.04)
- next-amulet-15.10
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 153 |
Proposed branch: | lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/neutron-api/next |
Diff against target: |
448 lines (+177/-35) 11 files modified
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) hooks/charmhelpers/contrib/openstack/amulet/utils.py (+1/-1) hooks/charmhelpers/contrib/openstack/context.py (+40/-13) hooks/charmhelpers/contrib/openstack/neutron.py (+17/-3) hooks/charmhelpers/contrib/openstack/templates/ceph.conf (+6/-0) hooks/charmhelpers/contrib/openstack/utils.py (+1/-0) hooks/charmhelpers/core/hookenv.py (+0/-1) hooks/charmhelpers/core/host.py (+12/-1) tests/basic_deployment.py (+19/-15) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) tests/charmhelpers/contrib/openstack/amulet/utils.py (+1/-1) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
Update amulet tests for Trusty-Liberty, Wily-Liberty.
Sync charmhelpers.
Add service and relations to satisfy workload status ready state.
Add new logic to wait for extended status message to confirm deploy is ready, before testing.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11175 neutron-api-next for 1chb1n mp274709
UNIT OK: passed
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7386 neutron-api-next for 1chb1n mp274709
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
- 157. By Ryan Beisner
-
fix relation check, remove varying unit data check
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #12028 neutron-api-next for 1chb1n mp274709
LINT OK: passed
Build: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11177 neutron-api-next for 1chb1n mp274709
UNIT OK: passed
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7391 neutron-api-next for 1chb1n mp274709
AMULET OK: passed
Build: http://
Preview Diff
1 | === modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py' | |||
2 | --- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-25 14:35:35 +0000 | |||
3 | +++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 16:14:02 +0000 | |||
4 | @@ -14,6 +14,7 @@ | |||
5 | 14 | # You should have received a copy of the GNU Lesser General Public License | 14 | # You should have received a copy of the GNU Lesser General Public License |
6 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
7 | 16 | 16 | ||
8 | 17 | import re | ||
9 | 17 | import six | 18 | import six |
10 | 18 | from collections import OrderedDict | 19 | from collections import OrderedDict |
11 | 19 | from charmhelpers.contrib.amulet.deployment import ( | 20 | from charmhelpers.contrib.amulet.deployment import ( |
12 | @@ -114,6 +115,45 @@ | |||
13 | 114 | for service, config in six.iteritems(configs): | 115 | for service, config in six.iteritems(configs): |
14 | 115 | self.d.configure(service, config) | 116 | self.d.configure(service, config) |
15 | 116 | 117 | ||
16 | 118 | def _auto_wait_for_status(self, message=None, exclude_services=None, | ||
17 | 119 | timeout=1800): | ||
18 | 120 | """Wait for all units to have a specific extended status, except | ||
19 | 121 | for any defined as excluded. Unless specified via message, any | ||
20 | 122 | status containing any case of 'ready' will be considered a match. | ||
21 | 123 | |||
22 | 124 | Examples of message usage: | ||
23 | 125 | |||
24 | 126 | Wait for all unit status to CONTAIN any case of 'ready' or 'ok': | ||
25 | 127 | message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) | ||
26 | 128 | |||
27 | 129 | Wait for all units to reach this status (exact match): | ||
28 | 130 | message = 'Unit is ready' | ||
29 | 131 | |||
30 | 132 | Wait for all units to reach any one of these (exact match): | ||
31 | 133 | message = re.compile('Unit is ready|OK|Ready') | ||
32 | 134 | |||
33 | 135 | Wait for at least one unit to reach this status (exact match): | ||
34 | 136 | message = {'ready'} | ||
35 | 137 | |||
36 | 138 | See Amulet's sentry.wait_for_messages() for message usage detail. | ||
37 | 139 | https://github.com/juju/amulet/blob/master/amulet/sentry.py | ||
38 | 140 | |||
39 | 141 | :param message: Expected status match | ||
40 | 142 | :param exclude_services: List of juju service names to ignore | ||
41 | 143 | :param timeout: Maximum time in seconds to wait for status match | ||
42 | 144 | :returns: None. Raises if timeout is hit. | ||
43 | 145 | """ | ||
44 | 146 | |||
45 | 147 | if not message: | ||
46 | 148 | message = re.compile('.*ready.*', re.IGNORECASE) | ||
47 | 149 | |||
48 | 150 | if not exclude_services: | ||
49 | 151 | exclude_services = [] | ||
50 | 152 | |||
51 | 153 | services = list(set(self.d.services.keys()) - set(exclude_services)) | ||
52 | 154 | service_messages = {service: message for service in services} | ||
53 | 155 | self.d.sentry.wait_for_messages(service_messages, timeout=timeout) | ||
54 | 156 | |||
55 | 117 | def _get_openstack_release(self): | 157 | def _get_openstack_release(self): |
56 | 118 | """Get openstack release. | 158 | """Get openstack release. |
57 | 119 | 159 | ||
58 | 120 | 160 | ||
59 | === modified file 'hooks/charmhelpers/contrib/openstack/amulet/utils.py' | |||
60 | --- hooks/charmhelpers/contrib/openstack/amulet/utils.py 2015-09-25 14:35:35 +0000 | |||
61 | +++ hooks/charmhelpers/contrib/openstack/amulet/utils.py 2015-10-16 16:14:02 +0000 | |||
62 | @@ -752,7 +752,7 @@ | |||
63 | 752 | self.log.debug('SSL is enabled @{}:{} ' | 752 | self.log.debug('SSL is enabled @{}:{} ' |
64 | 753 | '({})'.format(host, port, unit_name)) | 753 | '({})'.format(host, port, unit_name)) |
65 | 754 | return True | 754 | return True |
67 | 755 | elif not port and not conf_ssl: | 755 | elif not conf_ssl: |
68 | 756 | self.log.debug('SSL not enabled @{}:{} ' | 756 | self.log.debug('SSL not enabled @{}:{} ' |
69 | 757 | '({})'.format(host, port, unit_name)) | 757 | '({})'.format(host, port, unit_name)) |
70 | 758 | return False | 758 | return False |
71 | 759 | 759 | ||
72 | === modified file 'hooks/charmhelpers/contrib/openstack/context.py' | |||
73 | --- hooks/charmhelpers/contrib/openstack/context.py 2015-09-28 19:06:04 +0000 | |||
74 | +++ hooks/charmhelpers/contrib/openstack/context.py 2015-10-16 16:14:02 +0000 | |||
75 | @@ -14,6 +14,7 @@ | |||
76 | 14 | # You should have received a copy of the GNU Lesser General Public License | 14 | # You should have received a copy of the GNU Lesser General Public License |
77 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
78 | 16 | 16 | ||
79 | 17 | import glob | ||
80 | 17 | import json | 18 | import json |
81 | 18 | import os | 19 | import os |
82 | 19 | import re | 20 | import re |
83 | @@ -951,6 +952,19 @@ | |||
84 | 951 | 'config': config} | 952 | 'config': config} |
85 | 952 | return ovs_ctxt | 953 | return ovs_ctxt |
86 | 953 | 954 | ||
87 | 955 | def midonet_ctxt(self): | ||
88 | 956 | driver = neutron_plugin_attribute(self.plugin, 'driver', | ||
89 | 957 | self.network_manager) | ||
90 | 958 | midonet_config = neutron_plugin_attribute(self.plugin, 'config', | ||
91 | 959 | self.network_manager) | ||
92 | 960 | mido_ctxt = {'core_plugin': driver, | ||
93 | 961 | 'neutron_plugin': 'midonet', | ||
94 | 962 | 'neutron_security_groups': self.neutron_security_groups, | ||
95 | 963 | 'local_ip': unit_private_ip(), | ||
96 | 964 | 'config': midonet_config} | ||
97 | 965 | |||
98 | 966 | return mido_ctxt | ||
99 | 967 | |||
100 | 954 | def __call__(self): | 968 | def __call__(self): |
101 | 955 | if self.network_manager not in ['quantum', 'neutron']: | 969 | if self.network_manager not in ['quantum', 'neutron']: |
102 | 956 | return {} | 970 | return {} |
103 | @@ -972,6 +986,8 @@ | |||
104 | 972 | ctxt.update(self.nuage_ctxt()) | 986 | ctxt.update(self.nuage_ctxt()) |
105 | 973 | elif self.plugin == 'plumgrid': | 987 | elif self.plugin == 'plumgrid': |
106 | 974 | ctxt.update(self.pg_ctxt()) | 988 | ctxt.update(self.pg_ctxt()) |
107 | 989 | elif self.plugin == 'midonet': | ||
108 | 990 | ctxt.update(self.midonet_ctxt()) | ||
109 | 975 | 991 | ||
110 | 976 | alchemy_flags = config('neutron-alchemy-flags') | 992 | alchemy_flags = config('neutron-alchemy-flags') |
111 | 977 | if alchemy_flags: | 993 | if alchemy_flags: |
112 | @@ -1104,7 +1120,7 @@ | |||
113 | 1104 | 1120 | ||
114 | 1105 | ctxt = { | 1121 | ctxt = { |
115 | 1106 | ... other context ... | 1122 | ... other context ... |
117 | 1107 | 'subordinate_config': { | 1123 | 'subordinate_configuration': { |
118 | 1108 | 'DEFAULT': { | 1124 | 'DEFAULT': { |
119 | 1109 | 'key1': 'value1', | 1125 | 'key1': 'value1', |
120 | 1110 | }, | 1126 | }, |
121 | @@ -1145,22 +1161,23 @@ | |||
122 | 1145 | try: | 1161 | try: |
123 | 1146 | sub_config = json.loads(sub_config) | 1162 | sub_config = json.loads(sub_config) |
124 | 1147 | except: | 1163 | except: |
127 | 1148 | log('Could not parse JSON from subordinate_config ' | 1164 | log('Could not parse JSON from ' |
128 | 1149 | 'setting from %s' % rid, level=ERROR) | 1165 | 'subordinate_configuration setting from %s' |
129 | 1166 | % rid, level=ERROR) | ||
130 | 1150 | continue | 1167 | continue |
131 | 1151 | 1168 | ||
132 | 1152 | for service in self.services: | 1169 | for service in self.services: |
133 | 1153 | if service not in sub_config: | 1170 | if service not in sub_config: |
137 | 1154 | log('Found subordinate_config on %s but it contained' | 1171 | log('Found subordinate_configuration on %s but it ' |
138 | 1155 | 'nothing for %s service' % (rid, service), | 1172 | 'contained nothing for %s service' |
139 | 1156 | level=INFO) | 1173 | % (rid, service), level=INFO) |
140 | 1157 | continue | 1174 | continue |
141 | 1158 | 1175 | ||
142 | 1159 | sub_config = sub_config[service] | 1176 | sub_config = sub_config[service] |
143 | 1160 | if self.config_file not in sub_config: | 1177 | if self.config_file not in sub_config: |
147 | 1161 | log('Found subordinate_config on %s but it contained' | 1178 | log('Found subordinate_configuration on %s but it ' |
148 | 1162 | 'nothing for %s' % (rid, self.config_file), | 1179 | 'contained nothing for %s' |
149 | 1163 | level=INFO) | 1180 | % (rid, self.config_file), level=INFO) |
150 | 1164 | continue | 1181 | continue |
151 | 1165 | 1182 | ||
152 | 1166 | sub_config = sub_config[self.config_file] | 1183 | sub_config = sub_config[self.config_file] |
153 | @@ -1363,7 +1380,7 @@ | |||
154 | 1363 | normalized.update({port: port for port in resolved | 1380 | normalized.update({port: port for port in resolved |
155 | 1364 | if port in ports}) | 1381 | if port in ports}) |
156 | 1365 | if resolved: | 1382 | if resolved: |
158 | 1366 | return {bridge: normalized[port] for port, bridge in | 1383 | return {normalized[port]: bridge for port, bridge in |
159 | 1367 | six.iteritems(portmap) if port in normalized.keys()} | 1384 | six.iteritems(portmap) if port in normalized.keys()} |
160 | 1368 | 1385 | ||
161 | 1369 | return None | 1386 | return None |
162 | @@ -1374,12 +1391,22 @@ | |||
163 | 1374 | def __call__(self): | 1391 | def __call__(self): |
164 | 1375 | ctxt = {} | 1392 | ctxt = {} |
165 | 1376 | mappings = super(PhyNICMTUContext, self).__call__() | 1393 | mappings = super(PhyNICMTUContext, self).__call__() |
168 | 1377 | if mappings and mappings.values(): | 1394 | if mappings and mappings.keys(): |
169 | 1378 | ports = mappings.values() | 1395 | ports = sorted(mappings.keys()) |
170 | 1379 | napi_settings = NeutronAPIContext()() | 1396 | napi_settings = NeutronAPIContext()() |
171 | 1380 | mtu = napi_settings.get('network_device_mtu') | 1397 | mtu = napi_settings.get('network_device_mtu') |
172 | 1398 | all_ports = set() | ||
173 | 1399 | # If any of ports is a vlan device, its underlying device must have | ||
174 | 1400 | # mtu applied first. | ||
175 | 1401 | for port in ports: | ||
176 | 1402 | for lport in glob.glob("/sys/class/net/%s/lower_*" % port): | ||
177 | 1403 | lport = os.path.basename(lport) | ||
178 | 1404 | all_ports.add(lport.split('_')[1]) | ||
179 | 1405 | |||
180 | 1406 | all_ports = list(all_ports) | ||
181 | 1407 | all_ports.extend(ports) | ||
182 | 1381 | if mtu: | 1408 | if mtu: |
184 | 1382 | ctxt["devs"] = '\\n'.join(ports) | 1409 | ctxt["devs"] = '\\n'.join(all_ports) |
185 | 1383 | ctxt['mtu'] = mtu | 1410 | ctxt['mtu'] = mtu |
186 | 1384 | 1411 | ||
187 | 1385 | return ctxt | 1412 | return ctxt |
188 | 1386 | 1413 | ||
189 | === modified file 'hooks/charmhelpers/contrib/openstack/neutron.py' | |||
190 | --- hooks/charmhelpers/contrib/openstack/neutron.py 2015-09-04 11:03:14 +0000 | |||
191 | +++ hooks/charmhelpers/contrib/openstack/neutron.py 2015-10-16 16:14:02 +0000 | |||
192 | @@ -209,6 +209,20 @@ | |||
193 | 209 | 'server_packages': ['neutron-server', | 209 | 'server_packages': ['neutron-server', |
194 | 210 | 'neutron-plugin-plumgrid'], | 210 | 'neutron-plugin-plumgrid'], |
195 | 211 | 'server_services': ['neutron-server'] | 211 | 'server_services': ['neutron-server'] |
196 | 212 | }, | ||
197 | 213 | 'midonet': { | ||
198 | 214 | 'config': '/etc/neutron/plugins/midonet/midonet.ini', | ||
199 | 215 | 'driver': 'midonet.neutron.plugin.MidonetPluginV2', | ||
200 | 216 | 'contexts': [ | ||
201 | 217 | context.SharedDBContext(user=config('neutron-database-user'), | ||
202 | 218 | database=config('neutron-database'), | ||
203 | 219 | relation_prefix='neutron', | ||
204 | 220 | ssl_dir=NEUTRON_CONF_DIR)], | ||
205 | 221 | 'services': [], | ||
206 | 222 | 'packages': [[headers_package()] + determine_dkms_package()], | ||
207 | 223 | 'server_packages': ['neutron-server', | ||
208 | 224 | 'python-neutron-plugin-midonet'], | ||
209 | 225 | 'server_services': ['neutron-server'] | ||
210 | 212 | } | 226 | } |
211 | 213 | } | 227 | } |
212 | 214 | if release >= 'icehouse': | 228 | if release >= 'icehouse': |
213 | @@ -310,10 +324,10 @@ | |||
214 | 310 | def parse_data_port_mappings(mappings, default_bridge='br-data'): | 324 | def parse_data_port_mappings(mappings, default_bridge='br-data'): |
215 | 311 | """Parse data port mappings. | 325 | """Parse data port mappings. |
216 | 312 | 326 | ||
218 | 313 | Mappings must be a space-delimited list of port:bridge mappings. | 327 | Mappings must be a space-delimited list of bridge:port. |
219 | 314 | 328 | ||
222 | 315 | Returns dict of the form {port:bridge} where port may be an mac address or | 329 | Returns dict of the form {port:bridge} where ports may be mac addresses or |
223 | 316 | interface name. | 330 | interface names. |
224 | 317 | """ | 331 | """ |
225 | 318 | 332 | ||
226 | 319 | # NOTE(dosaboy): we use rvalue for key to allow multiple values to be | 333 | # NOTE(dosaboy): we use rvalue for key to allow multiple values to be |
227 | 320 | 334 | ||
228 | === modified file 'hooks/charmhelpers/contrib/openstack/templates/ceph.conf' | |||
229 | --- hooks/charmhelpers/contrib/openstack/templates/ceph.conf 2015-07-16 20:17:53 +0000 | |||
230 | +++ hooks/charmhelpers/contrib/openstack/templates/ceph.conf 2015-10-16 16:14:02 +0000 | |||
231 | @@ -13,3 +13,9 @@ | |||
232 | 13 | err to syslog = {{ use_syslog }} | 13 | err to syslog = {{ use_syslog }} |
233 | 14 | clog to syslog = {{ use_syslog }} | 14 | clog to syslog = {{ use_syslog }} |
234 | 15 | 15 | ||
235 | 16 | [client] | ||
236 | 17 | {% if rbd_client_cache_settings -%} | ||
237 | 18 | {% for key, value in rbd_client_cache_settings.iteritems() -%} | ||
238 | 19 | {{ key }} = {{ value }} | ||
239 | 20 | {% endfor -%} | ||
240 | 21 | {%- endif %} | ||
241 | 16 | \ No newline at end of file | 22 | \ No newline at end of file |
242 | 17 | 23 | ||
243 | === modified file 'hooks/charmhelpers/contrib/openstack/utils.py' | |||
244 | --- hooks/charmhelpers/contrib/openstack/utils.py 2015-10-06 07:11:01 +0000 | |||
245 | +++ hooks/charmhelpers/contrib/openstack/utils.py 2015-10-16 16:14:02 +0000 | |||
246 | @@ -121,6 +121,7 @@ | |||
247 | 121 | ('2.2.2', 'kilo'), | 121 | ('2.2.2', 'kilo'), |
248 | 122 | ('2.3.0', 'liberty'), | 122 | ('2.3.0', 'liberty'), |
249 | 123 | ('2.4.0', 'liberty'), | 123 | ('2.4.0', 'liberty'), |
250 | 124 | ('2.5.0', 'liberty'), | ||
251 | 124 | ]) | 125 | ]) |
252 | 125 | 126 | ||
253 | 126 | # >= Liberty version->codename mapping | 127 | # >= Liberty version->codename mapping |
254 | 127 | 128 | ||
255 | === modified file 'hooks/charmhelpers/core/hookenv.py' | |||
256 | --- hooks/charmhelpers/core/hookenv.py 2015-09-28 19:06:04 +0000 | |||
257 | +++ hooks/charmhelpers/core/hookenv.py 2015-10-16 16:14:02 +0000 | |||
258 | @@ -795,7 +795,6 @@ | |||
259 | 795 | raise | 795 | raise |
260 | 796 | log_message = 'status-set failed: {} {}'.format(workload_state, | 796 | log_message = 'status-set failed: {} {}'.format(workload_state, |
261 | 797 | message) | 797 | message) |
262 | 798 | # XXX Fix this | ||
263 | 799 | log(log_message, level='INFO') | 798 | log(log_message, level='INFO') |
264 | 800 | 799 | ||
265 | 801 | 800 | ||
266 | 802 | 801 | ||
267 | === modified file 'hooks/charmhelpers/core/host.py' | |||
268 | --- hooks/charmhelpers/core/host.py 2015-09-25 14:35:35 +0000 | |||
269 | +++ hooks/charmhelpers/core/host.py 2015-10-16 16:14:02 +0000 | |||
270 | @@ -566,7 +566,14 @@ | |||
271 | 566 | os.chdir(cur) | 566 | os.chdir(cur) |
272 | 567 | 567 | ||
273 | 568 | 568 | ||
275 | 569 | def chownr(path, owner, group, follow_links=True): | 569 | def chownr(path, owner, group, follow_links=True, chowntopdir=False): |
276 | 570 | """ | ||
277 | 571 | Recursively change user and group ownership of files and directories | ||
278 | 572 | in given path. Doesn't chown path itself by default, only its children. | ||
279 | 573 | |||
280 | 574 | :param bool follow_links: Also Chown links if True | ||
281 | 575 | :param bool chowntopdir: Also chown path itself if True | ||
282 | 576 | """ | ||
283 | 570 | uid = pwd.getpwnam(owner).pw_uid | 577 | uid = pwd.getpwnam(owner).pw_uid |
284 | 571 | gid = grp.getgrnam(group).gr_gid | 578 | gid = grp.getgrnam(group).gr_gid |
285 | 572 | if follow_links: | 579 | if follow_links: |
286 | @@ -574,6 +581,10 @@ | |||
287 | 574 | else: | 581 | else: |
288 | 575 | chown = os.lchown | 582 | chown = os.lchown |
289 | 576 | 583 | ||
290 | 584 | if chowntopdir: | ||
291 | 585 | broken_symlink = os.path.lexists(path) and not os.path.exists(path) | ||
292 | 586 | if not broken_symlink: | ||
293 | 587 | chown(path, uid, gid) | ||
294 | 577 | for root, dirs, files in os.walk(path): | 588 | for root, dirs, files in os.walk(path): |
295 | 578 | for name in dirs + files: | 589 | for name in dirs + files: |
296 | 579 | full = os.path.join(root, name) | 590 | full = os.path.join(root, name) |
297 | 580 | 591 | ||
298 | === modified file 'tests/020-basic-trusty-liberty' (properties changed: -x to +x) | |||
299 | === modified file 'tests/021-basic-wily-liberty' (properties changed: -x to +x) | |||
300 | === modified file 'tests/basic_deployment.py' | |||
301 | --- tests/basic_deployment.py 2015-09-28 19:06:04 +0000 | |||
302 | +++ tests/basic_deployment.py 2015-10-16 16:14:02 +0000 | |||
303 | @@ -1,11 +1,5 @@ | |||
304 | 1 | #!/usr/bin/python | ||
305 | 2 | """ | ||
306 | 3 | Basic neutron-api functional test. | ||
307 | 4 | """ | ||
308 | 5 | |||
309 | 6 | import amulet | 1 | import amulet |
310 | 7 | import os | 2 | import os |
311 | 8 | import time | ||
312 | 9 | import yaml | 3 | import yaml |
313 | 10 | 4 | ||
314 | 11 | from charmhelpers.contrib.openstack.amulet.deployment import ( | 5 | from charmhelpers.contrib.openstack.amulet.deployment import ( |
315 | @@ -35,6 +29,11 @@ | |||
316 | 35 | self._add_relations() | 29 | self._add_relations() |
317 | 36 | self._configure_services() | 30 | self._configure_services() |
318 | 37 | self._deploy() | 31 | self._deploy() |
319 | 32 | |||
320 | 33 | u.log.info('Waiting on extended status checks...') | ||
321 | 34 | exclude_services = ['mysql'] | ||
322 | 35 | self._auto_wait_for_status(exclude_services=exclude_services) | ||
323 | 36 | |||
324 | 38 | self._initialize_tests() | 37 | self._initialize_tests() |
325 | 39 | 38 | ||
326 | 40 | def _add_services(self): | 39 | def _add_services(self): |
327 | @@ -48,6 +47,7 @@ | |||
328 | 48 | other_services = [{'name': 'mysql'}, | 47 | other_services = [{'name': 'mysql'}, |
329 | 49 | {'name': 'rabbitmq-server'}, | 48 | {'name': 'rabbitmq-server'}, |
330 | 50 | {'name': 'keystone'}, | 49 | {'name': 'keystone'}, |
331 | 50 | {'name': 'glance'}, # to satisfy workload status | ||
332 | 51 | {'name': 'neutron-openvswitch'}, | 51 | {'name': 'neutron-openvswitch'}, |
333 | 52 | {'name': 'nova-cloud-controller'}, | 52 | {'name': 'nova-cloud-controller'}, |
334 | 53 | {'name': 'neutron-gateway'}, | 53 | {'name': 'neutron-gateway'}, |
335 | @@ -68,6 +68,19 @@ | |||
336 | 68 | 'nova-compute:neutron-plugin': 'neutron-openvswitch:' | 68 | 'nova-compute:neutron-plugin': 'neutron-openvswitch:' |
337 | 69 | 'neutron-plugin', | 69 | 'neutron-plugin', |
338 | 70 | 'nova-cloud-controller:shared-db': 'mysql:shared-db', | 70 | 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
339 | 71 | 'neutron-gateway:amqp': 'rabbitmq-server:amqp', | ||
340 | 72 | 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', | ||
341 | 73 | 'nova-compute:amqp': 'rabbitmq-server:amqp', | ||
342 | 74 | 'neutron-openvswitch:amqp': 'rabbitmq-server:amqp', | ||
343 | 75 | 'nova-cloud-controller:identity-service': 'keystone:' | ||
344 | 76 | 'identity-service', | ||
345 | 77 | 'nova-cloud-controller:cloud-compute': 'nova-compute:' | ||
346 | 78 | 'cloud-compute', | ||
347 | 79 | 'glance:identity-service': 'keystone:identity-service', | ||
348 | 80 | 'glance:shared-db': 'mysql:shared-db', | ||
349 | 81 | 'glance:amqp': 'rabbitmq-server:amqp', | ||
350 | 82 | 'nova-compute:image-service': 'glance:image-service', | ||
351 | 83 | 'nova-cloud-controller:image-service': 'glance:image-service', | ||
352 | 71 | } | 84 | } |
353 | 72 | 85 | ||
354 | 73 | # NOTE(beisner): relate this separately due to the resulting | 86 | # NOTE(beisner): relate this separately due to the resulting |
355 | @@ -158,8 +171,6 @@ | |||
356 | 158 | self._get_openstack_release())) | 171 | self._get_openstack_release())) |
357 | 159 | u.log.debug('openstack release str: {}'.format( | 172 | u.log.debug('openstack release str: {}'.format( |
358 | 160 | self._get_openstack_release_string())) | 173 | self._get_openstack_release_string())) |
359 | 161 | # Let things settle a bit before moving forward | ||
360 | 162 | time.sleep(30) | ||
361 | 163 | 174 | ||
362 | 164 | def test_100_services(self): | 175 | def test_100_services(self): |
363 | 165 | """Verify the expected services are running on the corresponding | 176 | """Verify the expected services are running on the corresponding |
364 | @@ -226,13 +237,6 @@ | |||
365 | 226 | 'password': u.not_null | 237 | 'password': u.not_null |
366 | 227 | } | 238 | } |
367 | 228 | 239 | ||
368 | 229 | if self._get_openstack_release() == self.precise_icehouse: | ||
369 | 230 | # Precise | ||
370 | 231 | expected['allowed_units'] = 'nova-cloud-controller/0 neutron-api/0' | ||
371 | 232 | else: | ||
372 | 233 | # Not Precise | ||
373 | 234 | expected['allowed_units'] = 'neutron-api/0' | ||
374 | 235 | |||
375 | 236 | ret = u.validate_relation_data(unit, relation, expected) | 240 | ret = u.validate_relation_data(unit, relation, expected) |
376 | 237 | if ret: | 241 | if ret: |
377 | 238 | message = u.relation_error('mysql shared-db', ret) | 242 | message = u.relation_error('mysql shared-db', ret) |
378 | 239 | 243 | ||
379 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' | |||
380 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-25 14:35:35 +0000 | |||
381 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 16:14:02 +0000 | |||
382 | @@ -14,6 +14,7 @@ | |||
383 | 14 | # You should have received a copy of the GNU Lesser General Public License | 14 | # You should have received a copy of the GNU Lesser General Public License |
384 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
385 | 16 | 16 | ||
386 | 17 | import re | ||
387 | 17 | import six | 18 | import six |
388 | 18 | from collections import OrderedDict | 19 | from collections import OrderedDict |
389 | 19 | from charmhelpers.contrib.amulet.deployment import ( | 20 | from charmhelpers.contrib.amulet.deployment import ( |
390 | @@ -114,6 +115,45 @@ | |||
391 | 114 | for service, config in six.iteritems(configs): | 115 | for service, config in six.iteritems(configs): |
392 | 115 | self.d.configure(service, config) | 116 | self.d.configure(service, config) |
393 | 116 | 117 | ||
394 | 118 | def _auto_wait_for_status(self, message=None, exclude_services=None, | ||
395 | 119 | timeout=1800): | ||
396 | 120 | """Wait for all units to have a specific extended status, except | ||
397 | 121 | for any defined as excluded. Unless specified via message, any | ||
398 | 122 | status containing any case of 'ready' will be considered a match. | ||
399 | 123 | |||
400 | 124 | Examples of message usage: | ||
401 | 125 | |||
402 | 126 | Wait for all unit status to CONTAIN any case of 'ready' or 'ok': | ||
403 | 127 | message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) | ||
404 | 128 | |||
405 | 129 | Wait for all units to reach this status (exact match): | ||
406 | 130 | message = 'Unit is ready' | ||
407 | 131 | |||
408 | 132 | Wait for all units to reach any one of these (exact match): | ||
409 | 133 | message = re.compile('Unit is ready|OK|Ready') | ||
410 | 134 | |||
411 | 135 | Wait for at least one unit to reach this status (exact match): | ||
412 | 136 | message = {'ready'} | ||
413 | 137 | |||
414 | 138 | See Amulet's sentry.wait_for_messages() for message usage detail. | ||
415 | 139 | https://github.com/juju/amulet/blob/master/amulet/sentry.py | ||
416 | 140 | |||
417 | 141 | :param message: Expected status match | ||
418 | 142 | :param exclude_services: List of juju service names to ignore | ||
419 | 143 | :param timeout: Maximum time in seconds to wait for status match | ||
420 | 144 | :returns: None. Raises if timeout is hit. | ||
421 | 145 | """ | ||
422 | 146 | |||
423 | 147 | if not message: | ||
424 | 148 | message = re.compile('.*ready.*', re.IGNORECASE) | ||
425 | 149 | |||
426 | 150 | if not exclude_services: | ||
427 | 151 | exclude_services = [] | ||
428 | 152 | |||
429 | 153 | services = list(set(self.d.services.keys()) - set(exclude_services)) | ||
430 | 154 | service_messages = {service: message for service in services} | ||
431 | 155 | self.d.sentry.wait_for_messages(service_messages, timeout=timeout) | ||
432 | 156 | |||
433 | 117 | def _get_openstack_release(self): | 157 | def _get_openstack_release(self): |
434 | 118 | """Get openstack release. | 158 | """Get openstack release. |
435 | 119 | 159 | ||
436 | 120 | 160 | ||
437 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/utils.py' | |||
438 | --- tests/charmhelpers/contrib/openstack/amulet/utils.py 2015-09-25 14:35:35 +0000 | |||
439 | +++ tests/charmhelpers/contrib/openstack/amulet/utils.py 2015-10-16 16:14:02 +0000 | |||
440 | @@ -752,7 +752,7 @@ | |||
441 | 752 | self.log.debug('SSL is enabled @{}:{} ' | 752 | self.log.debug('SSL is enabled @{}:{} ' |
442 | 753 | '({})'.format(host, port, unit_name)) | 753 | '({})'.format(host, port, unit_name)) |
443 | 754 | return True | 754 | return True |
445 | 755 | elif not port and not conf_ssl: | 755 | elif not conf_ssl: |
446 | 756 | self.log.debug('SSL not enabled @{}:{} ' | 756 | self.log.debug('SSL not enabled @{}:{} ' |
447 | 757 | '({})'.format(host, port, unit_name)) | 757 | '({})'.format(host, port, unit_name)) |
448 | 758 | return False | 758 | return False |
charm_lint_check #12024 neutron-api-next for 1chb1n mp274709
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/12024/