blob: 71aacbddebcf20a2fd85f1ea1467643beed61ad6 [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
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000122from tempest.common import waiters
Joe Gordon28a84ae2014-07-17 15:38:28 +0000123from tempest import config
Sean Dague655e0af2014-05-29 09:00:22 -0400124from tempest.services.compute.json import flavors_client
Emilien Macchic3e3e292015-03-11 17:42:08 -0400125from tempest.services.compute.json import floating_ips_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000126from tempest.services.compute.json import security_group_rules_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200127from tempest.services.compute.json import security_groups_client
Sean Dague655e0af2014-05-29 09:00:22 -0400128from tempest.services.compute.json import servers_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100129from tempest.services.identity.v2.json import identity_client
Sean Dague655e0af2014-05-29 09:00:22 -0400130from tempest.services.image.v2.json import image_client
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200131from tempest.services.network.json import network_client
Sean Dague655e0af2014-05-29 09:00:22 -0400132from tempest.services.object_storage import container_client
133from tempest.services.object_storage import object_client
Chris Dent878f3782014-06-30 17:04:15 +0100134from tempest.services.telemetry.json import telemetry_client
Emilien Macchi626b4f82014-06-15 21:44:29 +0200135from tempest.services.volume.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400136
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200137CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400138OPTS = {}
139USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100140RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400141
142LOG = None
143
Chris Dent878f3782014-06-30 17:04:15 +0100144JAVELIN_START = datetime.datetime.utcnow()
145
Sean Dague655e0af2014-05-29 09:00:22 -0400146
147class OSClient(object):
148 _creds = None
149 identity = None
150 servers = None
151
152 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000153 default_params = {
154 'disable_ssl_certificate_validation':
155 CONF.identity.disable_ssl_certificate_validation,
156 'ca_certs': CONF.identity.ca_certificates_file,
157 'trace_requests': CONF.debug.trace_requests
158 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000159 default_params_with_timeout_values = {
160 'build_interval': CONF.compute.build_interval,
161 'build_timeout': CONF.compute.build_timeout
162 }
163 default_params_with_timeout_values.update(default_params)
164
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000165 compute_params = {
166 'service': CONF.compute.catalog_type,
167 'region': CONF.compute.region or CONF.identity.region,
168 'endpoint_type': CONF.compute.endpoint_type,
169 'build_interval': CONF.compute.build_interval,
170 'build_timeout': CONF.compute.build_timeout
171 }
172 compute_params.update(default_params)
173
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000174 object_storage_params = {
175 'service': CONF.object_storage.catalog_type,
176 'region': CONF.object_storage.region or CONF.identity.region,
177 'endpoint_type': CONF.object_storage.endpoint_type
178 }
179 object_storage_params.update(default_params)
180
andreafb8a52282015-03-19 22:21:54 +0000181 _creds = auth.KeystoneV2Credentials(
Sean Dague655e0af2014-05-29 09:00:22 -0400182 username=user,
183 password=pw,
184 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000185 auth_provider_params = {
186 'disable_ssl_certificate_validation':
187 CONF.identity.disable_ssl_certificate_validation,
188 'ca_certs': CONF.identity.ca_certificates_file,
189 'trace_requests': CONF.debug.trace_requests
190 }
andreafb8a52282015-03-19 22:21:54 +0000191 _auth = auth.KeystoneV2AuthProvider(
Andrea Frittoli90012352015-02-25 21:58:02 +0000192 _creds, CONF.identity.uri, **auth_provider_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000193 self.identity = identity_client.IdentityClient(
ghanshyamd26b5cd2015-02-09 14:48:58 +0900194 _auth,
195 CONF.identity.catalog_type,
196 CONF.identity.region,
197 endpoint_type='adminURL',
198 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000199 self.servers = servers_client.ServersClient(_auth,
200 **compute_params)
201 self.flavors = flavors_client.FlavorsClient(_auth,
202 **compute_params)
203 self.floating_ips = floating_ips_client.FloatingIPsClient(
Emilien Macchic3e3e292015-03-11 17:42:08 -0400204 _auth, **compute_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000205 self.secgroups = security_groups_client.SecurityGroupsClient(
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000206 _auth, **compute_params)
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000207 self.secrules = security_group_rules_client.SecurityGroupRulesClient(
208 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000209 self.objects = object_client.ObjectClient(_auth,
210 **object_storage_params)
211 self.containers = container_client.ContainerClient(
212 _auth, **object_storage_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000213 self.images = image_client.ImageClientV2(
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900214 _auth,
215 CONF.image.catalog_type,
216 CONF.image.region or CONF.identity.region,
217 endpoint_type=CONF.image.endpoint_type,
218 build_interval=CONF.image.build_interval,
219 build_timeout=CONF.image.build_timeout,
220 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000221 self.telemetry = telemetry_client.TelemetryClient(
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000222 _auth,
223 CONF.telemetry.catalog_type,
224 CONF.identity.region,
225 endpoint_type=CONF.telemetry.endpoint_type,
226 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000227 self.volumes = volumes_client.VolumesClient(
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000228 _auth,
229 CONF.volume.catalog_type,
230 CONF.volume.region or CONF.identity.region,
231 endpoint_type=CONF.volume.endpoint_type,
232 build_interval=CONF.volume.build_interval,
233 build_timeout=CONF.volume.build_timeout,
234 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000235 self.networks = network_client.NetworkClient(
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000236 _auth,
237 CONF.network.catalog_type,
238 CONF.network.region or CONF.identity.region,
239 endpoint_type=CONF.network.endpoint_type,
240 build_interval=CONF.network.build_interval,
241 build_timeout=CONF.network.build_timeout,
242 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400243
244
245def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100246 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400247 return yaml.load(open(fname, 'r'))
248
249
250def keystone_admin():
251 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
252
253
254def client_for_user(name):
255 LOG.debug("Entering client_for_user")
256 if name in USERS:
257 user = USERS[name]
258 LOG.debug("Created client for user %s" % user)
259 return OSClient(user['name'], user['pass'], user['tenant'])
260 else:
261 LOG.error("%s not found in USERS: %s" % (name, USERS))
262
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200263
Sean Dague655e0af2014-05-29 09:00:22 -0400264###################
265#
266# TENANTS
267#
268###################
269
270
271def create_tenants(tenants):
272 """Create tenants from resource definition.
273
274 Don't create the tenants if they already exist.
275 """
276 admin = keystone_admin()
John Warrenacf00512015-08-06 16:13:58 -0400277 body = admin.identity.list_tenants()['tenants']
Sean Dague655e0af2014-05-29 09:00:22 -0400278 existing = [x['name'] for x in body]
279 for tenant in tenants:
280 if tenant not in existing:
281 admin.identity.create_tenant(tenant)
282 else:
283 LOG.warn("Tenant '%s' already exists in this environment" % tenant)
284
Emilien Macchibb71e072014-07-05 19:18:52 +0200285
286def destroy_tenants(tenants):
287 admin = keystone_admin()
288 for tenant in tenants:
289 tenant_id = admin.identity.get_tenant_by_name(tenant)['id']
David Kranzb7afa922014-12-30 10:56:26 -0500290 admin.identity.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200291
Sean Dague655e0af2014-05-29 09:00:22 -0400292##############
293#
294# USERS
295#
296##############
297
298
299def _users_for_tenant(users, tenant):
300 u_for_t = []
301 for user in users:
302 for n in user:
303 if user[n]['tenant'] == tenant:
304 u_for_t.append(user[n])
305 return u_for_t
306
307
308def _tenants_from_users(users):
309 tenants = set()
310 for user in users:
311 for n in user:
312 tenants.add(user[n]['tenant'])
313 return tenants
314
315
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200316def _assign_swift_role(user, swift_role):
Sean Dague655e0af2014-05-29 09:00:22 -0400317 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500318 roles = admin.identity.list_roles()
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200319 role = next(r for r in roles if r['name'] == swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400320 LOG.debug(USERS[user])
321 try:
322 admin.identity.assign_user_role(
323 USERS[user]['tenant_id'],
324 USERS[user]['id'],
325 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900326 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400327 # don't care if it's already assigned
328 pass
329
330
331def create_users(users):
332 """Create tenants from resource definition.
333
334 Don't create the tenants if they already exist.
335 """
336 global USERS
337 LOG.info("Creating users")
338 admin = keystone_admin()
339 for u in users:
340 try:
341 tenant = admin.identity.get_tenant_by_name(u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900342 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400343 LOG.error("Tenant: %s - not found" % u['tenant'])
344 continue
345 try:
346 admin.identity.get_user_by_username(tenant['id'], u['name'])
347 LOG.warn("User '%s' already exists in this environment"
348 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900349 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400350 admin.identity.create_user(
351 u['name'], u['pass'], tenant['id'],
352 "%s@%s" % (u['name'], tenant['id']),
353 enabled=True)
354
355
Emilien Macchibb71e072014-07-05 19:18:52 +0200356def destroy_users(users):
357 admin = keystone_admin()
358 for user in users:
Emilien Macchi436de862014-09-30 17:09:50 -0400359 tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
360 user_id = admin.identity.get_user_by_username(tenant_id,
361 user['name'])['id']
David Kranzb7afa922014-12-30 10:56:26 -0500362 admin.identity.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200363
364
Sean Dague655e0af2014-05-29 09:00:22 -0400365def collect_users(users):
366 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200367 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400368 admin = keystone_admin()
369 for u in users:
370 tenant = admin.identity.get_tenant_by_name(u['tenant'])
371 u['tenant_id'] = tenant['id']
372 USERS[u['name']] = u
373 body = admin.identity.get_user_by_username(tenant['id'], u['name'])
374 USERS[u['name']]['id'] = body['id']
375
376
377class JavelinCheck(unittest.TestCase):
378 def __init__(self, users, resources):
379 super(JavelinCheck, self).__init__()
380 self.users = users
381 self.res = resources
382
383 def runTest(self, *args):
384 pass
385
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200386 def _ping_ip(self, ip_addr, count, namespace=None):
387 if namespace is None:
388 ping_cmd = "ping -c1 " + ip_addr
389 else:
390 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
391 ip_addr)
392 for current in range(count):
393 return_code = os.system(ping_cmd)
394 if return_code is 0:
395 break
396 self.assertNotEqual(current, count - 1,
397 "Server is not pingable at %s" % ip_addr)
398
Sean Dague655e0af2014-05-29 09:00:22 -0400399 def check(self):
400 self.check_users()
401 self.check_objects()
402 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400403 self.check_volumes()
Chris Dent878f3782014-06-30 17:04:15 +0100404 self.check_telemetry()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200405 self.check_secgroups()
406
407 # validate neutron is enabled and ironic disabled:
408 # Tenant network isolation is not supported when using ironic.
409 # "admin" has set up a neutron flat network environment within a shared
410 # fixed network for all tenants to use.
411 # In this case, network/subnet/router creation can be skipped and the
412 # server booted the same as nova network.
413 if (CONF.service_available.neutron and
414 not CONF.baremetal.driver_enabled):
415 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400416
417 def check_users(self):
418 """Check that the users we expect to exist, do.
419
420 We don't use the resource list for this because we need to validate
421 that things like tenantId didn't drift across versions.
422 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200423 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400424 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400425 client = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500426 found = client.identity.get_user(user['id'])
Sean Dague655e0af2014-05-29 09:00:22 -0400427 self.assertEqual(found['name'], user['name'])
428 self.assertEqual(found['tenantId'], user['tenant_id'])
429
430 # also ensure we can auth with that user, and do something
431 # on the cloud. We don't care about the results except that it
432 # remains authorized.
433 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500434 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400435
436 def check_objects(self):
437 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000438 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000439 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200440 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400441 for obj in self.res['objects']:
442 client = client_for_user(obj['owner'])
443 r, contents = client.objects.get_object(
444 obj['container'], obj['name'])
445 source = _file_contents(obj['file'])
446 self.assertEqual(contents, source)
447
448 def check_servers(self):
449 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000450 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000451 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200452 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400453 for server in self.res['servers']:
454 client = client_for_user(server['owner'])
455 found = _get_server_by_name(client, server['name'])
456 self.assertIsNotNone(
457 found,
458 "Couldn't find expected server %s" % server['name'])
459
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +0000460 found = client.servers.show_server(found['id'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200461 # validate neutron is enabled and ironic disabled:
462 if (CONF.service_available.neutron and
463 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400464 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200465 for network_name, body in found['addresses'].items():
466 for addr in body:
467 ip = addr['addr']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400468 # If floatingip_for_ssh is at True, it's assumed
469 # you want to use the floating IP to reach the server,
470 # fallback to fixed IP, then other type.
471 # This is useful in multi-node environment.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700472 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400473 if addr.get('OS-EXT-IPS:type',
474 'floating') == 'floating':
475 self._ping_ip(ip, 60)
476 _floating_is_alive = True
477 elif addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200478 namespace = _get_router_namespace(client,
479 network_name)
480 self._ping_ip(ip, 60, namespace)
481 else:
482 self._ping_ip(ip, 60)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400483 # if floatingip_for_ssh is at True, validate found a
484 # floating IP and ping worked.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700485 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400486 self.assertTrue(_floating_is_alive,
487 "Server %s has no floating IP." %
488 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200489 else:
490 addr = found['addresses']['private'][0]['addr']
491 self._ping_ip(addr, 60)
492
493 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100494 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200495 LOG.info("Checking security groups")
496 for secgroup in self.res['secgroups']:
497 client = client_for_user(secgroup['owner'])
498 found = _get_resource_by_name(client.secgroups, 'security_groups',
499 secgroup['name'])
500 self.assertIsNotNone(
501 found,
502 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400503
Chris Dent878f3782014-06-30 17:04:15 +0100504 def check_telemetry(self):
505 """Check that ceilometer provides a sane sample.
506
nayna-patel1dfbedb2015-08-04 11:07:56 +0000507 Confirm that there is more than one sample and that they have the
Chris Dent878f3782014-06-30 17:04:15 +0100508 expected metadata.
509
510 If in check mode confirm that the oldest sample available is from
511 before the upgrade.
512 """
Chris Dent0b76f2f2014-10-10 14:24:28 +0100513 if not self.res.get('telemetry'):
514 return
Chris Dent878f3782014-06-30 17:04:15 +0100515 LOG.info("checking telemetry")
516 for server in self.res['servers']:
517 client = client_for_user(server['owner'])
David Kranz20d06f42015-02-09 14:54:15 -0500518 body = client.telemetry.list_samples(
Chris Dent878f3782014-06-30 17:04:15 +0100519 'instance',
520 query=('metadata.display_name', 'eq', server['name'])
521 )
Chris Dent878f3782014-06-30 17:04:15 +0100522 self.assertTrue(len(body) >= 1, 'expecting at least one sample')
523 self._confirm_telemetry_sample(server, body[-1])
524
Emilien Macchi626b4f82014-06-15 21:44:29 +0200525 def check_volumes(self):
526 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000527 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000528 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200529 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200530 for volume in self.res['volumes']:
531 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400532 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200533 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400534 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200535 "Couldn't find expected volume %s" % volume['name'])
536
537 # Verify that a volume's attachment retrieved
538 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400539 attachment = client.volumes.get_attachment_from_volume(vol_body)
540 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200541 self.assertEqual(server_id, attachment['server_id'])
542
Chris Dent878f3782014-06-30 17:04:15 +0100543 def _confirm_telemetry_sample(self, server, sample):
544 """Check this sample matches the expected resource metadata."""
545 # Confirm display_name
546 self.assertEqual(server['name'],
547 sample['resource_metadata']['display_name'])
548 # Confirm instance_type of flavor
549 flavor = sample['resource_metadata'].get(
550 'flavor.name',
551 sample['resource_metadata'].get('instance_type')
552 )
553 self.assertEqual(server['flavor'], flavor)
554 # Confirm the oldest sample was created before upgrade.
555 if OPTS.mode == 'check':
556 oldest_timestamp = timeutils.normalize_time(
557 timeutils.parse_isotime(sample['timestamp']))
558 self.assertTrue(
559 oldest_timestamp < JAVELIN_START,
560 'timestamp should come before start of second javelin run'
561 )
562
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200563 def check_networking(self):
564 """Check that the networks are still there."""
565 for res_type in ('networks', 'subnets', 'routers'):
566 for res in self.res[res_type]:
567 client = client_for_user(res['owner'])
568 found = _get_resource_by_name(client.networks, res_type,
569 res['name'])
570 self.assertIsNotNone(
571 found,
572 "Couldn't find expected resource %s" % res['name'])
573
Sean Dague655e0af2014-05-29 09:00:22 -0400574
575#######################
576#
577# OBJECTS
578#
579#######################
580
581
582def _file_contents(fname):
583 with open(fname, 'r') as f:
584 return f.read()
585
586
587def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000588 if not objects:
589 return
Sean Dague655e0af2014-05-29 09:00:22 -0400590 LOG.info("Creating objects")
591 for obj in objects:
592 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200593 swift_role = obj.get('swift_role', 'Member')
594 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400595 client = client_for_user(obj['owner'])
596 client.containers.create_container(obj['container'])
597 client.objects.create_object(
598 obj['container'], obj['name'],
599 _file_contents(obj['file']))
600
Emilien Macchibb71e072014-07-05 19:18:52 +0200601
602def destroy_objects(objects):
603 for obj in objects:
604 client = client_for_user(obj['owner'])
605 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400606 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200607 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
608
609
Sean Dague655e0af2014-05-29 09:00:22 -0400610#######################
611#
612# IMAGES
613#
614#######################
615
616
Sean Dague319b37a2014-07-11 07:28:11 -0400617def _resolve_image(image, imgtype):
618 name = image[imgtype]
619 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
620 return name, fname
621
622
Joe Gordon6f0426c2014-07-25 01:10:28 +0000623def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000624 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000625 for image in body:
626 if name == image['name']:
627 return image
628 return None
629
630
Sean Dague655e0af2014-05-29 09:00:22 -0400631def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000632 if not images:
633 return
Joe Gordona18d6862014-07-24 22:55:46 +0000634 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400635 for image in images:
636 client = client_for_user(image['owner'])
637
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100638 # DEPRECATED: 'format' was used for ami images
639 # Use 'disk_format' and 'container_format' instead
640 if 'format' in image:
641 LOG.warning("Deprecated: 'format' is deprecated for images "
642 "description. Please use 'disk_format' and 'container_"
643 "format' instead.")
644 image['disk_format'] = image['format']
645 image['container_format'] = image['format']
646
Sean Dague655e0af2014-05-29 09:00:22 -0400647 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000648 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000649 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400650 continue
651
652 # special handling for 3 part image
653 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100654 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400655 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500656 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400657 'javelin_' + name, 'aki', 'aki')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000658 client.images.store_image_file(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400659 extras['kernel_id'] = aki.get('id')
660
Sean Dague319b37a2014-07-11 07:28:11 -0400661 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500662 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400663 'javelin_' + name, 'ari', 'ari')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000664 client.images.store_image_file(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400665 extras['ramdisk_id'] = ari.get('id')
666
Sean Dague319b37a2014-07-11 07:28:11 -0400667 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500668 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100669 image['name'], image['container_format'],
670 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400671 image_id = body.get('id')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000672 client.images.store_image_file(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400673
674
Joe Gordon6f0426c2014-07-25 01:10:28 +0000675def destroy_images(images):
676 if not images:
677 return
678 LOG.info("Destroying images")
679 for image in images:
680 client = client_for_user(image['owner'])
681
682 response = _get_image_by_name(client, image['name'])
683 if not response:
nayna-patel1dfbedb2015-08-04 11:07:56 +0000684 LOG.info("Image '%s' does not exist" % image['name'])
Joe Gordon6f0426c2014-07-25 01:10:28 +0000685 continue
686 client.images.delete_image(response['id'])
687
688
Sean Dague655e0af2014-05-29 09:00:22 -0400689#######################
690#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200691# NETWORKS
692#
693#######################
694
695def _get_router_namespace(client, network):
696 network_id = _get_resource_by_name(client.networks,
697 'networks', network)['id']
David Kranz34e88122014-12-11 15:24:05 -0500698 n_body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200699 for router in n_body['routers']:
700 router_id = router['id']
David Kranz34e88122014-12-11 15:24:05 -0500701 r_body = client.networks.list_router_interfaces(router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200702 for port in r_body['ports']:
703 if port['network_id'] == network_id:
704 return "qrouter-%s" % router_id
705
706
707def _get_resource_by_name(client, resource, name):
708 get_resources = getattr(client, 'list_%s' % resource)
709 if get_resources is None:
710 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500711 # Until all tempest client methods are changed to return only one value,
712 # we cannot assume they all have the same signature so we need to discard
713 # the unused response first value it two values are being returned.
714 body = get_resources()
715 if type(body) == tuple:
716 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200717 if isinstance(body, dict):
718 body = body[resource]
719 for res in body:
720 if name == res['name']:
721 return res
722 raise ValueError('%s not found in %s resources' % (name, resource))
723
724
725def create_networks(networks):
726 LOG.info("Creating networks")
727 for network in networks:
728 client = client_for_user(network['owner'])
729
730 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500731 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200732 if any(item['name'] == network['name'] for item in body['networks']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000733 LOG.warning("Duplicated network name: %s" % network['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200734 continue
735
736 client.networks.create_network(name=network['name'])
737
738
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100739def destroy_networks(networks):
740 LOG.info("Destroying subnets")
741 for network in networks:
742 client = client_for_user(network['owner'])
743 network_id = _get_resource_by_name(client.networks, 'networks',
744 network['name'])['id']
745 client.networks.delete_network(network_id)
746
747
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200748def create_subnets(subnets):
749 LOG.info("Creating subnets")
750 for subnet in subnets:
751 client = client_for_user(subnet['owner'])
752
753 network = _get_resource_by_name(client.networks, 'networks',
754 subnet['network'])
755 ip_version = netaddr.IPNetwork(subnet['range']).version
756 # ensure we don't overlap with another subnet in the network
757 try:
758 client.networks.create_subnet(network_id=network['id'],
759 cidr=subnet['range'],
760 name=subnet['name'],
761 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900762 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200763 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
764 if not is_overlapping_cidr:
765 raise
766
767
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100768def destroy_subnets(subnets):
769 LOG.info("Destroying subnets")
770 for subnet in subnets:
771 client = client_for_user(subnet['owner'])
772 subnet_id = _get_resource_by_name(client.networks,
773 'subnets', subnet['name'])['id']
774 client.networks.delete_subnet(subnet_id)
775
776
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200777def create_routers(routers):
778 LOG.info("Creating routers")
779 for router in routers:
780 client = client_for_user(router['owner'])
781
782 # only create a router if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500783 body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200784 if any(item['name'] == router['name'] for item in body['routers']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000785 LOG.warning("Duplicated router name: %s" % router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200786 continue
787
788 client.networks.create_router(router['name'])
789
790
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100791def destroy_routers(routers):
792 LOG.info("Destroying routers")
793 for router in routers:
794 client = client_for_user(router['owner'])
795 router_id = _get_resource_by_name(client.networks,
796 'routers', router['name'])['id']
797 for subnet in router['subnet']:
798 subnet_id = _get_resource_by_name(client.networks,
799 'subnets', subnet)['id']
800 client.networks.remove_router_interface_with_subnet_id(router_id,
801 subnet_id)
802 client.networks.delete_router(router_id)
803
804
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200805def add_router_interface(routers):
806 for router in routers:
807 client = client_for_user(router['owner'])
808 router_id = _get_resource_by_name(client.networks,
809 'routers', router['name'])['id']
810
811 for subnet in router['subnet']:
812 subnet_id = _get_resource_by_name(client.networks,
813 'subnets', subnet)['id']
814 # connect routers to their subnets
815 client.networks.add_router_interface_with_subnet_id(router_id,
816 subnet_id)
nayna-patel1dfbedb2015-08-04 11:07:56 +0000817 # connect routers to external network if set to "gateway"
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200818 if router['gateway']:
819 if CONF.network.public_network_id:
820 ext_net = CONF.network.public_network_id
821 client.networks._update_router(
822 router_id, set_enable_snat=True,
823 external_gateway_info={"network_id": ext_net})
824 else:
825 raise ValueError('public_network_id is not configured.')
826
827
828#######################
829#
Sean Dague655e0af2014-05-29 09:00:22 -0400830# SERVERS
831#
832#######################
833
834def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500835 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400836 for server in body['servers']:
837 if name == server['name']:
838 return server
839 return None
840
841
Sean Dague655e0af2014-05-29 09:00:22 -0400842def _get_flavor_by_name(client, name):
David Kranz2fa77b22015-02-09 11:39:50 -0500843 body = client.flavors.list_flavors()
Sean Dague655e0af2014-05-29 09:00:22 -0400844 for flavor in body:
845 if name == flavor['name']:
846 return flavor
847 return None
848
849
850def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000851 if not servers:
852 return
Joe Gordona18d6862014-07-24 22:55:46 +0000853 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400854 for server in servers:
855 client = client_for_user(server['owner'])
856
857 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000858 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400859 continue
860
861 image_id = _get_image_by_name(client, server['image'])['id']
862 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200863 # validate neutron is enabled and ironic disabled
864 kwargs = dict()
865 if (CONF.service_available.neutron and
866 not CONF.baremetal.driver_enabled and server.get('networks')):
867 get_net_id = lambda x: (_get_resource_by_name(
868 client.networks, 'networks', x)['id'])
869 kwargs['networks'] = [{'uuid': get_net_id(network)}
870 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500871 body = client.servers.create_server(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200872 server['name'], image_id, flavor_id, **kwargs)
Joe Gordon10f260b2014-07-24 23:27:19 +0000873 server_id = body['id']
874 client.servers.wait_for_server_status(server_id, 'ACTIVE')
nayna-patel1dfbedb2015-08-04 11:07:56 +0000875 # create security group(s) after server spawning
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200876 for secgroup in server['secgroups']:
877 client.servers.add_security_group(server_id, secgroup)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400878 if CONF.compute.use_floatingip_for_ssh:
Joe H. Rahme9350a102015-03-29 17:39:20 +0200879 floating_ip_pool = server.get('floating_ip_pool')
880 floating_ip = client.floating_ips.create_floating_ip(
881 pool_name=floating_ip_pool)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400882 client.floating_ips.associate_floating_ip_to_server(
883 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400884
885
Joe Gordondb63b1c2014-07-24 23:21:21 +0000886def destroy_servers(servers):
887 if not servers:
888 return
889 LOG.info("Destroying servers")
890 for server in servers:
891 client = client_for_user(server['owner'])
892
Emilien Macchidc5bae22015-03-16 08:49:02 -0400893 response = _get_server_by_name(client, server['name'])
894 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000895 LOG.info("Server '%s' does not exist" % server['name'])
896 continue
897
Emilien Macchidc5bae22015-03-16 08:49:02 -0400898 # TODO(EmilienM): disassociate floating IP from server and release it.
899 client.servers.delete_server(response['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000900 waiters.wait_for_server_termination(client.servers, response['id'],
901 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000902
903
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200904def create_secgroups(secgroups):
905 LOG.info("Creating security groups")
906 for secgroup in secgroups:
907 client = client_for_user(secgroup['owner'])
908
909 # only create a security group if the name isn't here
910 # i.e. a security group may be used by another server
911 # only create a router if the name isn't here
David Kranz9964b4e2015-02-06 15:45:29 -0500912 body = client.secgroups.list_security_groups()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200913 if any(item['name'] == secgroup['name'] for item in body):
914 LOG.warning("Security group '%s' already exists" %
915 secgroup['name'])
916 continue
917
David Kranz9964b4e2015-02-06 15:45:29 -0500918 body = client.secgroups.create_security_group(
Ken'ichi Ohmichi34563cc2015-07-21 00:53:17 +0000919 name=secgroup['name'], description=secgroup['description'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200920 secgroup_id = body['id']
921 # for each security group, create the rules
922 for rule in secgroup['rules']:
923 ip_proto, from_port, to_port, cidr = rule.split()
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000924 client.secrules.create_security_group_rule(
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000925 parent_group_id=secgroup_id, ip_protocol=ip_proto,
926 from_port=from_port, to_port=to_port, cidr=cidr)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200927
928
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100929def destroy_secgroups(secgroups):
930 LOG.info("Destroying security groups")
931 for secgroup in secgroups:
932 client = client_for_user(secgroup['owner'])
933 sg_id = _get_resource_by_name(client.secgroups,
934 'security_groups',
935 secgroup['name'])
936 # sg rules are deleted automatically
937 client.secgroups.delete_security_group(sg_id['id'])
938
939
Sean Dague655e0af2014-05-29 09:00:22 -0400940#######################
941#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200942# VOLUMES
943#
944#######################
945
946def _get_volume_by_name(client, name):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000947 body = client.volumes.list_volumes()
Emilien Macchid18fec12014-09-15 14:32:54 -0400948 for volume in body:
949 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200950 return volume
951 return None
952
953
954def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100955 if not volumes:
956 return
957 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200958 for volume in volumes:
959 client = client_for_user(volume['owner'])
960
961 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400962 if _get_volume_by_name(client, volume['name']):
963 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200964 continue
965
Emilien Macchid18fec12014-09-15 14:32:54 -0400966 size = volume['gb']
967 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000968 body = client.volumes.create_volume(size=size,
969 display_name=v_name)
Emilien Macchid18fec12014-09-15 14:32:54 -0400970 client.volumes.wait_for_volume_status(body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200971
972
Emilien Macchibb71e072014-07-05 19:18:52 +0200973def destroy_volumes(volumes):
974 for volume in volumes:
975 client = client_for_user(volume['owner'])
976 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400977 client.volumes.detach_volume(volume_id)
978 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200979
980
Emilien Macchi626b4f82014-06-15 21:44:29 +0200981def attach_volumes(volumes):
982 for volume in volumes:
983 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200984 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400985 volume_id = _get_volume_by_name(client, volume['name'])['id']
986 device = volume['device']
987 client.volumes.attach_volume(volume_id, server_id, device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200988
989
990#######################
991#
Sean Dague655e0af2014-05-29 09:00:22 -0400992# MAIN LOGIC
993#
994#######################
995
996def create_resources():
997 LOG.info("Creating Resources")
998 # first create keystone level resources, and we need to be admin
nayna-patel1dfbedb2015-08-04 11:07:56 +0000999 # for this.
Sean Dague655e0af2014-05-29 09:00:22 -04001000 create_tenants(RES['tenants'])
1001 create_users(RES['users'])
1002 collect_users(RES['users'])
1003
1004 # next create resources in a well known order
1005 create_objects(RES['objects'])
1006 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001007
1008 # validate neutron is enabled and ironic is disabled
1009 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1010 create_networks(RES['networks'])
1011 create_subnets(RES['subnets'])
1012 create_routers(RES['routers'])
1013 add_router_interface(RES['routers'])
1014
1015 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001016 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001017
1018 # Only attempt attaching the volumes if servers are defined in the
nayna-patel1dfbedb2015-08-04 11:07:56 +00001019 # resource file
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001020 if 'servers' in RES:
1021 create_servers(RES['servers'])
1022 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001023
1024
Joe Gordondb63b1c2014-07-24 23:21:21 +00001025def destroy_resources():
1026 LOG.info("Destroying Resources")
1027 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001028 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001029 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001030 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001031 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001032 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1033 destroy_routers(RES['routers'])
1034 destroy_subnets(RES['subnets'])
1035 destroy_networks(RES['networks'])
1036 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001037 destroy_users(RES['users'])
1038 destroy_tenants(RES['tenants'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001039 LOG.warn("Destroy mode incomplete")
1040
Joe Gordondb63b1c2014-07-24 23:21:21 +00001041
Sean Dague655e0af2014-05-29 09:00:22 -04001042def get_options():
1043 global OPTS
1044 parser = argparse.ArgumentParser(
1045 description='Create and validate a fixed set of OpenStack resources')
1046 parser.add_argument('-m', '--mode',
1047 metavar='<create|check|destroy>',
1048 required=True,
1049 help=('One of (create, check, destroy)'))
1050 parser.add_argument('-r', '--resources',
1051 required=True,
1052 metavar='resourcefile.yaml',
1053 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001054
Sean Dague319b37a2014-07-11 07:28:11 -04001055 parser.add_argument(
1056 '-d', '--devstack-base',
1057 required=True,
1058 metavar='/opt/stack/old',
1059 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001060 parser.add_argument(
1061 '-c', '--config-file',
1062 metavar='/etc/tempest.conf',
1063 help='path to javelin2(tempest) config file')
1064
Sean Dague655e0af2014-05-29 09:00:22 -04001065 # auth bits, letting us also just source the devstack openrc
1066 parser.add_argument('--os-username',
1067 metavar='<auth-user-name>',
1068 default=os.environ.get('OS_USERNAME'),
1069 help=('Defaults to env[OS_USERNAME].'))
1070 parser.add_argument('--os-password',
1071 metavar='<auth-password>',
1072 default=os.environ.get('OS_PASSWORD'),
1073 help=('Defaults to env[OS_PASSWORD].'))
1074 parser.add_argument('--os-tenant-name',
1075 metavar='<auth-tenant-name>',
1076 default=os.environ.get('OS_TENANT_NAME'),
1077 help=('Defaults to env[OS_TENANT_NAME].'))
1078
1079 OPTS = parser.parse_args()
1080 if OPTS.mode not in ('create', 'check', 'destroy'):
1081 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1082 parser.print_help()
1083 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001084 if OPTS.config_file:
1085 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001086
1087
Joe Gordon915eb8e2014-07-17 11:25:46 +02001088def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001089 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001090 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001091 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001092
1093
1094def main():
1095 global RES
1096 get_options()
1097 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001098 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001099
1100 if OPTS.mode == 'create':
1101 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001102 # Make sure the resources we just created actually work
1103 checker = JavelinCheck(USERS, RES)
1104 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001105 elif OPTS.mode == 'check':
1106 collect_users(RES['users'])
1107 checker = JavelinCheck(USERS, RES)
1108 checker.check()
1109 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001110 collect_users(RES['users'])
1111 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001112 else:
1113 LOG.error('Unknown mode %s' % OPTS.mode)
1114 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001115 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001116 return 0
1117
1118if __name__ == "__main__":
1119 sys.exit(main())