blob: e9702493b39ef0d2a955acf4dc7d6ba623885fc4 [file] [log] [blame]
Sean Dague655e0af2014-05-29 09:00:22 -04001#!/usr/bin/env python
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Joe H. Rahme61469fd2014-12-02 17:09:17 +010015"""Javelin is a tool for creating, verifying, and deleting a small set of
Sean Dague655e0af2014-05-29 09:00:22 -040016resources in a declarative way.
17
Joe H. Rahme61469fd2014-12-02 17:09:17 +010018Javelin is meant to be used as a way to validate quickly that resources can
19survive an upgrade process.
20
21Authentication
22--------------
23
24Javelin will be creating (and removing) users and tenants so it needs the admin
25credentials of your cloud to operate properly. The corresponding info can be
26given the usual way, either through CLI options or environment variables.
27
28You're probably familiar with these, but just in case::
29
30 +----------+------------------+----------------------+
31 | Param | CLI | Environment Variable |
32 +----------+------------------+----------------------+
33 | Username | --os-username | OS_USERNAME |
34 | Password | --os-password | OS_PASSWORD |
35 | Tenant | --os-tenant-name | OS_TENANT_NAME |
36 +----------+------------------+----------------------+
37
38
39Runtime Arguments
40-----------------
41
42**-m/--mode**: (Required) Has to be one of 'check', 'create' or 'destroy'. It
43indicates which actions javelin is going to perform.
44
45**-r/--resources**: (Required) The path to a YAML file describing the resources
46used by Javelin.
47
48**-d/--devstack-base**: (Required) The path to the devstack repo used to
49retrieve artefacts (like images) that will be referenced in the resource files.
50
51**-c/--config-file**: (Optional) The path to a valid Tempest config file
52describing your cloud. Javelin may use this to determine if certain services
53are enabled and modify its behavior accordingly.
54
55
56Resource file
57-------------
58
59The resource file is a valid YAML file describing the resources that will be
60created, checked and destroyed by javelin. Here's a canonical example of a
61resource file::
62
63 tenants:
64 - javelin
65 - discuss
66
67 users:
68 - name: javelin
69 pass: gungnir
70 tenant: javelin
71 - name: javelin2
72 pass: gungnir2
73 tenant: discuss
74
75 # resources that we want to create
76 images:
77 - name: javelin_cirros
78 owner: javelin
79 file: cirros-0.3.2-x86_64-blank.img
80 format: ami
81 aki: cirros-0.3.2-x86_64-vmlinuz
82 ari: cirros-0.3.2-x86_64-initrd
83
84 servers:
85 - name: peltast
86 owner: javelin
87 flavor: m1.small
88 image: javelin_cirros
89 - name: hoplite
90 owner: javelin
91 flavor: m1.medium
92 image: javelin_cirros
93
94
95An important piece of the resource definition is the *owner* field, which is
96the user (that we've created) that is the owner of that resource. All
97operations on that resource will happen as that regular user to ensure that
98admin level access does not mask issues.
99
100The check phase will act like a unit test, using well known assert methods to
101verify that the correct resources exist.
102
Sean Dague655e0af2014-05-29 09:00:22 -0400103"""
104
Matthew Treinish96e9e882014-06-09 18:37:19 -0400105import argparse
Chris Dent51e76de2014-10-01 12:07:14 +0100106import collections
Chris Dent878f3782014-06-30 17:04:15 +0100107import datetime
Sean Dague655e0af2014-05-29 09:00:22 -0400108import os
109import sys
110import unittest
Sean Dague655e0af2014-05-29 09:00:22 -0400111
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200112import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +0000113from oslo_log import log as logging
114from oslo_utils import timeutils
Masayuki Igawad9388762015-01-20 14:56:42 +0900115from tempest_lib import exceptions as lib_exc
Matthew Treinish96e9e882014-06-09 18:37:19 -0400116import yaml
Sean Dague655e0af2014-05-29 09:00:22 -0400117
118import tempest.auth
Joe Gordon28a84ae2014-07-17 15:38:28 +0000119from tempest import config
Sean Dague655e0af2014-05-29 09:00:22 -0400120from tempest.services.compute.json import flavors_client
Emilien Macchic3e3e292015-03-11 17:42:08 -0400121from tempest.services.compute.json import floating_ips_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200122from tempest.services.compute.json import security_groups_client
Sean Dague655e0af2014-05-29 09:00:22 -0400123from tempest.services.compute.json import servers_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100124from tempest.services.identity.v2.json import identity_client
Sean Dague655e0af2014-05-29 09:00:22 -0400125from tempest.services.image.v2.json import image_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200126from tempest.services.network.json import network_client
Sean Dague655e0af2014-05-29 09:00:22 -0400127from tempest.services.object_storage import container_client
128from tempest.services.object_storage import object_client
Chris Dent878f3782014-06-30 17:04:15 +0100129from tempest.services.telemetry.json import telemetry_client
Emilien Macchi626b4f82014-06-15 21:44:29 +0200130from tempest.services.volume.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400131
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200132CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400133OPTS = {}
134USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100135RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400136
137LOG = None
138
Chris Dent878f3782014-06-30 17:04:15 +0100139JAVELIN_START = datetime.datetime.utcnow()
140
Sean Dague655e0af2014-05-29 09:00:22 -0400141
142class OSClient(object):
143 _creds = None
144 identity = None
145 servers = None
146
147 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000148 default_params = {
149 'disable_ssl_certificate_validation':
150 CONF.identity.disable_ssl_certificate_validation,
151 'ca_certs': CONF.identity.ca_certificates_file,
152 'trace_requests': CONF.debug.trace_requests
153 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000154 default_params_with_timeout_values = {
155 'build_interval': CONF.compute.build_interval,
156 'build_timeout': CONF.compute.build_timeout
157 }
158 default_params_with_timeout_values.update(default_params)
159
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000160 compute_params = {
161 'service': CONF.compute.catalog_type,
162 'region': CONF.compute.region or CONF.identity.region,
163 'endpoint_type': CONF.compute.endpoint_type,
164 'build_interval': CONF.compute.build_interval,
165 'build_timeout': CONF.compute.build_timeout
166 }
167 compute_params.update(default_params)
168
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000169 object_storage_params = {
170 'service': CONF.object_storage.catalog_type,
171 'region': CONF.object_storage.region or CONF.identity.region,
172 'endpoint_type': CONF.object_storage.endpoint_type
173 }
174 object_storage_params.update(default_params)
175
Sean Dague655e0af2014-05-29 09:00:22 -0400176 _creds = tempest.auth.KeystoneV2Credentials(
177 username=user,
178 password=pw,
179 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000180 auth_provider_params = {
181 'disable_ssl_certificate_validation':
182 CONF.identity.disable_ssl_certificate_validation,
183 'ca_certs': CONF.identity.ca_certificates_file,
184 'trace_requests': CONF.debug.trace_requests
185 }
186 _auth = tempest.auth.KeystoneV2AuthProvider(
187 _creds, CONF.identity.uri, **auth_provider_params)
ghanshyamd26b5cd2015-02-09 14:48:58 +0900188 self.identity = identity_client.IdentityClientJSON(
189 _auth,
190 CONF.identity.catalog_type,
191 CONF.identity.region,
192 endpoint_type='adminURL',
193 **default_params_with_timeout_values)
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000194 self.servers = servers_client.ServersClientJSON(_auth,
195 **compute_params)
196 self.flavors = flavors_client.FlavorsClientJSON(_auth,
197 **compute_params)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400198 self.floating_ips = floating_ips_client.FloatingIPsClientJSON(
199 _auth, **compute_params)
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000200 self.secgroups = security_groups_client.SecurityGroupsClientJSON(
201 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000202 self.objects = object_client.ObjectClient(_auth,
203 **object_storage_params)
204 self.containers = container_client.ContainerClient(
205 _auth, **object_storage_params)
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900206 self.images = image_client.ImageClientV2JSON(
207 _auth,
208 CONF.image.catalog_type,
209 CONF.image.region or CONF.identity.region,
210 endpoint_type=CONF.image.endpoint_type,
211 build_interval=CONF.image.build_interval,
212 build_timeout=CONF.image.build_timeout,
213 **default_params)
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000214 self.telemetry = telemetry_client.TelemetryClientJSON(
215 _auth,
216 CONF.telemetry.catalog_type,
217 CONF.identity.region,
218 endpoint_type=CONF.telemetry.endpoint_type,
219 **default_params_with_timeout_values)
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000220 self.volumes = volumes_client.VolumesClientJSON(
221 _auth,
222 CONF.volume.catalog_type,
223 CONF.volume.region or CONF.identity.region,
224 endpoint_type=CONF.volume.endpoint_type,
225 build_interval=CONF.volume.build_interval,
226 build_timeout=CONF.volume.build_timeout,
227 **default_params)
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000228 self.networks = network_client.NetworkClientJSON(
229 _auth,
230 CONF.network.catalog_type,
231 CONF.network.region or CONF.identity.region,
232 endpoint_type=CONF.network.endpoint_type,
233 build_interval=CONF.network.build_interval,
234 build_timeout=CONF.network.build_timeout,
235 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400236
237
238def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100239 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400240 return yaml.load(open(fname, 'r'))
241
242
243def keystone_admin():
244 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
245
246
247def client_for_user(name):
248 LOG.debug("Entering client_for_user")
249 if name in USERS:
250 user = USERS[name]
251 LOG.debug("Created client for user %s" % user)
252 return OSClient(user['name'], user['pass'], user['tenant'])
253 else:
254 LOG.error("%s not found in USERS: %s" % (name, USERS))
255
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200256
Sean Dague655e0af2014-05-29 09:00:22 -0400257###################
258#
259# TENANTS
260#
261###################
262
263
264def create_tenants(tenants):
265 """Create tenants from resource definition.
266
267 Don't create the tenants if they already exist.
268 """
269 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500270 body = admin.identity.list_tenants()
Sean Dague655e0af2014-05-29 09:00:22 -0400271 existing = [x['name'] for x in body]
272 for tenant in tenants:
273 if tenant not in existing:
274 admin.identity.create_tenant(tenant)
275 else:
276 LOG.warn("Tenant '%s' already exists in this environment" % tenant)
277
Emilien Macchibb71e072014-07-05 19:18:52 +0200278
279def destroy_tenants(tenants):
280 admin = keystone_admin()
281 for tenant in tenants:
282 tenant_id = admin.identity.get_tenant_by_name(tenant)['id']
David Kranzb7afa922014-12-30 10:56:26 -0500283 admin.identity.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200284
Sean Dague655e0af2014-05-29 09:00:22 -0400285##############
286#
287# USERS
288#
289##############
290
291
292def _users_for_tenant(users, tenant):
293 u_for_t = []
294 for user in users:
295 for n in user:
296 if user[n]['tenant'] == tenant:
297 u_for_t.append(user[n])
298 return u_for_t
299
300
301def _tenants_from_users(users):
302 tenants = set()
303 for user in users:
304 for n in user:
305 tenants.add(user[n]['tenant'])
306 return tenants
307
308
309def _assign_swift_role(user):
310 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500311 roles = admin.identity.list_roles()
Sean Dague655e0af2014-05-29 09:00:22 -0400312 role = next(r for r in roles if r['name'] == 'Member')
313 LOG.debug(USERS[user])
314 try:
315 admin.identity.assign_user_role(
316 USERS[user]['tenant_id'],
317 USERS[user]['id'],
318 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900319 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400320 # don't care if it's already assigned
321 pass
322
323
324def create_users(users):
325 """Create tenants from resource definition.
326
327 Don't create the tenants if they already exist.
328 """
329 global USERS
330 LOG.info("Creating users")
331 admin = keystone_admin()
332 for u in users:
333 try:
334 tenant = admin.identity.get_tenant_by_name(u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900335 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400336 LOG.error("Tenant: %s - not found" % u['tenant'])
337 continue
338 try:
339 admin.identity.get_user_by_username(tenant['id'], u['name'])
340 LOG.warn("User '%s' already exists in this environment"
341 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900342 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400343 admin.identity.create_user(
344 u['name'], u['pass'], tenant['id'],
345 "%s@%s" % (u['name'], tenant['id']),
346 enabled=True)
347
348
Emilien Macchibb71e072014-07-05 19:18:52 +0200349def destroy_users(users):
350 admin = keystone_admin()
351 for user in users:
Emilien Macchi436de862014-09-30 17:09:50 -0400352 tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
353 user_id = admin.identity.get_user_by_username(tenant_id,
354 user['name'])['id']
David Kranzb7afa922014-12-30 10:56:26 -0500355 admin.identity.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200356
357
Sean Dague655e0af2014-05-29 09:00:22 -0400358def collect_users(users):
359 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200360 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400361 admin = keystone_admin()
362 for u in users:
363 tenant = admin.identity.get_tenant_by_name(u['tenant'])
364 u['tenant_id'] = tenant['id']
365 USERS[u['name']] = u
366 body = admin.identity.get_user_by_username(tenant['id'], u['name'])
367 USERS[u['name']]['id'] = body['id']
368
369
370class JavelinCheck(unittest.TestCase):
371 def __init__(self, users, resources):
372 super(JavelinCheck, self).__init__()
373 self.users = users
374 self.res = resources
375
376 def runTest(self, *args):
377 pass
378
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200379 def _ping_ip(self, ip_addr, count, namespace=None):
380 if namespace is None:
381 ping_cmd = "ping -c1 " + ip_addr
382 else:
383 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
384 ip_addr)
385 for current in range(count):
386 return_code = os.system(ping_cmd)
387 if return_code is 0:
388 break
389 self.assertNotEqual(current, count - 1,
390 "Server is not pingable at %s" % ip_addr)
391
Sean Dague655e0af2014-05-29 09:00:22 -0400392 def check(self):
393 self.check_users()
394 self.check_objects()
395 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400396 self.check_volumes()
Chris Dent878f3782014-06-30 17:04:15 +0100397 self.check_telemetry()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200398 self.check_secgroups()
399
400 # validate neutron is enabled and ironic disabled:
401 # Tenant network isolation is not supported when using ironic.
402 # "admin" has set up a neutron flat network environment within a shared
403 # fixed network for all tenants to use.
404 # In this case, network/subnet/router creation can be skipped and the
405 # server booted the same as nova network.
406 if (CONF.service_available.neutron and
407 not CONF.baremetal.driver_enabled):
408 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400409
410 def check_users(self):
411 """Check that the users we expect to exist, do.
412
413 We don't use the resource list for this because we need to validate
414 that things like tenantId didn't drift across versions.
415 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200416 LOG.info("checking users")
Sean Dague655e0af2014-05-29 09:00:22 -0400417 for name, user in self.users.iteritems():
418 client = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500419 found = client.identity.get_user(user['id'])
Sean Dague655e0af2014-05-29 09:00:22 -0400420 self.assertEqual(found['name'], user['name'])
421 self.assertEqual(found['tenantId'], user['tenant_id'])
422
423 # also ensure we can auth with that user, and do something
424 # on the cloud. We don't care about the results except that it
425 # remains authorized.
426 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500427 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400428
429 def check_objects(self):
430 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000431 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000432 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200433 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400434 for obj in self.res['objects']:
435 client = client_for_user(obj['owner'])
436 r, contents = client.objects.get_object(
437 obj['container'], obj['name'])
438 source = _file_contents(obj['file'])
439 self.assertEqual(contents, source)
440
441 def check_servers(self):
442 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000443 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000444 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200445 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400446 for server in self.res['servers']:
447 client = client_for_user(server['owner'])
448 found = _get_server_by_name(client, server['name'])
449 self.assertIsNotNone(
450 found,
451 "Couldn't find expected server %s" % server['name'])
452
David Kranz0fb14292015-02-11 15:55:20 -0500453 found = client.servers.get_server(found['id'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200454 # validate neutron is enabled and ironic disabled:
455 if (CONF.service_available.neutron and
456 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400457 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200458 for network_name, body in found['addresses'].items():
459 for addr in body:
460 ip = addr['addr']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400461 # If floatingip_for_ssh is at True, it's assumed
462 # you want to use the floating IP to reach the server,
463 # fallback to fixed IP, then other type.
464 # This is useful in multi-node environment.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700465 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400466 if addr.get('OS-EXT-IPS:type',
467 'floating') == 'floating':
468 self._ping_ip(ip, 60)
469 _floating_is_alive = True
470 elif addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200471 namespace = _get_router_namespace(client,
472 network_name)
473 self._ping_ip(ip, 60, namespace)
474 else:
475 self._ping_ip(ip, 60)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400476 # if floatingip_for_ssh is at True, validate found a
477 # floating IP and ping worked.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700478 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400479 self.assertTrue(_floating_is_alive,
480 "Server %s has no floating IP." %
481 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200482 else:
483 addr = found['addresses']['private'][0]['addr']
484 self._ping_ip(addr, 60)
485
486 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100487 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200488 LOG.info("Checking security groups")
489 for secgroup in self.res['secgroups']:
490 client = client_for_user(secgroup['owner'])
491 found = _get_resource_by_name(client.secgroups, 'security_groups',
492 secgroup['name'])
493 self.assertIsNotNone(
494 found,
495 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400496
Chris Dent878f3782014-06-30 17:04:15 +0100497 def check_telemetry(self):
498 """Check that ceilometer provides a sane sample.
499
500 Confirm that there are more than one sample and that they have the
501 expected metadata.
502
503 If in check mode confirm that the oldest sample available is from
504 before the upgrade.
505 """
Chris Dent0b76f2f2014-10-10 14:24:28 +0100506 if not self.res.get('telemetry'):
507 return
Chris Dent878f3782014-06-30 17:04:15 +0100508 LOG.info("checking telemetry")
509 for server in self.res['servers']:
510 client = client_for_user(server['owner'])
David Kranz20d06f42015-02-09 14:54:15 -0500511 body = client.telemetry.list_samples(
Chris Dent878f3782014-06-30 17:04:15 +0100512 'instance',
513 query=('metadata.display_name', 'eq', server['name'])
514 )
Chris Dent878f3782014-06-30 17:04:15 +0100515 self.assertTrue(len(body) >= 1, 'expecting at least one sample')
516 self._confirm_telemetry_sample(server, body[-1])
517
Emilien Macchi626b4f82014-06-15 21:44:29 +0200518 def check_volumes(self):
519 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000520 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000521 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200522 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200523 for volume in self.res['volumes']:
524 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400525 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200526 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400527 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200528 "Couldn't find expected volume %s" % volume['name'])
529
530 # Verify that a volume's attachment retrieved
531 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400532 attachment = client.volumes.get_attachment_from_volume(vol_body)
533 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200534 self.assertEqual(server_id, attachment['server_id'])
535
Chris Dent878f3782014-06-30 17:04:15 +0100536 def _confirm_telemetry_sample(self, server, sample):
537 """Check this sample matches the expected resource metadata."""
538 # Confirm display_name
539 self.assertEqual(server['name'],
540 sample['resource_metadata']['display_name'])
541 # Confirm instance_type of flavor
542 flavor = sample['resource_metadata'].get(
543 'flavor.name',
544 sample['resource_metadata'].get('instance_type')
545 )
546 self.assertEqual(server['flavor'], flavor)
547 # Confirm the oldest sample was created before upgrade.
548 if OPTS.mode == 'check':
549 oldest_timestamp = timeutils.normalize_time(
550 timeutils.parse_isotime(sample['timestamp']))
551 self.assertTrue(
552 oldest_timestamp < JAVELIN_START,
553 'timestamp should come before start of second javelin run'
554 )
555
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200556 def check_networking(self):
557 """Check that the networks are still there."""
558 for res_type in ('networks', 'subnets', 'routers'):
559 for res in self.res[res_type]:
560 client = client_for_user(res['owner'])
561 found = _get_resource_by_name(client.networks, res_type,
562 res['name'])
563 self.assertIsNotNone(
564 found,
565 "Couldn't find expected resource %s" % res['name'])
566
Sean Dague655e0af2014-05-29 09:00:22 -0400567
568#######################
569#
570# OBJECTS
571#
572#######################
573
574
575def _file_contents(fname):
576 with open(fname, 'r') as f:
577 return f.read()
578
579
580def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000581 if not objects:
582 return
Sean Dague655e0af2014-05-29 09:00:22 -0400583 LOG.info("Creating objects")
584 for obj in objects:
585 LOG.debug("Object %s" % obj)
586 _assign_swift_role(obj['owner'])
587 client = client_for_user(obj['owner'])
588 client.containers.create_container(obj['container'])
589 client.objects.create_object(
590 obj['container'], obj['name'],
591 _file_contents(obj['file']))
592
Emilien Macchibb71e072014-07-05 19:18:52 +0200593
594def destroy_objects(objects):
595 for obj in objects:
596 client = client_for_user(obj['owner'])
597 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400598 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200599 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
600
601
Sean Dague655e0af2014-05-29 09:00:22 -0400602#######################
603#
604# IMAGES
605#
606#######################
607
608
Sean Dague319b37a2014-07-11 07:28:11 -0400609def _resolve_image(image, imgtype):
610 name = image[imgtype]
611 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
612 return name, fname
613
614
Joe Gordon6f0426c2014-07-25 01:10:28 +0000615def _get_image_by_name(client, name):
David Kranz34f18782015-01-06 13:43:55 -0500616 body = client.images.image_list()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000617 for image in body:
618 if name == image['name']:
619 return image
620 return None
621
622
Sean Dague655e0af2014-05-29 09:00:22 -0400623def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000624 if not images:
625 return
Joe Gordona18d6862014-07-24 22:55:46 +0000626 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400627 for image in images:
628 client = client_for_user(image['owner'])
629
630 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000631 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000632 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400633 continue
634
635 # special handling for 3 part image
636 extras = {}
637 if image['format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400638 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500639 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400640 'javelin_' + name, 'aki', 'aki')
641 client.images.store_image(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400642 extras['kernel_id'] = aki.get('id')
643
Sean Dague319b37a2014-07-11 07:28:11 -0400644 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500645 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400646 'javelin_' + name, 'ari', 'ari')
647 client.images.store_image(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400648 extras['ramdisk_id'] = ari.get('id')
649
Sean Dague319b37a2014-07-11 07:28:11 -0400650 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500651 body = client.images.create_image(
Sean Dague655e0af2014-05-29 09:00:22 -0400652 image['name'], image['format'], image['format'], **extras)
653 image_id = body.get('id')
Sean Dague319b37a2014-07-11 07:28:11 -0400654 client.images.store_image(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400655
656
Joe Gordon6f0426c2014-07-25 01:10:28 +0000657def destroy_images(images):
658 if not images:
659 return
660 LOG.info("Destroying images")
661 for image in images:
662 client = client_for_user(image['owner'])
663
664 response = _get_image_by_name(client, image['name'])
665 if not response:
666 LOG.info("Image '%s' does not exists" % image['name'])
667 continue
668 client.images.delete_image(response['id'])
669
670
Sean Dague655e0af2014-05-29 09:00:22 -0400671#######################
672#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200673# NETWORKS
674#
675#######################
676
677def _get_router_namespace(client, network):
678 network_id = _get_resource_by_name(client.networks,
679 'networks', network)['id']
David Kranz34e88122014-12-11 15:24:05 -0500680 n_body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200681 for router in n_body['routers']:
682 router_id = router['id']
David Kranz34e88122014-12-11 15:24:05 -0500683 r_body = client.networks.list_router_interfaces(router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200684 for port in r_body['ports']:
685 if port['network_id'] == network_id:
686 return "qrouter-%s" % router_id
687
688
689def _get_resource_by_name(client, resource, name):
690 get_resources = getattr(client, 'list_%s' % resource)
691 if get_resources is None:
692 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500693 # Until all tempest client methods are changed to return only one value,
694 # we cannot assume they all have the same signature so we need to discard
695 # the unused response first value it two values are being returned.
696 body = get_resources()
697 if type(body) == tuple:
698 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200699 if isinstance(body, dict):
700 body = body[resource]
701 for res in body:
702 if name == res['name']:
703 return res
704 raise ValueError('%s not found in %s resources' % (name, resource))
705
706
707def create_networks(networks):
708 LOG.info("Creating networks")
709 for network in networks:
710 client = client_for_user(network['owner'])
711
712 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500713 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200714 if any(item['name'] == network['name'] for item in body['networks']):
715 LOG.warning("Dupplicated network name: %s" % network['name'])
716 continue
717
718 client.networks.create_network(name=network['name'])
719
720
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100721def destroy_networks(networks):
722 LOG.info("Destroying subnets")
723 for network in networks:
724 client = client_for_user(network['owner'])
725 network_id = _get_resource_by_name(client.networks, 'networks',
726 network['name'])['id']
727 client.networks.delete_network(network_id)
728
729
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200730def create_subnets(subnets):
731 LOG.info("Creating subnets")
732 for subnet in subnets:
733 client = client_for_user(subnet['owner'])
734
735 network = _get_resource_by_name(client.networks, 'networks',
736 subnet['network'])
737 ip_version = netaddr.IPNetwork(subnet['range']).version
738 # ensure we don't overlap with another subnet in the network
739 try:
740 client.networks.create_subnet(network_id=network['id'],
741 cidr=subnet['range'],
742 name=subnet['name'],
743 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900744 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200745 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
746 if not is_overlapping_cidr:
747 raise
748
749
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100750def destroy_subnets(subnets):
751 LOG.info("Destroying subnets")
752 for subnet in subnets:
753 client = client_for_user(subnet['owner'])
754 subnet_id = _get_resource_by_name(client.networks,
755 'subnets', subnet['name'])['id']
756 client.networks.delete_subnet(subnet_id)
757
758
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200759def create_routers(routers):
760 LOG.info("Creating routers")
761 for router in routers:
762 client = client_for_user(router['owner'])
763
764 # only create a router if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500765 body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200766 if any(item['name'] == router['name'] for item in body['routers']):
767 LOG.warning("Dupplicated router name: %s" % router['name'])
768 continue
769
770 client.networks.create_router(router['name'])
771
772
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100773def destroy_routers(routers):
774 LOG.info("Destroying routers")
775 for router in routers:
776 client = client_for_user(router['owner'])
777 router_id = _get_resource_by_name(client.networks,
778 'routers', router['name'])['id']
779 for subnet in router['subnet']:
780 subnet_id = _get_resource_by_name(client.networks,
781 'subnets', subnet)['id']
782 client.networks.remove_router_interface_with_subnet_id(router_id,
783 subnet_id)
784 client.networks.delete_router(router_id)
785
786
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200787def add_router_interface(routers):
788 for router in routers:
789 client = client_for_user(router['owner'])
790 router_id = _get_resource_by_name(client.networks,
791 'routers', router['name'])['id']
792
793 for subnet in router['subnet']:
794 subnet_id = _get_resource_by_name(client.networks,
795 'subnets', subnet)['id']
796 # connect routers to their subnets
797 client.networks.add_router_interface_with_subnet_id(router_id,
798 subnet_id)
799 # connect routers to exteral network if set to "gateway"
800 if router['gateway']:
801 if CONF.network.public_network_id:
802 ext_net = CONF.network.public_network_id
803 client.networks._update_router(
804 router_id, set_enable_snat=True,
805 external_gateway_info={"network_id": ext_net})
806 else:
807 raise ValueError('public_network_id is not configured.')
808
809
810#######################
811#
Sean Dague655e0af2014-05-29 09:00:22 -0400812# SERVERS
813#
814#######################
815
816def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500817 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400818 for server in body['servers']:
819 if name == server['name']:
820 return server
821 return None
822
823
Sean Dague655e0af2014-05-29 09:00:22 -0400824def _get_flavor_by_name(client, name):
David Kranz2fa77b22015-02-09 11:39:50 -0500825 body = client.flavors.list_flavors()
Sean Dague655e0af2014-05-29 09:00:22 -0400826 for flavor in body:
827 if name == flavor['name']:
828 return flavor
829 return None
830
831
832def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000833 if not servers:
834 return
Joe Gordona18d6862014-07-24 22:55:46 +0000835 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400836 for server in servers:
837 client = client_for_user(server['owner'])
838
839 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000840 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400841 continue
842
843 image_id = _get_image_by_name(client, server['image'])['id']
844 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200845 # validate neutron is enabled and ironic disabled
846 kwargs = dict()
847 if (CONF.service_available.neutron and
848 not CONF.baremetal.driver_enabled and server.get('networks')):
849 get_net_id = lambda x: (_get_resource_by_name(
850 client.networks, 'networks', x)['id'])
851 kwargs['networks'] = [{'uuid': get_net_id(network)}
852 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500853 body = client.servers.create_server(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200854 server['name'], image_id, flavor_id, **kwargs)
Joe Gordon10f260b2014-07-24 23:27:19 +0000855 server_id = body['id']
856 client.servers.wait_for_server_status(server_id, 'ACTIVE')
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200857 # create to security group(s) after server spawning
858 for secgroup in server['secgroups']:
859 client.servers.add_security_group(server_id, secgroup)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400860 if CONF.compute.use_floatingip_for_ssh:
861 floating_ip = client.floating_ips.create_floating_ip()
862 client.floating_ips.associate_floating_ip_to_server(
863 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400864
865
Joe Gordondb63b1c2014-07-24 23:21:21 +0000866def destroy_servers(servers):
867 if not servers:
868 return
869 LOG.info("Destroying servers")
870 for server in servers:
871 client = client_for_user(server['owner'])
872
Emilien Macchidc5bae22015-03-16 08:49:02 -0400873 response = _get_server_by_name(client, server['name'])
874 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000875 LOG.info("Server '%s' does not exist" % server['name'])
876 continue
877
Emilien Macchidc5bae22015-03-16 08:49:02 -0400878 # TODO(EmilienM): disassociate floating IP from server and release it.
879 client.servers.delete_server(response['id'])
880 client.servers.wait_for_server_termination(response['id'],
Matthew Treinish1d14c542014-06-17 20:25:40 -0400881 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000882
883
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200884def create_secgroups(secgroups):
885 LOG.info("Creating security groups")
886 for secgroup in secgroups:
887 client = client_for_user(secgroup['owner'])
888
889 # only create a security group if the name isn't here
890 # i.e. a security group may be used by another server
891 # only create a router if the name isn't here
David Kranz9964b4e2015-02-06 15:45:29 -0500892 body = client.secgroups.list_security_groups()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200893 if any(item['name'] == secgroup['name'] for item in body):
894 LOG.warning("Security group '%s' already exists" %
895 secgroup['name'])
896 continue
897
David Kranz9964b4e2015-02-06 15:45:29 -0500898 body = client.secgroups.create_security_group(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200899 secgroup['name'], secgroup['description'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200900 secgroup_id = body['id']
901 # for each security group, create the rules
902 for rule in secgroup['rules']:
903 ip_proto, from_port, to_port, cidr = rule.split()
904 client.secgroups.create_security_group_rule(
905 secgroup_id, ip_proto, from_port, to_port, cidr=cidr)
906
907
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100908def destroy_secgroups(secgroups):
909 LOG.info("Destroying security groups")
910 for secgroup in secgroups:
911 client = client_for_user(secgroup['owner'])
912 sg_id = _get_resource_by_name(client.secgroups,
913 'security_groups',
914 secgroup['name'])
915 # sg rules are deleted automatically
916 client.secgroups.delete_security_group(sg_id['id'])
917
918
Sean Dague655e0af2014-05-29 09:00:22 -0400919#######################
920#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200921# VOLUMES
922#
923#######################
924
925def _get_volume_by_name(client, name):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000926 body = client.volumes.list_volumes()
Emilien Macchid18fec12014-09-15 14:32:54 -0400927 for volume in body:
928 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200929 return volume
930 return None
931
932
933def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100934 if not volumes:
935 return
936 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200937 for volume in volumes:
938 client = client_for_user(volume['owner'])
939
940 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400941 if _get_volume_by_name(client, volume['name']):
942 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200943 continue
944
Emilien Macchid18fec12014-09-15 14:32:54 -0400945 size = volume['gb']
946 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000947 body = client.volumes.create_volume(size=size,
948 display_name=v_name)
Emilien Macchid18fec12014-09-15 14:32:54 -0400949 client.volumes.wait_for_volume_status(body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200950
951
Emilien Macchibb71e072014-07-05 19:18:52 +0200952def destroy_volumes(volumes):
953 for volume in volumes:
954 client = client_for_user(volume['owner'])
955 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400956 client.volumes.detach_volume(volume_id)
957 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200958
959
Emilien Macchi626b4f82014-06-15 21:44:29 +0200960def attach_volumes(volumes):
961 for volume in volumes:
962 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200963 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400964 volume_id = _get_volume_by_name(client, volume['name'])['id']
965 device = volume['device']
966 client.volumes.attach_volume(volume_id, server_id, device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200967
968
969#######################
970#
Sean Dague655e0af2014-05-29 09:00:22 -0400971# MAIN LOGIC
972#
973#######################
974
975def create_resources():
976 LOG.info("Creating Resources")
977 # first create keystone level resources, and we need to be admin
978 # for those.
979 create_tenants(RES['tenants'])
980 create_users(RES['users'])
981 collect_users(RES['users'])
982
983 # next create resources in a well known order
984 create_objects(RES['objects'])
985 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200986
987 # validate neutron is enabled and ironic is disabled
988 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
989 create_networks(RES['networks'])
990 create_subnets(RES['subnets'])
991 create_routers(RES['routers'])
992 add_router_interface(RES['routers'])
993
994 create_secgroups(RES['secgroups'])
Sean Dague655e0af2014-05-29 09:00:22 -0400995 create_servers(RES['servers'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400996 create_volumes(RES['volumes'])
997 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -0400998
999
Joe Gordondb63b1c2014-07-24 23:21:21 +00001000def destroy_resources():
1001 LOG.info("Destroying Resources")
1002 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001003 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001004 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001005 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001006 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001007 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1008 destroy_routers(RES['routers'])
1009 destroy_subnets(RES['subnets'])
1010 destroy_networks(RES['networks'])
1011 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001012 destroy_users(RES['users'])
1013 destroy_tenants(RES['tenants'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001014 LOG.warn("Destroy mode incomplete")
1015
Joe Gordondb63b1c2014-07-24 23:21:21 +00001016
Sean Dague655e0af2014-05-29 09:00:22 -04001017def get_options():
1018 global OPTS
1019 parser = argparse.ArgumentParser(
1020 description='Create and validate a fixed set of OpenStack resources')
1021 parser.add_argument('-m', '--mode',
1022 metavar='<create|check|destroy>',
1023 required=True,
1024 help=('One of (create, check, destroy)'))
1025 parser.add_argument('-r', '--resources',
1026 required=True,
1027 metavar='resourcefile.yaml',
1028 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001029
Sean Dague319b37a2014-07-11 07:28:11 -04001030 parser.add_argument(
1031 '-d', '--devstack-base',
1032 required=True,
1033 metavar='/opt/stack/old',
1034 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001035 parser.add_argument(
1036 '-c', '--config-file',
1037 metavar='/etc/tempest.conf',
1038 help='path to javelin2(tempest) config file')
1039
Sean Dague655e0af2014-05-29 09:00:22 -04001040 # auth bits, letting us also just source the devstack openrc
1041 parser.add_argument('--os-username',
1042 metavar='<auth-user-name>',
1043 default=os.environ.get('OS_USERNAME'),
1044 help=('Defaults to env[OS_USERNAME].'))
1045 parser.add_argument('--os-password',
1046 metavar='<auth-password>',
1047 default=os.environ.get('OS_PASSWORD'),
1048 help=('Defaults to env[OS_PASSWORD].'))
1049 parser.add_argument('--os-tenant-name',
1050 metavar='<auth-tenant-name>',
1051 default=os.environ.get('OS_TENANT_NAME'),
1052 help=('Defaults to env[OS_TENANT_NAME].'))
1053
1054 OPTS = parser.parse_args()
1055 if OPTS.mode not in ('create', 'check', 'destroy'):
1056 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1057 parser.print_help()
1058 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001059 if OPTS.config_file:
1060 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001061
1062
Joe Gordon915eb8e2014-07-17 11:25:46 +02001063def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001064 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001065 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001066 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001067
1068
1069def main():
1070 global RES
1071 get_options()
1072 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001073 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001074
1075 if OPTS.mode == 'create':
1076 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001077 # Make sure the resources we just created actually work
1078 checker = JavelinCheck(USERS, RES)
1079 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001080 elif OPTS.mode == 'check':
1081 collect_users(RES['users'])
1082 checker = JavelinCheck(USERS, RES)
1083 checker.check()
1084 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001085 collect_users(RES['users'])
1086 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001087 else:
1088 LOG.error('Unknown mode %s' % OPTS.mode)
1089 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001090 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001091 return 0
1092
1093if __name__ == "__main__":
1094 sys.exit(main())