blob: d3426c65698a496638a2e0f262641a10c17bc0cf [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
Joe H. Rahme4352d5d2015-03-09 17:41:18 +010080 disk_format: ami
81 container_format: ami
Joe H. Rahme61469fd2014-12-02 17:09:17 +010082 aki: cirros-0.3.2-x86_64-vmlinuz
83 ari: cirros-0.3.2-x86_64-initrd
84
85 servers:
86 - name: peltast
87 owner: javelin
88 flavor: m1.small
89 image: javelin_cirros
Joe H. Rahme9350a102015-03-29 17:39:20 +020090 floating_ip_pool: public
Joe H. Rahme61469fd2014-12-02 17:09:17 +010091 - name: hoplite
92 owner: javelin
93 flavor: m1.medium
94 image: javelin_cirros
95
96
97An important piece of the resource definition is the *owner* field, which is
98the user (that we've created) that is the owner of that resource. All
99operations on that resource will happen as that regular user to ensure that
100admin level access does not mask issues.
101
102The check phase will act like a unit test, using well known assert methods to
103verify that the correct resources exist.
104
Sean Dague655e0af2014-05-29 09:00:22 -0400105"""
106
Matthew Treinish96e9e882014-06-09 18:37:19 -0400107import argparse
Chris Dent51e76de2014-10-01 12:07:14 +0100108import collections
Chris Dent878f3782014-06-30 17:04:15 +0100109import datetime
Sean Dague655e0af2014-05-29 09:00:22 -0400110import os
111import sys
112import unittest
Sean Dague655e0af2014-05-29 09:00:22 -0400113
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200114import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +0000115from oslo_log import log as logging
116from oslo_utils import timeutils
Matthew Treinish71426682015-04-23 11:19:38 -0400117import six
andreafb8a52282015-03-19 22:21:54 +0000118from tempest_lib import auth
Masayuki Igawad9388762015-01-20 14:56:42 +0900119from tempest_lib import exceptions as lib_exc
Matthew Treinish96e9e882014-06-09 18:37:19 -0400120import yaml
Sean Dague655e0af2014-05-29 09:00:22 -0400121
Joe Gordon28a84ae2014-07-17 15:38:28 +0000122from tempest import config
Sean Dague655e0af2014-05-29 09:00:22 -0400123from tempest.services.compute.json import flavors_client
Emilien Macchic3e3e292015-03-11 17:42:08 -0400124from tempest.services.compute.json import floating_ips_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200125from tempest.services.compute.json import security_groups_client
Sean Dague655e0af2014-05-29 09:00:22 -0400126from tempest.services.compute.json import servers_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100127from tempest.services.identity.v2.json import identity_client
Sean Dague655e0af2014-05-29 09:00:22 -0400128from tempest.services.image.v2.json import image_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200129from tempest.services.network.json import network_client
Sean Dague655e0af2014-05-29 09:00:22 -0400130from tempest.services.object_storage import container_client
131from tempest.services.object_storage import object_client
Chris Dent878f3782014-06-30 17:04:15 +0100132from tempest.services.telemetry.json import telemetry_client
Emilien Macchi626b4f82014-06-15 21:44:29 +0200133from tempest.services.volume.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400134
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200135CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400136OPTS = {}
137USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100138RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400139
140LOG = None
141
Chris Dent878f3782014-06-30 17:04:15 +0100142JAVELIN_START = datetime.datetime.utcnow()
143
Sean Dague655e0af2014-05-29 09:00:22 -0400144
145class OSClient(object):
146 _creds = None
147 identity = None
148 servers = None
149
150 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000151 default_params = {
152 'disable_ssl_certificate_validation':
153 CONF.identity.disable_ssl_certificate_validation,
154 'ca_certs': CONF.identity.ca_certificates_file,
155 'trace_requests': CONF.debug.trace_requests
156 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000157 default_params_with_timeout_values = {
158 'build_interval': CONF.compute.build_interval,
159 'build_timeout': CONF.compute.build_timeout
160 }
161 default_params_with_timeout_values.update(default_params)
162
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000163 compute_params = {
164 'service': CONF.compute.catalog_type,
165 'region': CONF.compute.region or CONF.identity.region,
166 'endpoint_type': CONF.compute.endpoint_type,
167 'build_interval': CONF.compute.build_interval,
168 'build_timeout': CONF.compute.build_timeout
169 }
170 compute_params.update(default_params)
171
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000172 object_storage_params = {
173 'service': CONF.object_storage.catalog_type,
174 'region': CONF.object_storage.region or CONF.identity.region,
175 'endpoint_type': CONF.object_storage.endpoint_type
176 }
177 object_storage_params.update(default_params)
178
andreafb8a52282015-03-19 22:21:54 +0000179 _creds = auth.KeystoneV2Credentials(
Sean Dague655e0af2014-05-29 09:00:22 -0400180 username=user,
181 password=pw,
182 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000183 auth_provider_params = {
184 'disable_ssl_certificate_validation':
185 CONF.identity.disable_ssl_certificate_validation,
186 'ca_certs': CONF.identity.ca_certificates_file,
187 'trace_requests': CONF.debug.trace_requests
188 }
andreafb8a52282015-03-19 22:21:54 +0000189 _auth = auth.KeystoneV2AuthProvider(
Andrea Frittoli90012352015-02-25 21:58:02 +0000190 _creds, CONF.identity.uri, **auth_provider_params)
ghanshyamd26b5cd2015-02-09 14:48:58 +0900191 self.identity = identity_client.IdentityClientJSON(
192 _auth,
193 CONF.identity.catalog_type,
194 CONF.identity.region,
195 endpoint_type='adminURL',
196 **default_params_with_timeout_values)
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000197 self.servers = servers_client.ServersClientJSON(_auth,
198 **compute_params)
199 self.flavors = flavors_client.FlavorsClientJSON(_auth,
200 **compute_params)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400201 self.floating_ips = floating_ips_client.FloatingIPsClientJSON(
202 _auth, **compute_params)
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000203 self.secgroups = security_groups_client.SecurityGroupsClientJSON(
204 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000205 self.objects = object_client.ObjectClient(_auth,
206 **object_storage_params)
207 self.containers = container_client.ContainerClient(
208 _auth, **object_storage_params)
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900209 self.images = image_client.ImageClientV2JSON(
210 _auth,
211 CONF.image.catalog_type,
212 CONF.image.region or CONF.identity.region,
213 endpoint_type=CONF.image.endpoint_type,
214 build_interval=CONF.image.build_interval,
215 build_timeout=CONF.image.build_timeout,
216 **default_params)
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000217 self.telemetry = telemetry_client.TelemetryClientJSON(
218 _auth,
219 CONF.telemetry.catalog_type,
220 CONF.identity.region,
221 endpoint_type=CONF.telemetry.endpoint_type,
222 **default_params_with_timeout_values)
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000223 self.volumes = volumes_client.VolumesClientJSON(
224 _auth,
225 CONF.volume.catalog_type,
226 CONF.volume.region or CONF.identity.region,
227 endpoint_type=CONF.volume.endpoint_type,
228 build_interval=CONF.volume.build_interval,
229 build_timeout=CONF.volume.build_timeout,
230 **default_params)
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000231 self.networks = network_client.NetworkClientJSON(
232 _auth,
233 CONF.network.catalog_type,
234 CONF.network.region or CONF.identity.region,
235 endpoint_type=CONF.network.endpoint_type,
236 build_interval=CONF.network.build_interval,
237 build_timeout=CONF.network.build_timeout,
238 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400239
240
241def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100242 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400243 return yaml.load(open(fname, 'r'))
244
245
246def keystone_admin():
247 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
248
249
250def client_for_user(name):
251 LOG.debug("Entering client_for_user")
252 if name in USERS:
253 user = USERS[name]
254 LOG.debug("Created client for user %s" % user)
255 return OSClient(user['name'], user['pass'], user['tenant'])
256 else:
257 LOG.error("%s not found in USERS: %s" % (name, USERS))
258
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200259
Sean Dague655e0af2014-05-29 09:00:22 -0400260###################
261#
262# TENANTS
263#
264###################
265
266
267def create_tenants(tenants):
268 """Create tenants from resource definition.
269
270 Don't create the tenants if they already exist.
271 """
272 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500273 body = admin.identity.list_tenants()
Sean Dague655e0af2014-05-29 09:00:22 -0400274 existing = [x['name'] for x in body]
275 for tenant in tenants:
276 if tenant not in existing:
277 admin.identity.create_tenant(tenant)
278 else:
279 LOG.warn("Tenant '%s' already exists in this environment" % tenant)
280
Emilien Macchibb71e072014-07-05 19:18:52 +0200281
282def destroy_tenants(tenants):
283 admin = keystone_admin()
284 for tenant in tenants:
285 tenant_id = admin.identity.get_tenant_by_name(tenant)['id']
David Kranzb7afa922014-12-30 10:56:26 -0500286 admin.identity.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200287
Sean Dague655e0af2014-05-29 09:00:22 -0400288##############
289#
290# USERS
291#
292##############
293
294
295def _users_for_tenant(users, tenant):
296 u_for_t = []
297 for user in users:
298 for n in user:
299 if user[n]['tenant'] == tenant:
300 u_for_t.append(user[n])
301 return u_for_t
302
303
304def _tenants_from_users(users):
305 tenants = set()
306 for user in users:
307 for n in user:
308 tenants.add(user[n]['tenant'])
309 return tenants
310
311
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200312def _assign_swift_role(user, swift_role):
Sean Dague655e0af2014-05-29 09:00:22 -0400313 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500314 roles = admin.identity.list_roles()
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200315 role = next(r for r in roles if r['name'] == swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400316 LOG.debug(USERS[user])
317 try:
318 admin.identity.assign_user_role(
319 USERS[user]['tenant_id'],
320 USERS[user]['id'],
321 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900322 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400323 # don't care if it's already assigned
324 pass
325
326
327def create_users(users):
328 """Create tenants from resource definition.
329
330 Don't create the tenants if they already exist.
331 """
332 global USERS
333 LOG.info("Creating users")
334 admin = keystone_admin()
335 for u in users:
336 try:
337 tenant = admin.identity.get_tenant_by_name(u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900338 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400339 LOG.error("Tenant: %s - not found" % u['tenant'])
340 continue
341 try:
342 admin.identity.get_user_by_username(tenant['id'], u['name'])
343 LOG.warn("User '%s' already exists in this environment"
344 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900345 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400346 admin.identity.create_user(
347 u['name'], u['pass'], tenant['id'],
348 "%s@%s" % (u['name'], tenant['id']),
349 enabled=True)
350
351
Emilien Macchibb71e072014-07-05 19:18:52 +0200352def destroy_users(users):
353 admin = keystone_admin()
354 for user in users:
Emilien Macchi436de862014-09-30 17:09:50 -0400355 tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
356 user_id = admin.identity.get_user_by_username(tenant_id,
357 user['name'])['id']
David Kranzb7afa922014-12-30 10:56:26 -0500358 admin.identity.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200359
360
Sean Dague655e0af2014-05-29 09:00:22 -0400361def collect_users(users):
362 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200363 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400364 admin = keystone_admin()
365 for u in users:
366 tenant = admin.identity.get_tenant_by_name(u['tenant'])
367 u['tenant_id'] = tenant['id']
368 USERS[u['name']] = u
369 body = admin.identity.get_user_by_username(tenant['id'], u['name'])
370 USERS[u['name']]['id'] = body['id']
371
372
373class JavelinCheck(unittest.TestCase):
374 def __init__(self, users, resources):
375 super(JavelinCheck, self).__init__()
376 self.users = users
377 self.res = resources
378
379 def runTest(self, *args):
380 pass
381
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200382 def _ping_ip(self, ip_addr, count, namespace=None):
383 if namespace is None:
384 ping_cmd = "ping -c1 " + ip_addr
385 else:
386 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
387 ip_addr)
388 for current in range(count):
389 return_code = os.system(ping_cmd)
390 if return_code is 0:
391 break
392 self.assertNotEqual(current, count - 1,
393 "Server is not pingable at %s" % ip_addr)
394
Sean Dague655e0af2014-05-29 09:00:22 -0400395 def check(self):
396 self.check_users()
397 self.check_objects()
398 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400399 self.check_volumes()
Chris Dent878f3782014-06-30 17:04:15 +0100400 self.check_telemetry()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200401 self.check_secgroups()
402
403 # validate neutron is enabled and ironic disabled:
404 # Tenant network isolation is not supported when using ironic.
405 # "admin" has set up a neutron flat network environment within a shared
406 # fixed network for all tenants to use.
407 # In this case, network/subnet/router creation can be skipped and the
408 # server booted the same as nova network.
409 if (CONF.service_available.neutron and
410 not CONF.baremetal.driver_enabled):
411 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400412
413 def check_users(self):
414 """Check that the users we expect to exist, do.
415
416 We don't use the resource list for this because we need to validate
417 that things like tenantId didn't drift across versions.
418 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200419 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400420 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400421 client = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500422 found = client.identity.get_user(user['id'])
Sean Dague655e0af2014-05-29 09:00:22 -0400423 self.assertEqual(found['name'], user['name'])
424 self.assertEqual(found['tenantId'], user['tenant_id'])
425
426 # also ensure we can auth with that user, and do something
427 # on the cloud. We don't care about the results except that it
428 # remains authorized.
429 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500430 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400431
432 def check_objects(self):
433 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000434 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000435 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200436 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400437 for obj in self.res['objects']:
438 client = client_for_user(obj['owner'])
439 r, contents = client.objects.get_object(
440 obj['container'], obj['name'])
441 source = _file_contents(obj['file'])
442 self.assertEqual(contents, source)
443
444 def check_servers(self):
445 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000446 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000447 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200448 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400449 for server in self.res['servers']:
450 client = client_for_user(server['owner'])
451 found = _get_server_by_name(client, server['name'])
452 self.assertIsNotNone(
453 found,
454 "Couldn't find expected server %s" % server['name'])
455
David Kranz0fb14292015-02-11 15:55:20 -0500456 found = client.servers.get_server(found['id'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200457 # validate neutron is enabled and ironic disabled:
458 if (CONF.service_available.neutron and
459 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400460 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200461 for network_name, body in found['addresses'].items():
462 for addr in body:
463 ip = addr['addr']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400464 # If floatingip_for_ssh is at True, it's assumed
465 # you want to use the floating IP to reach the server,
466 # fallback to fixed IP, then other type.
467 # This is useful in multi-node environment.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700468 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400469 if addr.get('OS-EXT-IPS:type',
470 'floating') == 'floating':
471 self._ping_ip(ip, 60)
472 _floating_is_alive = True
473 elif addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200474 namespace = _get_router_namespace(client,
475 network_name)
476 self._ping_ip(ip, 60, namespace)
477 else:
478 self._ping_ip(ip, 60)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400479 # if floatingip_for_ssh is at True, validate found a
480 # floating IP and ping worked.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700481 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400482 self.assertTrue(_floating_is_alive,
483 "Server %s has no floating IP." %
484 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200485 else:
486 addr = found['addresses']['private'][0]['addr']
487 self._ping_ip(addr, 60)
488
489 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100490 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200491 LOG.info("Checking security groups")
492 for secgroup in self.res['secgroups']:
493 client = client_for_user(secgroup['owner'])
494 found = _get_resource_by_name(client.secgroups, 'security_groups',
495 secgroup['name'])
496 self.assertIsNotNone(
497 found,
498 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400499
Chris Dent878f3782014-06-30 17:04:15 +0100500 def check_telemetry(self):
501 """Check that ceilometer provides a sane sample.
502
503 Confirm that there are more than one sample and that they have the
504 expected metadata.
505
506 If in check mode confirm that the oldest sample available is from
507 before the upgrade.
508 """
Chris Dent0b76f2f2014-10-10 14:24:28 +0100509 if not self.res.get('telemetry'):
510 return
Chris Dent878f3782014-06-30 17:04:15 +0100511 LOG.info("checking telemetry")
512 for server in self.res['servers']:
513 client = client_for_user(server['owner'])
David Kranz20d06f42015-02-09 14:54:15 -0500514 body = client.telemetry.list_samples(
Chris Dent878f3782014-06-30 17:04:15 +0100515 'instance',
516 query=('metadata.display_name', 'eq', server['name'])
517 )
Chris Dent878f3782014-06-30 17:04:15 +0100518 self.assertTrue(len(body) >= 1, 'expecting at least one sample')
519 self._confirm_telemetry_sample(server, body[-1])
520
Emilien Macchi626b4f82014-06-15 21:44:29 +0200521 def check_volumes(self):
522 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000523 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000524 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200525 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200526 for volume in self.res['volumes']:
527 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400528 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200529 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400530 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200531 "Couldn't find expected volume %s" % volume['name'])
532
533 # Verify that a volume's attachment retrieved
534 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400535 attachment = client.volumes.get_attachment_from_volume(vol_body)
536 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200537 self.assertEqual(server_id, attachment['server_id'])
538
Chris Dent878f3782014-06-30 17:04:15 +0100539 def _confirm_telemetry_sample(self, server, sample):
540 """Check this sample matches the expected resource metadata."""
541 # Confirm display_name
542 self.assertEqual(server['name'],
543 sample['resource_metadata']['display_name'])
544 # Confirm instance_type of flavor
545 flavor = sample['resource_metadata'].get(
546 'flavor.name',
547 sample['resource_metadata'].get('instance_type')
548 )
549 self.assertEqual(server['flavor'], flavor)
550 # Confirm the oldest sample was created before upgrade.
551 if OPTS.mode == 'check':
552 oldest_timestamp = timeutils.normalize_time(
553 timeutils.parse_isotime(sample['timestamp']))
554 self.assertTrue(
555 oldest_timestamp < JAVELIN_START,
556 'timestamp should come before start of second javelin run'
557 )
558
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200559 def check_networking(self):
560 """Check that the networks are still there."""
561 for res_type in ('networks', 'subnets', 'routers'):
562 for res in self.res[res_type]:
563 client = client_for_user(res['owner'])
564 found = _get_resource_by_name(client.networks, res_type,
565 res['name'])
566 self.assertIsNotNone(
567 found,
568 "Couldn't find expected resource %s" % res['name'])
569
Sean Dague655e0af2014-05-29 09:00:22 -0400570
571#######################
572#
573# OBJECTS
574#
575#######################
576
577
578def _file_contents(fname):
579 with open(fname, 'r') as f:
580 return f.read()
581
582
583def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000584 if not objects:
585 return
Sean Dague655e0af2014-05-29 09:00:22 -0400586 LOG.info("Creating objects")
587 for obj in objects:
588 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200589 swift_role = obj.get('swift_role', 'Member')
590 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400591 client = client_for_user(obj['owner'])
592 client.containers.create_container(obj['container'])
593 client.objects.create_object(
594 obj['container'], obj['name'],
595 _file_contents(obj['file']))
596
Emilien Macchibb71e072014-07-05 19:18:52 +0200597
598def destroy_objects(objects):
599 for obj in objects:
600 client = client_for_user(obj['owner'])
601 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400602 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200603 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
604
605
Sean Dague655e0af2014-05-29 09:00:22 -0400606#######################
607#
608# IMAGES
609#
610#######################
611
612
Sean Dague319b37a2014-07-11 07:28:11 -0400613def _resolve_image(image, imgtype):
614 name = image[imgtype]
615 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
616 return name, fname
617
618
Joe Gordon6f0426c2014-07-25 01:10:28 +0000619def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000620 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000621 for image in body:
622 if name == image['name']:
623 return image
624 return None
625
626
Sean Dague655e0af2014-05-29 09:00:22 -0400627def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000628 if not images:
629 return
Joe Gordona18d6862014-07-24 22:55:46 +0000630 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400631 for image in images:
632 client = client_for_user(image['owner'])
633
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100634 # DEPRECATED: 'format' was used for ami images
635 # Use 'disk_format' and 'container_format' instead
636 if 'format' in image:
637 LOG.warning("Deprecated: 'format' is deprecated for images "
638 "description. Please use 'disk_format' and 'container_"
639 "format' instead.")
640 image['disk_format'] = image['format']
641 image['container_format'] = image['format']
642
Sean Dague655e0af2014-05-29 09:00:22 -0400643 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000644 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000645 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400646 continue
647
648 # special handling for 3 part image
649 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100650 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400651 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500652 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400653 'javelin_' + name, 'aki', 'aki')
654 client.images.store_image(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400655 extras['kernel_id'] = aki.get('id')
656
Sean Dague319b37a2014-07-11 07:28:11 -0400657 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500658 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400659 'javelin_' + name, 'ari', 'ari')
660 client.images.store_image(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400661 extras['ramdisk_id'] = ari.get('id')
662
Sean Dague319b37a2014-07-11 07:28:11 -0400663 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500664 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100665 image['name'], image['container_format'],
666 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400667 image_id = body.get('id')
Sean Dague319b37a2014-07-11 07:28:11 -0400668 client.images.store_image(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400669
670
Joe Gordon6f0426c2014-07-25 01:10:28 +0000671def destroy_images(images):
672 if not images:
673 return
674 LOG.info("Destroying images")
675 for image in images:
676 client = client_for_user(image['owner'])
677
678 response = _get_image_by_name(client, image['name'])
679 if not response:
680 LOG.info("Image '%s' does not exists" % image['name'])
681 continue
682 client.images.delete_image(response['id'])
683
684
Sean Dague655e0af2014-05-29 09:00:22 -0400685#######################
686#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200687# NETWORKS
688#
689#######################
690
691def _get_router_namespace(client, network):
692 network_id = _get_resource_by_name(client.networks,
693 'networks', network)['id']
David Kranz34e88122014-12-11 15:24:05 -0500694 n_body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200695 for router in n_body['routers']:
696 router_id = router['id']
David Kranz34e88122014-12-11 15:24:05 -0500697 r_body = client.networks.list_router_interfaces(router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200698 for port in r_body['ports']:
699 if port['network_id'] == network_id:
700 return "qrouter-%s" % router_id
701
702
703def _get_resource_by_name(client, resource, name):
704 get_resources = getattr(client, 'list_%s' % resource)
705 if get_resources is None:
706 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500707 # Until all tempest client methods are changed to return only one value,
708 # we cannot assume they all have the same signature so we need to discard
709 # the unused response first value it two values are being returned.
710 body = get_resources()
711 if type(body) == tuple:
712 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200713 if isinstance(body, dict):
714 body = body[resource]
715 for res in body:
716 if name == res['name']:
717 return res
718 raise ValueError('%s not found in %s resources' % (name, resource))
719
720
721def create_networks(networks):
722 LOG.info("Creating networks")
723 for network in networks:
724 client = client_for_user(network['owner'])
725
726 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500727 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200728 if any(item['name'] == network['name'] for item in body['networks']):
729 LOG.warning("Dupplicated network name: %s" % network['name'])
730 continue
731
732 client.networks.create_network(name=network['name'])
733
734
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100735def destroy_networks(networks):
736 LOG.info("Destroying subnets")
737 for network in networks:
738 client = client_for_user(network['owner'])
739 network_id = _get_resource_by_name(client.networks, 'networks',
740 network['name'])['id']
741 client.networks.delete_network(network_id)
742
743
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200744def create_subnets(subnets):
745 LOG.info("Creating subnets")
746 for subnet in subnets:
747 client = client_for_user(subnet['owner'])
748
749 network = _get_resource_by_name(client.networks, 'networks',
750 subnet['network'])
751 ip_version = netaddr.IPNetwork(subnet['range']).version
752 # ensure we don't overlap with another subnet in the network
753 try:
754 client.networks.create_subnet(network_id=network['id'],
755 cidr=subnet['range'],
756 name=subnet['name'],
757 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900758 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200759 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
760 if not is_overlapping_cidr:
761 raise
762
763
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100764def destroy_subnets(subnets):
765 LOG.info("Destroying subnets")
766 for subnet in subnets:
767 client = client_for_user(subnet['owner'])
768 subnet_id = _get_resource_by_name(client.networks,
769 'subnets', subnet['name'])['id']
770 client.networks.delete_subnet(subnet_id)
771
772
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200773def create_routers(routers):
774 LOG.info("Creating routers")
775 for router in routers:
776 client = client_for_user(router['owner'])
777
778 # only create a router if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500779 body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200780 if any(item['name'] == router['name'] for item in body['routers']):
781 LOG.warning("Dupplicated router name: %s" % router['name'])
782 continue
783
784 client.networks.create_router(router['name'])
785
786
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100787def destroy_routers(routers):
788 LOG.info("Destroying routers")
789 for router in routers:
790 client = client_for_user(router['owner'])
791 router_id = _get_resource_by_name(client.networks,
792 'routers', router['name'])['id']
793 for subnet in router['subnet']:
794 subnet_id = _get_resource_by_name(client.networks,
795 'subnets', subnet)['id']
796 client.networks.remove_router_interface_with_subnet_id(router_id,
797 subnet_id)
798 client.networks.delete_router(router_id)
799
800
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200801def add_router_interface(routers):
802 for router in routers:
803 client = client_for_user(router['owner'])
804 router_id = _get_resource_by_name(client.networks,
805 'routers', router['name'])['id']
806
807 for subnet in router['subnet']:
808 subnet_id = _get_resource_by_name(client.networks,
809 'subnets', subnet)['id']
810 # connect routers to their subnets
811 client.networks.add_router_interface_with_subnet_id(router_id,
812 subnet_id)
813 # connect routers to exteral network if set to "gateway"
814 if router['gateway']:
815 if CONF.network.public_network_id:
816 ext_net = CONF.network.public_network_id
817 client.networks._update_router(
818 router_id, set_enable_snat=True,
819 external_gateway_info={"network_id": ext_net})
820 else:
821 raise ValueError('public_network_id is not configured.')
822
823
824#######################
825#
Sean Dague655e0af2014-05-29 09:00:22 -0400826# SERVERS
827#
828#######################
829
830def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500831 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400832 for server in body['servers']:
833 if name == server['name']:
834 return server
835 return None
836
837
Sean Dague655e0af2014-05-29 09:00:22 -0400838def _get_flavor_by_name(client, name):
David Kranz2fa77b22015-02-09 11:39:50 -0500839 body = client.flavors.list_flavors()
Sean Dague655e0af2014-05-29 09:00:22 -0400840 for flavor in body:
841 if name == flavor['name']:
842 return flavor
843 return None
844
845
846def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000847 if not servers:
848 return
Joe Gordona18d6862014-07-24 22:55:46 +0000849 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400850 for server in servers:
851 client = client_for_user(server['owner'])
852
853 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000854 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400855 continue
856
857 image_id = _get_image_by_name(client, server['image'])['id']
858 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200859 # validate neutron is enabled and ironic disabled
860 kwargs = dict()
861 if (CONF.service_available.neutron and
862 not CONF.baremetal.driver_enabled and server.get('networks')):
863 get_net_id = lambda x: (_get_resource_by_name(
864 client.networks, 'networks', x)['id'])
865 kwargs['networks'] = [{'uuid': get_net_id(network)}
866 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500867 body = client.servers.create_server(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200868 server['name'], image_id, flavor_id, **kwargs)
Joe Gordon10f260b2014-07-24 23:27:19 +0000869 server_id = body['id']
870 client.servers.wait_for_server_status(server_id, 'ACTIVE')
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200871 # create to security group(s) after server spawning
872 for secgroup in server['secgroups']:
873 client.servers.add_security_group(server_id, secgroup)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400874 if CONF.compute.use_floatingip_for_ssh:
Joe H. Rahme9350a102015-03-29 17:39:20 +0200875 floating_ip_pool = server.get('floating_ip_pool')
876 floating_ip = client.floating_ips.create_floating_ip(
877 pool_name=floating_ip_pool)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400878 client.floating_ips.associate_floating_ip_to_server(
879 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400880
881
Joe Gordondb63b1c2014-07-24 23:21:21 +0000882def destroy_servers(servers):
883 if not servers:
884 return
885 LOG.info("Destroying servers")
886 for server in servers:
887 client = client_for_user(server['owner'])
888
Emilien Macchidc5bae22015-03-16 08:49:02 -0400889 response = _get_server_by_name(client, server['name'])
890 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000891 LOG.info("Server '%s' does not exist" % server['name'])
892 continue
893
Emilien Macchidc5bae22015-03-16 08:49:02 -0400894 # TODO(EmilienM): disassociate floating IP from server and release it.
895 client.servers.delete_server(response['id'])
896 client.servers.wait_for_server_termination(response['id'],
Matthew Treinish1d14c542014-06-17 20:25:40 -0400897 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000898
899
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200900def create_secgroups(secgroups):
901 LOG.info("Creating security groups")
902 for secgroup in secgroups:
903 client = client_for_user(secgroup['owner'])
904
905 # only create a security group if the name isn't here
906 # i.e. a security group may be used by another server
907 # only create a router if the name isn't here
David Kranz9964b4e2015-02-06 15:45:29 -0500908 body = client.secgroups.list_security_groups()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200909 if any(item['name'] == secgroup['name'] for item in body):
910 LOG.warning("Security group '%s' already exists" %
911 secgroup['name'])
912 continue
913
David Kranz9964b4e2015-02-06 15:45:29 -0500914 body = client.secgroups.create_security_group(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200915 secgroup['name'], secgroup['description'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200916 secgroup_id = body['id']
917 # for each security group, create the rules
918 for rule in secgroup['rules']:
919 ip_proto, from_port, to_port, cidr = rule.split()
920 client.secgroups.create_security_group_rule(
921 secgroup_id, ip_proto, from_port, to_port, cidr=cidr)
922
923
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100924def destroy_secgroups(secgroups):
925 LOG.info("Destroying security groups")
926 for secgroup in secgroups:
927 client = client_for_user(secgroup['owner'])
928 sg_id = _get_resource_by_name(client.secgroups,
929 'security_groups',
930 secgroup['name'])
931 # sg rules are deleted automatically
932 client.secgroups.delete_security_group(sg_id['id'])
933
934
Sean Dague655e0af2014-05-29 09:00:22 -0400935#######################
936#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200937# VOLUMES
938#
939#######################
940
941def _get_volume_by_name(client, name):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000942 body = client.volumes.list_volumes()
Emilien Macchid18fec12014-09-15 14:32:54 -0400943 for volume in body:
944 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200945 return volume
946 return None
947
948
949def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100950 if not volumes:
951 return
952 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200953 for volume in volumes:
954 client = client_for_user(volume['owner'])
955
956 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400957 if _get_volume_by_name(client, volume['name']):
958 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200959 continue
960
Emilien Macchid18fec12014-09-15 14:32:54 -0400961 size = volume['gb']
962 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000963 body = client.volumes.create_volume(size=size,
964 display_name=v_name)
Emilien Macchid18fec12014-09-15 14:32:54 -0400965 client.volumes.wait_for_volume_status(body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200966
967
Emilien Macchibb71e072014-07-05 19:18:52 +0200968def destroy_volumes(volumes):
969 for volume in volumes:
970 client = client_for_user(volume['owner'])
971 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400972 client.volumes.detach_volume(volume_id)
973 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200974
975
Emilien Macchi626b4f82014-06-15 21:44:29 +0200976def attach_volumes(volumes):
977 for volume in volumes:
978 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200979 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400980 volume_id = _get_volume_by_name(client, volume['name'])['id']
981 device = volume['device']
982 client.volumes.attach_volume(volume_id, server_id, device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200983
984
985#######################
986#
Sean Dague655e0af2014-05-29 09:00:22 -0400987# MAIN LOGIC
988#
989#######################
990
991def create_resources():
992 LOG.info("Creating Resources")
993 # first create keystone level resources, and we need to be admin
994 # for those.
995 create_tenants(RES['tenants'])
996 create_users(RES['users'])
997 collect_users(RES['users'])
998
999 # next create resources in a well known order
1000 create_objects(RES['objects'])
1001 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001002
1003 # validate neutron is enabled and ironic is disabled
1004 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1005 create_networks(RES['networks'])
1006 create_subnets(RES['subnets'])
1007 create_routers(RES['routers'])
1008 add_router_interface(RES['routers'])
1009
1010 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001011 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001012
1013 # Only attempt attaching the volumes if servers are defined in the
1014 # resourcefile
1015 if 'servers' in RES:
1016 create_servers(RES['servers'])
1017 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001018
1019
Joe Gordondb63b1c2014-07-24 23:21:21 +00001020def destroy_resources():
1021 LOG.info("Destroying Resources")
1022 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001023 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001024 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001025 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001026 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001027 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1028 destroy_routers(RES['routers'])
1029 destroy_subnets(RES['subnets'])
1030 destroy_networks(RES['networks'])
1031 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001032 destroy_users(RES['users'])
1033 destroy_tenants(RES['tenants'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001034 LOG.warn("Destroy mode incomplete")
1035
Joe Gordondb63b1c2014-07-24 23:21:21 +00001036
Sean Dague655e0af2014-05-29 09:00:22 -04001037def get_options():
1038 global OPTS
1039 parser = argparse.ArgumentParser(
1040 description='Create and validate a fixed set of OpenStack resources')
1041 parser.add_argument('-m', '--mode',
1042 metavar='<create|check|destroy>',
1043 required=True,
1044 help=('One of (create, check, destroy)'))
1045 parser.add_argument('-r', '--resources',
1046 required=True,
1047 metavar='resourcefile.yaml',
1048 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001049
Sean Dague319b37a2014-07-11 07:28:11 -04001050 parser.add_argument(
1051 '-d', '--devstack-base',
1052 required=True,
1053 metavar='/opt/stack/old',
1054 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001055 parser.add_argument(
1056 '-c', '--config-file',
1057 metavar='/etc/tempest.conf',
1058 help='path to javelin2(tempest) config file')
1059
Sean Dague655e0af2014-05-29 09:00:22 -04001060 # auth bits, letting us also just source the devstack openrc
1061 parser.add_argument('--os-username',
1062 metavar='<auth-user-name>',
1063 default=os.environ.get('OS_USERNAME'),
1064 help=('Defaults to env[OS_USERNAME].'))
1065 parser.add_argument('--os-password',
1066 metavar='<auth-password>',
1067 default=os.environ.get('OS_PASSWORD'),
1068 help=('Defaults to env[OS_PASSWORD].'))
1069 parser.add_argument('--os-tenant-name',
1070 metavar='<auth-tenant-name>',
1071 default=os.environ.get('OS_TENANT_NAME'),
1072 help=('Defaults to env[OS_TENANT_NAME].'))
1073
1074 OPTS = parser.parse_args()
1075 if OPTS.mode not in ('create', 'check', 'destroy'):
1076 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1077 parser.print_help()
1078 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001079 if OPTS.config_file:
1080 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001081
1082
Joe Gordon915eb8e2014-07-17 11:25:46 +02001083def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001084 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001085 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001086 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001087
1088
1089def main():
1090 global RES
1091 get_options()
1092 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001093 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001094
1095 if OPTS.mode == 'create':
1096 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001097 # Make sure the resources we just created actually work
1098 checker = JavelinCheck(USERS, RES)
1099 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001100 elif OPTS.mode == 'check':
1101 collect_users(RES['users'])
1102 checker = JavelinCheck(USERS, RES)
1103 checker.check()
1104 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001105 collect_users(RES['users'])
1106 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001107 else:
1108 LOG.error('Unknown mode %s' % OPTS.mode)
1109 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001110 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001111 return 0
1112
1113if __name__ == "__main__":
1114 sys.exit(main())