blob: 97d431a1bdee5a03eb62a6f89b95a69ef181affd [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
ghanshyam2f6f5f12015-10-14 14:27:36 +0900120from tempest_lib.services.compute import flavors_client
Matthew Treinish96e9e882014-06-09 18:37:19 -0400121import yaml
Sean Dague655e0af2014-05-29 09:00:22 -0400122
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000123from tempest.common import waiters
Joe Gordon28a84ae2014-07-17 15:38:28 +0000124from tempest import config
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
John Warren3961acd2015-10-02 14:38:53 -0400132from tempest.services.network.json import subnets_client
Sean Dague655e0af2014-05-29 09:00:22 -0400133from tempest.services.object_storage import container_client
134from tempest.services.object_storage import object_client
Chris Dent878f3782014-06-30 17:04:15 +0100135from tempest.services.telemetry.json import telemetry_client
Emilien Macchi626b4f82014-06-15 21:44:29 +0200136from tempest.services.volume.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400137
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200138CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400139OPTS = {}
140USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100141RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400142
143LOG = None
144
Chris Dent878f3782014-06-30 17:04:15 +0100145JAVELIN_START = datetime.datetime.utcnow()
146
Sean Dague655e0af2014-05-29 09:00:22 -0400147
148class OSClient(object):
149 _creds = None
150 identity = None
151 servers = None
152
153 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000154 default_params = {
155 'disable_ssl_certificate_validation':
156 CONF.identity.disable_ssl_certificate_validation,
157 'ca_certs': CONF.identity.ca_certificates_file,
158 'trace_requests': CONF.debug.trace_requests
159 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000160 default_params_with_timeout_values = {
161 'build_interval': CONF.compute.build_interval,
162 'build_timeout': CONF.compute.build_timeout
163 }
164 default_params_with_timeout_values.update(default_params)
165
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000166 compute_params = {
167 'service': CONF.compute.catalog_type,
168 'region': CONF.compute.region or CONF.identity.region,
169 'endpoint_type': CONF.compute.endpoint_type,
170 'build_interval': CONF.compute.build_interval,
171 'build_timeout': CONF.compute.build_timeout
172 }
173 compute_params.update(default_params)
174
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000175 object_storage_params = {
176 'service': CONF.object_storage.catalog_type,
177 'region': CONF.object_storage.region or CONF.identity.region,
178 'endpoint_type': CONF.object_storage.endpoint_type
179 }
180 object_storage_params.update(default_params)
181
andreafb8a52282015-03-19 22:21:54 +0000182 _creds = auth.KeystoneV2Credentials(
Sean Dague655e0af2014-05-29 09:00:22 -0400183 username=user,
184 password=pw,
185 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000186 auth_provider_params = {
187 'disable_ssl_certificate_validation':
188 CONF.identity.disable_ssl_certificate_validation,
189 'ca_certs': CONF.identity.ca_certificates_file,
190 'trace_requests': CONF.debug.trace_requests
191 }
andreafb8a52282015-03-19 22:21:54 +0000192 _auth = auth.KeystoneV2AuthProvider(
Andrea Frittoli90012352015-02-25 21:58:02 +0000193 _creds, CONF.identity.uri, **auth_provider_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000194 self.identity = identity_client.IdentityClient(
ghanshyamd26b5cd2015-02-09 14:48:58 +0900195 _auth,
196 CONF.identity.catalog_type,
197 CONF.identity.region,
198 endpoint_type='adminURL',
199 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000200 self.servers = servers_client.ServersClient(_auth,
201 **compute_params)
202 self.flavors = flavors_client.FlavorsClient(_auth,
203 **compute_params)
204 self.floating_ips = floating_ips_client.FloatingIPsClient(
Emilien Macchic3e3e292015-03-11 17:42:08 -0400205 _auth, **compute_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000206 self.secgroups = security_groups_client.SecurityGroupsClient(
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000207 _auth, **compute_params)
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000208 self.secrules = security_group_rules_client.SecurityGroupRulesClient(
209 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000210 self.objects = object_client.ObjectClient(_auth,
211 **object_storage_params)
212 self.containers = container_client.ContainerClient(
213 _auth, **object_storage_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000214 self.images = image_client.ImageClientV2(
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900215 _auth,
216 CONF.image.catalog_type,
217 CONF.image.region or CONF.identity.region,
218 endpoint_type=CONF.image.endpoint_type,
219 build_interval=CONF.image.build_interval,
220 build_timeout=CONF.image.build_timeout,
221 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000222 self.telemetry = telemetry_client.TelemetryClient(
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000223 _auth,
224 CONF.telemetry.catalog_type,
225 CONF.identity.region,
226 endpoint_type=CONF.telemetry.endpoint_type,
227 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000228 self.volumes = volumes_client.VolumesClient(
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000229 _auth,
230 CONF.volume.catalog_type,
231 CONF.volume.region or CONF.identity.region,
232 endpoint_type=CONF.volume.endpoint_type,
233 build_interval=CONF.volume.build_interval,
234 build_timeout=CONF.volume.build_timeout,
235 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000236 self.networks = network_client.NetworkClient(
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000237 _auth,
238 CONF.network.catalog_type,
239 CONF.network.region or CONF.identity.region,
240 endpoint_type=CONF.network.endpoint_type,
241 build_interval=CONF.network.build_interval,
242 build_timeout=CONF.network.build_timeout,
243 **default_params)
John Warren3961acd2015-10-02 14:38:53 -0400244 self.subnets = subnets_client.SubnetsClient(
245 _auth,
246 CONF.network.catalog_type,
247 CONF.network.region or CONF.identity.region,
248 endpoint_type=CONF.network.endpoint_type,
249 build_interval=CONF.network.build_interval,
250 build_timeout=CONF.network.build_timeout,
251 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400252
253
254def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100255 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400256 return yaml.load(open(fname, 'r'))
257
258
259def keystone_admin():
260 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
261
262
263def client_for_user(name):
264 LOG.debug("Entering client_for_user")
265 if name in USERS:
266 user = USERS[name]
267 LOG.debug("Created client for user %s" % user)
268 return OSClient(user['name'], user['pass'], user['tenant'])
269 else:
270 LOG.error("%s not found in USERS: %s" % (name, USERS))
271
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200272
Sean Dague655e0af2014-05-29 09:00:22 -0400273###################
274#
275# TENANTS
276#
277###################
278
279
280def create_tenants(tenants):
281 """Create tenants from resource definition.
282
283 Don't create the tenants if they already exist.
284 """
285 admin = keystone_admin()
John Warrenacf00512015-08-06 16:13:58 -0400286 body = admin.identity.list_tenants()['tenants']
Sean Dague655e0af2014-05-29 09:00:22 -0400287 existing = [x['name'] for x in body]
288 for tenant in tenants:
289 if tenant not in existing:
Anusha Ramineni0cfb4612015-08-24 08:49:10 +0530290 admin.identity.create_tenant(tenant)['tenant']
Sean Dague655e0af2014-05-29 09:00:22 -0400291 else:
292 LOG.warn("Tenant '%s' already exists in this environment" % tenant)
293
Emilien Macchibb71e072014-07-05 19:18:52 +0200294
295def destroy_tenants(tenants):
296 admin = keystone_admin()
297 for tenant in tenants:
298 tenant_id = admin.identity.get_tenant_by_name(tenant)['id']
David Kranzb7afa922014-12-30 10:56:26 -0500299 admin.identity.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200300
Sean Dague655e0af2014-05-29 09:00:22 -0400301##############
302#
303# USERS
304#
305##############
306
307
308def _users_for_tenant(users, tenant):
309 u_for_t = []
310 for user in users:
311 for n in user:
312 if user[n]['tenant'] == tenant:
313 u_for_t.append(user[n])
314 return u_for_t
315
316
317def _tenants_from_users(users):
318 tenants = set()
319 for user in users:
320 for n in user:
321 tenants.add(user[n]['tenant'])
322 return tenants
323
324
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200325def _assign_swift_role(user, swift_role):
Sean Dague655e0af2014-05-29 09:00:22 -0400326 admin = keystone_admin()
David Kranzb7afa922014-12-30 10:56:26 -0500327 roles = admin.identity.list_roles()
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200328 role = next(r for r in roles if r['name'] == swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400329 LOG.debug(USERS[user])
330 try:
331 admin.identity.assign_user_role(
332 USERS[user]['tenant_id'],
333 USERS[user]['id'],
334 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900335 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400336 # don't care if it's already assigned
337 pass
338
339
340def create_users(users):
341 """Create tenants from resource definition.
342
343 Don't create the tenants if they already exist.
344 """
345 global USERS
346 LOG.info("Creating users")
347 admin = keystone_admin()
348 for u in users:
349 try:
350 tenant = admin.identity.get_tenant_by_name(u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900351 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400352 LOG.error("Tenant: %s - not found" % u['tenant'])
353 continue
354 try:
355 admin.identity.get_user_by_username(tenant['id'], u['name'])
356 LOG.warn("User '%s' already exists in this environment"
357 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900358 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400359 admin.identity.create_user(
360 u['name'], u['pass'], tenant['id'],
361 "%s@%s" % (u['name'], tenant['id']),
362 enabled=True)
363
364
Emilien Macchibb71e072014-07-05 19:18:52 +0200365def destroy_users(users):
366 admin = keystone_admin()
367 for user in users:
Emilien Macchi436de862014-09-30 17:09:50 -0400368 tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
369 user_id = admin.identity.get_user_by_username(tenant_id,
370 user['name'])['id']
David Kranzb7afa922014-12-30 10:56:26 -0500371 admin.identity.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200372
373
Sean Dague655e0af2014-05-29 09:00:22 -0400374def collect_users(users):
375 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200376 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400377 admin = keystone_admin()
378 for u in users:
379 tenant = admin.identity.get_tenant_by_name(u['tenant'])
380 u['tenant_id'] = tenant['id']
381 USERS[u['name']] = u
382 body = admin.identity.get_user_by_username(tenant['id'], u['name'])
383 USERS[u['name']]['id'] = body['id']
384
385
386class JavelinCheck(unittest.TestCase):
387 def __init__(self, users, resources):
388 super(JavelinCheck, self).__init__()
389 self.users = users
390 self.res = resources
391
392 def runTest(self, *args):
393 pass
394
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200395 def _ping_ip(self, ip_addr, count, namespace=None):
396 if namespace is None:
397 ping_cmd = "ping -c1 " + ip_addr
398 else:
399 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
400 ip_addr)
401 for current in range(count):
402 return_code = os.system(ping_cmd)
403 if return_code is 0:
404 break
405 self.assertNotEqual(current, count - 1,
406 "Server is not pingable at %s" % ip_addr)
407
Sean Dague655e0af2014-05-29 09:00:22 -0400408 def check(self):
409 self.check_users()
410 self.check_objects()
411 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400412 self.check_volumes()
Chris Dent878f3782014-06-30 17:04:15 +0100413 self.check_telemetry()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200414 self.check_secgroups()
415
416 # validate neutron is enabled and ironic disabled:
417 # Tenant network isolation is not supported when using ironic.
418 # "admin" has set up a neutron flat network environment within a shared
419 # fixed network for all tenants to use.
420 # In this case, network/subnet/router creation can be skipped and the
421 # server booted the same as nova network.
422 if (CONF.service_available.neutron and
423 not CONF.baremetal.driver_enabled):
424 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400425
426 def check_users(self):
427 """Check that the users we expect to exist, do.
428
429 We don't use the resource list for this because we need to validate
430 that things like tenantId didn't drift across versions.
431 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200432 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400433 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400434 client = keystone_admin()
Ken'ichi Ohmichi402b8752015-11-09 10:47:16 +0000435 found = client.identity.show_user(user['id'])['user']
Sean Dague655e0af2014-05-29 09:00:22 -0400436 self.assertEqual(found['name'], user['name'])
437 self.assertEqual(found['tenantId'], user['tenant_id'])
438
439 # also ensure we can auth with that user, and do something
440 # on the cloud. We don't care about the results except that it
441 # remains authorized.
442 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500443 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400444
445 def check_objects(self):
446 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000447 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000448 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200449 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400450 for obj in self.res['objects']:
451 client = client_for_user(obj['owner'])
452 r, contents = client.objects.get_object(
453 obj['container'], obj['name'])
454 source = _file_contents(obj['file'])
455 self.assertEqual(contents, source)
456
457 def check_servers(self):
458 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000459 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000460 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200461 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400462 for server in self.res['servers']:
463 client = client_for_user(server['owner'])
464 found = _get_server_by_name(client, server['name'])
465 self.assertIsNotNone(
466 found,
467 "Couldn't find expected server %s" % server['name'])
468
ghanshyam0f825252015-08-25 16:02:50 +0900469 found = client.servers.show_server(found['id'])['server']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200470 # validate neutron is enabled and ironic disabled:
471 if (CONF.service_available.neutron and
472 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400473 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200474 for network_name, body in found['addresses'].items():
475 for addr in body:
476 ip = addr['addr']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400477 # If floatingip_for_ssh is at True, it's assumed
478 # you want to use the floating IP to reach the server,
479 # fallback to fixed IP, then other type.
480 # This is useful in multi-node environment.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700481 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400482 if addr.get('OS-EXT-IPS:type',
483 'floating') == 'floating':
484 self._ping_ip(ip, 60)
485 _floating_is_alive = True
486 elif addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200487 namespace = _get_router_namespace(client,
488 network_name)
489 self._ping_ip(ip, 60, namespace)
490 else:
491 self._ping_ip(ip, 60)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400492 # if floatingip_for_ssh is at True, validate found a
493 # floating IP and ping worked.
armando-migliaccio2a5ac822015-03-13 19:49:55 -0700494 if CONF.compute.use_floatingip_for_ssh:
Emilien Macchic3e3e292015-03-11 17:42:08 -0400495 self.assertTrue(_floating_is_alive,
496 "Server %s has no floating IP." %
497 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200498 else:
499 addr = found['addresses']['private'][0]['addr']
500 self._ping_ip(addr, 60)
501
502 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100503 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200504 LOG.info("Checking security groups")
505 for secgroup in self.res['secgroups']:
506 client = client_for_user(secgroup['owner'])
507 found = _get_resource_by_name(client.secgroups, 'security_groups',
508 secgroup['name'])
509 self.assertIsNotNone(
510 found,
511 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400512
Chris Dent878f3782014-06-30 17:04:15 +0100513 def check_telemetry(self):
514 """Check that ceilometer provides a sane sample.
515
nayna-patel1dfbedb2015-08-04 11:07:56 +0000516 Confirm that there is more than one sample and that they have the
Chris Dent878f3782014-06-30 17:04:15 +0100517 expected metadata.
518
519 If in check mode confirm that the oldest sample available is from
520 before the upgrade.
521 """
Chris Dent0b76f2f2014-10-10 14:24:28 +0100522 if not self.res.get('telemetry'):
523 return
Chris Dent878f3782014-06-30 17:04:15 +0100524 LOG.info("checking telemetry")
525 for server in self.res['servers']:
526 client = client_for_user(server['owner'])
David Kranz20d06f42015-02-09 14:54:15 -0500527 body = client.telemetry.list_samples(
Chris Dent878f3782014-06-30 17:04:15 +0100528 'instance',
529 query=('metadata.display_name', 'eq', server['name'])
530 )
Chris Dent878f3782014-06-30 17:04:15 +0100531 self.assertTrue(len(body) >= 1, 'expecting at least one sample')
532 self._confirm_telemetry_sample(server, body[-1])
533
Emilien Macchi626b4f82014-06-15 21:44:29 +0200534 def check_volumes(self):
535 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000536 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000537 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200538 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200539 for volume in self.res['volumes']:
540 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400541 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200542 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400543 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200544 "Couldn't find expected volume %s" % volume['name'])
545
546 # Verify that a volume's attachment retrieved
547 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400548 attachment = client.volumes.get_attachment_from_volume(vol_body)
549 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200550 self.assertEqual(server_id, attachment['server_id'])
551
Chris Dent878f3782014-06-30 17:04:15 +0100552 def _confirm_telemetry_sample(self, server, sample):
553 """Check this sample matches the expected resource metadata."""
554 # Confirm display_name
555 self.assertEqual(server['name'],
556 sample['resource_metadata']['display_name'])
557 # Confirm instance_type of flavor
558 flavor = sample['resource_metadata'].get(
559 'flavor.name',
560 sample['resource_metadata'].get('instance_type')
561 )
562 self.assertEqual(server['flavor'], flavor)
563 # Confirm the oldest sample was created before upgrade.
564 if OPTS.mode == 'check':
565 oldest_timestamp = timeutils.normalize_time(
566 timeutils.parse_isotime(sample['timestamp']))
567 self.assertTrue(
568 oldest_timestamp < JAVELIN_START,
569 'timestamp should come before start of second javelin run'
570 )
571
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200572 def check_networking(self):
573 """Check that the networks are still there."""
574 for res_type in ('networks', 'subnets', 'routers'):
575 for res in self.res[res_type]:
576 client = client_for_user(res['owner'])
577 found = _get_resource_by_name(client.networks, res_type,
578 res['name'])
579 self.assertIsNotNone(
580 found,
581 "Couldn't find expected resource %s" % res['name'])
582
Sean Dague655e0af2014-05-29 09:00:22 -0400583
584#######################
585#
586# OBJECTS
587#
588#######################
589
590
591def _file_contents(fname):
592 with open(fname, 'r') as f:
593 return f.read()
594
595
596def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000597 if not objects:
598 return
Sean Dague655e0af2014-05-29 09:00:22 -0400599 LOG.info("Creating objects")
600 for obj in objects:
601 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200602 swift_role = obj.get('swift_role', 'Member')
603 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400604 client = client_for_user(obj['owner'])
605 client.containers.create_container(obj['container'])
606 client.objects.create_object(
607 obj['container'], obj['name'],
608 _file_contents(obj['file']))
609
Emilien Macchibb71e072014-07-05 19:18:52 +0200610
611def destroy_objects(objects):
612 for obj in objects:
613 client = client_for_user(obj['owner'])
614 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400615 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200616 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
617
618
Sean Dague655e0af2014-05-29 09:00:22 -0400619#######################
620#
621# IMAGES
622#
623#######################
624
625
Sean Dague319b37a2014-07-11 07:28:11 -0400626def _resolve_image(image, imgtype):
627 name = image[imgtype]
628 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
629 return name, fname
630
631
Joe Gordon6f0426c2014-07-25 01:10:28 +0000632def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000633 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000634 for image in body:
635 if name == image['name']:
636 return image
637 return None
638
639
Sean Dague655e0af2014-05-29 09:00:22 -0400640def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000641 if not images:
642 return
Joe Gordona18d6862014-07-24 22:55:46 +0000643 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400644 for image in images:
645 client = client_for_user(image['owner'])
646
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100647 # DEPRECATED: 'format' was used for ami images
648 # Use 'disk_format' and 'container_format' instead
649 if 'format' in image:
650 LOG.warning("Deprecated: 'format' is deprecated for images "
651 "description. Please use 'disk_format' and 'container_"
652 "format' instead.")
653 image['disk_format'] = image['format']
654 image['container_format'] = image['format']
655
Sean Dague655e0af2014-05-29 09:00:22 -0400656 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000657 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000658 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400659 continue
660
661 # special handling for 3 part image
662 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100663 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400664 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500665 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400666 'javelin_' + name, 'aki', 'aki')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000667 client.images.store_image_file(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400668 extras['kernel_id'] = aki.get('id')
669
Sean Dague319b37a2014-07-11 07:28:11 -0400670 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500671 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400672 'javelin_' + name, 'ari', 'ari')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000673 client.images.store_image_file(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400674 extras['ramdisk_id'] = ari.get('id')
675
Sean Dague319b37a2014-07-11 07:28:11 -0400676 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500677 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100678 image['name'], image['container_format'],
679 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400680 image_id = body.get('id')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000681 client.images.store_image_file(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400682
683
Joe Gordon6f0426c2014-07-25 01:10:28 +0000684def destroy_images(images):
685 if not images:
686 return
687 LOG.info("Destroying images")
688 for image in images:
689 client = client_for_user(image['owner'])
690
691 response = _get_image_by_name(client, image['name'])
692 if not response:
nayna-patel1dfbedb2015-08-04 11:07:56 +0000693 LOG.info("Image '%s' does not exist" % image['name'])
Joe Gordon6f0426c2014-07-25 01:10:28 +0000694 continue
695 client.images.delete_image(response['id'])
696
697
Sean Dague655e0af2014-05-29 09:00:22 -0400698#######################
699#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200700# NETWORKS
701#
702#######################
703
704def _get_router_namespace(client, network):
705 network_id = _get_resource_by_name(client.networks,
706 'networks', network)['id']
David Kranz34e88122014-12-11 15:24:05 -0500707 n_body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200708 for router in n_body['routers']:
709 router_id = router['id']
David Kranz34e88122014-12-11 15:24:05 -0500710 r_body = client.networks.list_router_interfaces(router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200711 for port in r_body['ports']:
712 if port['network_id'] == network_id:
713 return "qrouter-%s" % router_id
714
715
716def _get_resource_by_name(client, resource, name):
717 get_resources = getattr(client, 'list_%s' % resource)
718 if get_resources is None:
719 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500720 # Until all tempest client methods are changed to return only one value,
721 # we cannot assume they all have the same signature so we need to discard
722 # the unused response first value it two values are being returned.
723 body = get_resources()
724 if type(body) == tuple:
725 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200726 if isinstance(body, dict):
727 body = body[resource]
728 for res in body:
729 if name == res['name']:
730 return res
731 raise ValueError('%s not found in %s resources' % (name, resource))
732
733
734def create_networks(networks):
735 LOG.info("Creating networks")
736 for network in networks:
737 client = client_for_user(network['owner'])
738
739 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500740 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200741 if any(item['name'] == network['name'] for item in body['networks']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000742 LOG.warning("Duplicated network name: %s" % network['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200743 continue
744
745 client.networks.create_network(name=network['name'])
746
747
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100748def destroy_networks(networks):
749 LOG.info("Destroying subnets")
750 for network in networks:
751 client = client_for_user(network['owner'])
752 network_id = _get_resource_by_name(client.networks, 'networks',
753 network['name'])['id']
754 client.networks.delete_network(network_id)
755
756
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200757def create_subnets(subnets):
758 LOG.info("Creating subnets")
759 for subnet in subnets:
760 client = client_for_user(subnet['owner'])
761
762 network = _get_resource_by_name(client.networks, 'networks',
763 subnet['network'])
764 ip_version = netaddr.IPNetwork(subnet['range']).version
765 # ensure we don't overlap with another subnet in the network
766 try:
767 client.networks.create_subnet(network_id=network['id'],
768 cidr=subnet['range'],
769 name=subnet['name'],
770 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900771 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200772 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
773 if not is_overlapping_cidr:
774 raise
775
776
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100777def destroy_subnets(subnets):
778 LOG.info("Destroying subnets")
779 for subnet in subnets:
780 client = client_for_user(subnet['owner'])
John Warren3961acd2015-10-02 14:38:53 -0400781 subnet_id = _get_resource_by_name(client.subnets,
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100782 'subnets', subnet['name'])['id']
John Warren3961acd2015-10-02 14:38:53 -0400783 client.subnets.delete_subnet(subnet_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100784
785
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200786def create_routers(routers):
787 LOG.info("Creating routers")
788 for router in routers:
789 client = client_for_user(router['owner'])
790
791 # only create a router if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500792 body = client.networks.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200793 if any(item['name'] == router['name'] for item in body['routers']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000794 LOG.warning("Duplicated router name: %s" % router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200795 continue
796
797 client.networks.create_router(router['name'])
798
799
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100800def destroy_routers(routers):
801 LOG.info("Destroying 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 for subnet in router['subnet']:
807 subnet_id = _get_resource_by_name(client.networks,
808 'subnets', subnet)['id']
809 client.networks.remove_router_interface_with_subnet_id(router_id,
810 subnet_id)
811 client.networks.delete_router(router_id)
812
813
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200814def add_router_interface(routers):
815 for router in routers:
816 client = client_for_user(router['owner'])
817 router_id = _get_resource_by_name(client.networks,
818 'routers', router['name'])['id']
819
820 for subnet in router['subnet']:
821 subnet_id = _get_resource_by_name(client.networks,
822 'subnets', subnet)['id']
823 # connect routers to their subnets
824 client.networks.add_router_interface_with_subnet_id(router_id,
825 subnet_id)
nayna-patel1dfbedb2015-08-04 11:07:56 +0000826 # connect routers to external network if set to "gateway"
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200827 if router['gateway']:
828 if CONF.network.public_network_id:
829 ext_net = CONF.network.public_network_id
830 client.networks._update_router(
831 router_id, set_enable_snat=True,
832 external_gateway_info={"network_id": ext_net})
833 else:
834 raise ValueError('public_network_id is not configured.')
835
836
837#######################
838#
Sean Dague655e0af2014-05-29 09:00:22 -0400839# SERVERS
840#
841#######################
842
843def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500844 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400845 for server in body['servers']:
846 if name == server['name']:
847 return server
848 return None
849
850
Sean Dague655e0af2014-05-29 09:00:22 -0400851def _get_flavor_by_name(client, name):
ghanshyam19973be2015-08-18 15:46:42 +0900852 body = client.flavors.list_flavors()['flavors']
Sean Dague655e0af2014-05-29 09:00:22 -0400853 for flavor in body:
854 if name == flavor['name']:
855 return flavor
856 return None
857
858
859def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000860 if not servers:
861 return
Joe Gordona18d6862014-07-24 22:55:46 +0000862 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400863 for server in servers:
864 client = client_for_user(server['owner'])
865
866 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000867 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400868 continue
869
870 image_id = _get_image_by_name(client, server['image'])['id']
871 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200872 # validate neutron is enabled and ironic disabled
873 kwargs = dict()
874 if (CONF.service_available.neutron and
875 not CONF.baremetal.driver_enabled and server.get('networks')):
876 get_net_id = lambda x: (_get_resource_by_name(
877 client.networks, 'networks', x)['id'])
878 kwargs['networks'] = [{'uuid': get_net_id(network)}
879 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500880 body = client.servers.create_server(
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000881 name=server['name'], imageRef=image_id, flavorRef=flavor_id,
882 **kwargs)['server']
Joe Gordon10f260b2014-07-24 23:27:19 +0000883 server_id = body['id']
884 client.servers.wait_for_server_status(server_id, 'ACTIVE')
nayna-patel1dfbedb2015-08-04 11:07:56 +0000885 # create security group(s) after server spawning
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200886 for secgroup in server['secgroups']:
887 client.servers.add_security_group(server_id, secgroup)
Emilien Macchic3e3e292015-03-11 17:42:08 -0400888 if CONF.compute.use_floatingip_for_ssh:
Joe H. Rahme9350a102015-03-29 17:39:20 +0200889 floating_ip_pool = server.get('floating_ip_pool')
890 floating_ip = client.floating_ips.create_floating_ip(
ghanshyam9a3a9a22015-08-18 17:03:55 +0900891 pool_name=floating_ip_pool)['floating_ip']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400892 client.floating_ips.associate_floating_ip_to_server(
893 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400894
895
Joe Gordondb63b1c2014-07-24 23:21:21 +0000896def destroy_servers(servers):
897 if not servers:
898 return
899 LOG.info("Destroying servers")
900 for server in servers:
901 client = client_for_user(server['owner'])
902
Emilien Macchidc5bae22015-03-16 08:49:02 -0400903 response = _get_server_by_name(client, server['name'])
904 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000905 LOG.info("Server '%s' does not exist" % server['name'])
906 continue
907
Emilien Macchidc5bae22015-03-16 08:49:02 -0400908 # TODO(EmilienM): disassociate floating IP from server and release it.
909 client.servers.delete_server(response['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000910 waiters.wait_for_server_termination(client.servers, response['id'],
911 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000912
913
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200914def create_secgroups(secgroups):
915 LOG.info("Creating security groups")
916 for secgroup in secgroups:
917 client = client_for_user(secgroup['owner'])
918
919 # only create a security group if the name isn't here
920 # i.e. a security group may be used by another server
921 # only create a router if the name isn't here
ghanshyamb610b772015-08-24 17:29:38 +0900922 body = client.secgroups.list_security_groups()['security_groups']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200923 if any(item['name'] == secgroup['name'] for item in body):
924 LOG.warning("Security group '%s' already exists" %
925 secgroup['name'])
926 continue
927
David Kranz9964b4e2015-02-06 15:45:29 -0500928 body = client.secgroups.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900929 name=secgroup['name'],
930 description=secgroup['description'])['security_group']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200931 secgroup_id = body['id']
932 # for each security group, create the rules
933 for rule in secgroup['rules']:
934 ip_proto, from_port, to_port, cidr = rule.split()
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000935 client.secrules.create_security_group_rule(
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000936 parent_group_id=secgroup_id, ip_protocol=ip_proto,
937 from_port=from_port, to_port=to_port, cidr=cidr)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200938
939
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100940def destroy_secgroups(secgroups):
941 LOG.info("Destroying security groups")
942 for secgroup in secgroups:
943 client = client_for_user(secgroup['owner'])
944 sg_id = _get_resource_by_name(client.secgroups,
945 'security_groups',
946 secgroup['name'])
947 # sg rules are deleted automatically
948 client.secgroups.delete_security_group(sg_id['id'])
949
950
Sean Dague655e0af2014-05-29 09:00:22 -0400951#######################
952#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200953# VOLUMES
954#
955#######################
956
957def _get_volume_by_name(client, name):
John Warren6177c9e2015-08-19 20:00:17 +0000958 body = client.volumes.list_volumes()['volumes']
Emilien Macchid18fec12014-09-15 14:32:54 -0400959 for volume in body:
960 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200961 return volume
962 return None
963
964
965def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100966 if not volumes:
967 return
968 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200969 for volume in volumes:
970 client = client_for_user(volume['owner'])
971
972 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400973 if _get_volume_by_name(client, volume['name']):
974 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200975 continue
976
Emilien Macchid18fec12014-09-15 14:32:54 -0400977 size = volume['gb']
978 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000979 body = client.volumes.create_volume(size=size,
John Warren6177c9e2015-08-19 20:00:17 +0000980 display_name=v_name)['volume']
Emilien Macchid18fec12014-09-15 14:32:54 -0400981 client.volumes.wait_for_volume_status(body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200982
983
Emilien Macchibb71e072014-07-05 19:18:52 +0200984def destroy_volumes(volumes):
985 for volume in volumes:
986 client = client_for_user(volume['owner'])
987 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400988 client.volumes.detach_volume(volume_id)
989 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200990
991
Emilien Macchi626b4f82014-06-15 21:44:29 +0200992def attach_volumes(volumes):
993 for volume in volumes:
994 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200995 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400996 volume_id = _get_volume_by_name(client, volume['name'])['id']
997 device = volume['device']
998 client.volumes.attach_volume(volume_id, server_id, device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200999
1000
1001#######################
1002#
Sean Dague655e0af2014-05-29 09:00:22 -04001003# MAIN LOGIC
1004#
1005#######################
1006
1007def create_resources():
1008 LOG.info("Creating Resources")
1009 # first create keystone level resources, and we need to be admin
nayna-patel1dfbedb2015-08-04 11:07:56 +00001010 # for this.
Sean Dague655e0af2014-05-29 09:00:22 -04001011 create_tenants(RES['tenants'])
1012 create_users(RES['users'])
1013 collect_users(RES['users'])
1014
1015 # next create resources in a well known order
1016 create_objects(RES['objects'])
1017 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001018
1019 # validate neutron is enabled and ironic is disabled
1020 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1021 create_networks(RES['networks'])
1022 create_subnets(RES['subnets'])
1023 create_routers(RES['routers'])
1024 add_router_interface(RES['routers'])
1025
1026 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001027 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001028
1029 # Only attempt attaching the volumes if servers are defined in the
nayna-patel1dfbedb2015-08-04 11:07:56 +00001030 # resource file
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001031 if 'servers' in RES:
1032 create_servers(RES['servers'])
1033 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001034
1035
Joe Gordondb63b1c2014-07-24 23:21:21 +00001036def destroy_resources():
1037 LOG.info("Destroying Resources")
1038 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001039 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001040 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001041 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001042 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001043 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1044 destroy_routers(RES['routers'])
1045 destroy_subnets(RES['subnets'])
1046 destroy_networks(RES['networks'])
1047 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001048 destroy_users(RES['users'])
1049 destroy_tenants(RES['tenants'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001050 LOG.warn("Destroy mode incomplete")
1051
Joe Gordondb63b1c2014-07-24 23:21:21 +00001052
Sean Dague655e0af2014-05-29 09:00:22 -04001053def get_options():
1054 global OPTS
1055 parser = argparse.ArgumentParser(
1056 description='Create and validate a fixed set of OpenStack resources')
1057 parser.add_argument('-m', '--mode',
1058 metavar='<create|check|destroy>',
1059 required=True,
1060 help=('One of (create, check, destroy)'))
1061 parser.add_argument('-r', '--resources',
1062 required=True,
1063 metavar='resourcefile.yaml',
1064 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001065
Sean Dague319b37a2014-07-11 07:28:11 -04001066 parser.add_argument(
1067 '-d', '--devstack-base',
1068 required=True,
1069 metavar='/opt/stack/old',
1070 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001071 parser.add_argument(
1072 '-c', '--config-file',
1073 metavar='/etc/tempest.conf',
1074 help='path to javelin2(tempest) config file')
1075
Sean Dague655e0af2014-05-29 09:00:22 -04001076 # auth bits, letting us also just source the devstack openrc
1077 parser.add_argument('--os-username',
1078 metavar='<auth-user-name>',
1079 default=os.environ.get('OS_USERNAME'),
1080 help=('Defaults to env[OS_USERNAME].'))
1081 parser.add_argument('--os-password',
1082 metavar='<auth-password>',
1083 default=os.environ.get('OS_PASSWORD'),
1084 help=('Defaults to env[OS_PASSWORD].'))
1085 parser.add_argument('--os-tenant-name',
1086 metavar='<auth-tenant-name>',
1087 default=os.environ.get('OS_TENANT_NAME'),
1088 help=('Defaults to env[OS_TENANT_NAME].'))
1089
1090 OPTS = parser.parse_args()
1091 if OPTS.mode not in ('create', 'check', 'destroy'):
1092 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1093 parser.print_help()
1094 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001095 if OPTS.config_file:
1096 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001097
1098
Joe Gordon915eb8e2014-07-17 11:25:46 +02001099def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001100 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001101 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001102 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001103
1104
1105def main():
1106 global RES
1107 get_options()
1108 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001109 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001110
1111 if OPTS.mode == 'create':
1112 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001113 # Make sure the resources we just created actually work
1114 checker = JavelinCheck(USERS, RES)
1115 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001116 elif OPTS.mode == 'check':
1117 collect_users(RES['users'])
1118 checker = JavelinCheck(USERS, RES)
1119 checker.check()
1120 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001121 collect_users(RES['users'])
1122 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001123 else:
1124 LOG.error('Unknown mode %s' % OPTS.mode)
1125 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001126 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001127 return 0
1128
1129if __name__ == "__main__":
1130 sys.exit(main())