blob: 9b3cac7cc70ad88040c34ccabea63fe636ea9734 [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
Matthew Treinish71426682015-04-23 11:19:38 -0400116import six
Matthew Treinish96e9e882014-06-09 18:37:19 -0400117import yaml
Sean Dague655e0af2014-05-29 09:00:22 -0400118
Ken'ichi Ohmichi6ea3f982015-11-09 12:41:13 +0000119from tempest.common import identity
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000120from tempest.common import waiters
Joe Gordon28a84ae2014-07-17 15:38:28 +0000121from tempest import config
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500122from tempest.lib import auth
123from tempest.lib import exceptions as lib_exc
124from tempest.lib.services.compute import flavors_client
125from tempest.lib.services.compute import floating_ips_client
126from tempest.lib.services.compute import security_group_rules_client
127from tempest.lib.services.compute import security_groups_client
128from tempest.lib.services.compute import servers_client
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700129from tempest.lib.services.network import networks_client
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700130from tempest.lib.services.network import ports_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500131from tempest.lib.services.network import subnets_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100132from tempest.services.identity.v2.json import identity_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000133from tempest.services.identity.v2.json import roles_client
Daniel Melladob04da902015-11-20 17:43:12 +0100134from tempest.services.identity.v2.json import tenants_client
Daniel Mellado82c83a52015-12-09 15:16:49 +0000135from tempest.services.identity.v2.json import users_client
Ken'ichi Ohmichi69dcf442015-11-30 11:48:01 +0000136from tempest.services.image.v2.json import images_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000137from tempest.services.network.json import routers_client
Sean Dague655e0af2014-05-29 09:00:22 -0400138from tempest.services.object_storage import container_client
139from tempest.services.object_storage import object_client
Yaroslav Lobankovdb4a2e12015-11-28 20:04:54 +0300140from tempest.services.volume.v1.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400141
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200142CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400143OPTS = {}
144USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100145RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400146
147LOG = None
148
Chris Dent878f3782014-06-30 17:04:15 +0100149JAVELIN_START = datetime.datetime.utcnow()
150
Sean Dague655e0af2014-05-29 09:00:22 -0400151
152class OSClient(object):
153 _creds = None
154 identity = None
155 servers = None
156
157 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000158 default_params = {
159 'disable_ssl_certificate_validation':
160 CONF.identity.disable_ssl_certificate_validation,
161 'ca_certs': CONF.identity.ca_certificates_file,
162 'trace_requests': CONF.debug.trace_requests
163 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000164 default_params_with_timeout_values = {
165 'build_interval': CONF.compute.build_interval,
166 'build_timeout': CONF.compute.build_timeout
167 }
168 default_params_with_timeout_values.update(default_params)
169
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000170 compute_params = {
171 'service': CONF.compute.catalog_type,
172 'region': CONF.compute.region or CONF.identity.region,
173 'endpoint_type': CONF.compute.endpoint_type,
174 'build_interval': CONF.compute.build_interval,
175 'build_timeout': CONF.compute.build_timeout
176 }
177 compute_params.update(default_params)
178
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000179 object_storage_params = {
180 'service': CONF.object_storage.catalog_type,
181 'region': CONF.object_storage.region or CONF.identity.region,
182 'endpoint_type': CONF.object_storage.endpoint_type
183 }
184 object_storage_params.update(default_params)
185
andreafb8a52282015-03-19 22:21:54 +0000186 _creds = auth.KeystoneV2Credentials(
Sean Dague655e0af2014-05-29 09:00:22 -0400187 username=user,
188 password=pw,
189 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000190 auth_provider_params = {
191 'disable_ssl_certificate_validation':
192 CONF.identity.disable_ssl_certificate_validation,
193 'ca_certs': CONF.identity.ca_certificates_file,
194 'trace_requests': CONF.debug.trace_requests
195 }
andreafb8a52282015-03-19 22:21:54 +0000196 _auth = auth.KeystoneV2AuthProvider(
Andrea Frittoli90012352015-02-25 21:58:02 +0000197 _creds, CONF.identity.uri, **auth_provider_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000198 self.identity = identity_client.IdentityClient(
ghanshyamd26b5cd2015-02-09 14:48:58 +0900199 _auth,
200 CONF.identity.catalog_type,
201 CONF.identity.region,
202 endpoint_type='adminURL',
203 **default_params_with_timeout_values)
Daniel Melladob04da902015-11-20 17:43:12 +0100204 self.tenants = tenants_client.TenantsClient(
205 _auth,
206 CONF.identity.catalog_type,
207 CONF.identity.region,
208 endpoint_type='adminURL',
209 **default_params_with_timeout_values)
Daniel Mellado6b16b922015-12-07 12:43:08 +0000210 self.roles = roles_client.RolesClient(
211 _auth,
212 CONF.identity.catalog_type,
213 CONF.identity.region,
214 endpoint_type='adminURL',
215 **default_params_with_timeout_values)
Daniel Mellado82c83a52015-12-09 15:16:49 +0000216 self.users = users_client.UsersClient(
217 _auth,
218 CONF.identity.catalog_type,
219 CONF.identity.region,
220 endpoint_type='adminURL',
221 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000222 self.servers = servers_client.ServersClient(_auth,
223 **compute_params)
224 self.flavors = flavors_client.FlavorsClient(_auth,
225 **compute_params)
226 self.floating_ips = floating_ips_client.FloatingIPsClient(
Emilien Macchic3e3e292015-03-11 17:42:08 -0400227 _auth, **compute_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000228 self.secgroups = security_groups_client.SecurityGroupsClient(
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000229 _auth, **compute_params)
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000230 self.secrules = security_group_rules_client.SecurityGroupRulesClient(
231 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000232 self.objects = object_client.ObjectClient(_auth,
233 **object_storage_params)
234 self.containers = container_client.ContainerClient(
235 _auth, **object_storage_params)
Ken'ichi Ohmichi69dcf442015-11-30 11:48:01 +0000236 self.images = images_client.ImagesClientV2(
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900237 _auth,
238 CONF.image.catalog_type,
239 CONF.image.region or CONF.identity.region,
240 endpoint_type=CONF.image.endpoint_type,
241 build_interval=CONF.image.build_interval,
242 build_timeout=CONF.image.build_timeout,
243 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000244 self.volumes = volumes_client.VolumesClient(
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000245 _auth,
246 CONF.volume.catalog_type,
247 CONF.volume.region or CONF.identity.region,
248 endpoint_type=CONF.volume.endpoint_type,
249 build_interval=CONF.volume.build_interval,
250 build_timeout=CONF.volume.build_timeout,
251 **default_params)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700252 self.networks = networks_client.NetworksClient(
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000253 _auth,
254 CONF.network.catalog_type,
255 CONF.network.region or CONF.identity.region,
256 endpoint_type=CONF.network.endpoint_type,
257 build_interval=CONF.network.build_interval,
258 build_timeout=CONF.network.build_timeout,
259 **default_params)
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700260 self.ports = ports_client.PortsClient(
261 _auth,
262 CONF.network.catalog_type,
263 CONF.network.region or CONF.identity.region,
264 endpoint_type=CONF.network.endpoint_type,
265 build_interval=CONF.network.build_interval,
266 build_timeout=CONF.network.build_timeout,
267 **default_params)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000268 self.routers = routers_client.RoutersClient(
269 _auth,
270 CONF.network.catalog_type,
271 CONF.network.region or CONF.identity.region,
272 endpoint_type=CONF.network.endpoint_type,
273 build_interval=CONF.network.build_interval,
274 build_timeout=CONF.network.build_timeout,
275 **default_params)
John Warren3961acd2015-10-02 14:38:53 -0400276 self.subnets = subnets_client.SubnetsClient(
277 _auth,
278 CONF.network.catalog_type,
279 CONF.network.region or CONF.identity.region,
280 endpoint_type=CONF.network.endpoint_type,
281 build_interval=CONF.network.build_interval,
282 build_timeout=CONF.network.build_timeout,
283 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400284
285
286def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100287 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400288 return yaml.load(open(fname, 'r'))
289
290
291def keystone_admin():
292 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
293
294
295def client_for_user(name):
296 LOG.debug("Entering client_for_user")
297 if name in USERS:
298 user = USERS[name]
299 LOG.debug("Created client for user %s" % user)
300 return OSClient(user['name'], user['pass'], user['tenant'])
301 else:
302 LOG.error("%s not found in USERS: %s" % (name, USERS))
303
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200304
Sean Dague655e0af2014-05-29 09:00:22 -0400305###################
306#
307# TENANTS
308#
309###################
310
311
312def create_tenants(tenants):
313 """Create tenants from resource definition.
314
315 Don't create the tenants if they already exist.
316 """
317 admin = keystone_admin()
Daniel Melladob04da902015-11-20 17:43:12 +0100318 body = admin.tenants.list_tenants()['tenants']
Sean Dague655e0af2014-05-29 09:00:22 -0400319 existing = [x['name'] for x in body]
320 for tenant in tenants:
321 if tenant not in existing:
Daniel Melladob04da902015-11-20 17:43:12 +0100322 admin.tenants.create_tenant(tenant)['tenant']
Sean Dague655e0af2014-05-29 09:00:22 -0400323 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000324 LOG.warning("Tenant '%s' already exists in this environment"
325 % tenant)
Sean Dague655e0af2014-05-29 09:00:22 -0400326
Emilien Macchibb71e072014-07-05 19:18:52 +0200327
328def destroy_tenants(tenants):
329 admin = keystone_admin()
330 for tenant in tenants:
Daniel Melladob04da902015-11-20 17:43:12 +0100331 tenant_id = identity.get_tenant_by_name(admin.tenant, tenant)['id']
332 admin.tenants.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200333
Sean Dague655e0af2014-05-29 09:00:22 -0400334##############
335#
336# USERS
337#
338##############
339
340
341def _users_for_tenant(users, tenant):
342 u_for_t = []
343 for user in users:
344 for n in user:
345 if user[n]['tenant'] == tenant:
346 u_for_t.append(user[n])
347 return u_for_t
348
349
350def _tenants_from_users(users):
351 tenants = set()
352 for user in users:
353 for n in user:
354 tenants.add(user[n]['tenant'])
355 return tenants
356
357
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200358def _assign_swift_role(user, swift_role):
Sean Dague655e0af2014-05-29 09:00:22 -0400359 admin = keystone_admin()
Daniel Mellado6b16b922015-12-07 12:43:08 +0000360 roles = admin.roles.list_roles()
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200361 role = next(r for r in roles if r['name'] == swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400362 LOG.debug(USERS[user])
363 try:
Daniel Mellado6b16b922015-12-07 12:43:08 +0000364 admin.roles.assign_user_role(
Sean Dague655e0af2014-05-29 09:00:22 -0400365 USERS[user]['tenant_id'],
366 USERS[user]['id'],
367 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900368 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400369 # don't care if it's already assigned
370 pass
371
372
373def create_users(users):
374 """Create tenants from resource definition.
375
376 Don't create the tenants if they already exist.
377 """
378 global USERS
379 LOG.info("Creating users")
380 admin = keystone_admin()
381 for u in users:
382 try:
Daniel Melladob04da902015-11-20 17:43:12 +0100383 tenant = identity.get_tenant_by_name(admin.tenants, u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900384 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400385 LOG.error("Tenant: %s - not found" % u['tenant'])
386 continue
387 try:
Daniel Mellado82c83a52015-12-09 15:16:49 +0000388 identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000389 tenant['id'], u['name'])
zhangguoqing6c096642016-01-04 06:17:21 +0000390 LOG.warning("User '%s' already exists in this environment"
391 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900392 except lib_exc.NotFound:
Daniel Mellado82c83a52015-12-09 15:16:49 +0000393 admin.users.create_user(
Sean Dague655e0af2014-05-29 09:00:22 -0400394 u['name'], u['pass'], tenant['id'],
395 "%s@%s" % (u['name'], tenant['id']),
396 enabled=True)
397
398
Emilien Macchibb71e072014-07-05 19:18:52 +0200399def destroy_users(users):
400 admin = keystone_admin()
401 for user in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100402 tenant_id = identity.get_tenant_by_name(admin.tenants,
Ken'ichi Ohmichi6ea3f982015-11-09 12:41:13 +0000403 user['tenant'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000404 user_id = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000405 tenant_id, user['name'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000406 admin.users.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200407
408
Sean Dague655e0af2014-05-29 09:00:22 -0400409def collect_users(users):
410 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200411 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400412 admin = keystone_admin()
413 for u in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100414 tenant = identity.get_tenant_by_name(admin.tenants, u['tenant'])
Sean Dague655e0af2014-05-29 09:00:22 -0400415 u['tenant_id'] = tenant['id']
416 USERS[u['name']] = u
Daniel Mellado82c83a52015-12-09 15:16:49 +0000417 body = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000418 tenant['id'], u['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400419 USERS[u['name']]['id'] = body['id']
420
421
422class JavelinCheck(unittest.TestCase):
423 def __init__(self, users, resources):
424 super(JavelinCheck, self).__init__()
425 self.users = users
426 self.res = resources
427
428 def runTest(self, *args):
429 pass
430
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200431 def _ping_ip(self, ip_addr, count, namespace=None):
432 if namespace is None:
433 ping_cmd = "ping -c1 " + ip_addr
434 else:
435 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
436 ip_addr)
437 for current in range(count):
438 return_code = os.system(ping_cmd)
439 if return_code is 0:
440 break
441 self.assertNotEqual(current, count - 1,
442 "Server is not pingable at %s" % ip_addr)
443
Sean Dague655e0af2014-05-29 09:00:22 -0400444 def check(self):
445 self.check_users()
446 self.check_objects()
447 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400448 self.check_volumes()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200449 self.check_secgroups()
450
451 # validate neutron is enabled and ironic disabled:
452 # Tenant network isolation is not supported when using ironic.
453 # "admin" has set up a neutron flat network environment within a shared
454 # fixed network for all tenants to use.
455 # In this case, network/subnet/router creation can be skipped and the
456 # server booted the same as nova network.
457 if (CONF.service_available.neutron and
458 not CONF.baremetal.driver_enabled):
459 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400460
461 def check_users(self):
462 """Check that the users we expect to exist, do.
463
464 We don't use the resource list for this because we need to validate
465 that things like tenantId didn't drift across versions.
466 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200467 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400468 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400469 client = keystone_admin()
Daniel Mellado82c83a52015-12-09 15:16:49 +0000470 found = client.users.show_user(user['id'])['user']
Sean Dague655e0af2014-05-29 09:00:22 -0400471 self.assertEqual(found['name'], user['name'])
472 self.assertEqual(found['tenantId'], user['tenant_id'])
473
474 # also ensure we can auth with that user, and do something
475 # on the cloud. We don't care about the results except that it
476 # remains authorized.
477 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500478 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400479
480 def check_objects(self):
481 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000482 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000483 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200484 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400485 for obj in self.res['objects']:
486 client = client_for_user(obj['owner'])
487 r, contents = client.objects.get_object(
488 obj['container'], obj['name'])
489 source = _file_contents(obj['file'])
490 self.assertEqual(contents, source)
491
492 def check_servers(self):
493 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000494 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000495 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200496 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400497 for server in self.res['servers']:
498 client = client_for_user(server['owner'])
499 found = _get_server_by_name(client, server['name'])
500 self.assertIsNotNone(
501 found,
502 "Couldn't find expected server %s" % server['name'])
503
ghanshyam0f825252015-08-25 16:02:50 +0900504 found = client.servers.show_server(found['id'])['server']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200505 # validate neutron is enabled and ironic disabled:
506 if (CONF.service_available.neutron and
507 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400508 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200509 for network_name, body in found['addresses'].items():
510 for addr in body:
511 ip = addr['addr']
lanoux283273b2015-12-04 03:01:54 -0800512 # Use floating IP, fixed IP or other type to
513 # reach the server.
Emilien Macchic3e3e292015-03-11 17:42:08 -0400514 # This is useful in multi-node environment.
lanoux283273b2015-12-04 03:01:54 -0800515 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400516 if addr.get('OS-EXT-IPS:type',
517 'floating') == 'floating':
518 self._ping_ip(ip, 60)
519 _floating_is_alive = True
lanoux283273b2015-12-04 03:01:54 -0800520 elif CONF.validation.connect_method == 'fixed':
521 if addr.get('OS-EXT-IPS:type',
522 'fixed') == 'fixed':
523 namespace = _get_router_namespace(client,
524 network_name)
525 self._ping_ip(ip, 60, namespace)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200526 else:
527 self._ping_ip(ip, 60)
lanoux283273b2015-12-04 03:01:54 -0800528 # If CONF.validation.connect_method is floating, validate
529 # that the floating IP is attached to the server and the
530 # the server is pingable.
531 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400532 self.assertTrue(_floating_is_alive,
533 "Server %s has no floating IP." %
534 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200535 else:
536 addr = found['addresses']['private'][0]['addr']
537 self._ping_ip(addr, 60)
538
539 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100540 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200541 LOG.info("Checking security groups")
542 for secgroup in self.res['secgroups']:
543 client = client_for_user(secgroup['owner'])
544 found = _get_resource_by_name(client.secgroups, 'security_groups',
545 secgroup['name'])
546 self.assertIsNotNone(
547 found,
548 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400549
Emilien Macchi626b4f82014-06-15 21:44:29 +0200550 def check_volumes(self):
551 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000552 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000553 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200554 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200555 for volume in self.res['volumes']:
556 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400557 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200558 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400559 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200560 "Couldn't find expected volume %s" % volume['name'])
561
562 # Verify that a volume's attachment retrieved
563 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400564 attachment = client.volumes.get_attachment_from_volume(vol_body)
565 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200566 self.assertEqual(server_id, attachment['server_id'])
567
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200568 def check_networking(self):
569 """Check that the networks are still there."""
570 for res_type in ('networks', 'subnets', 'routers'):
571 for res in self.res[res_type]:
572 client = client_for_user(res['owner'])
573 found = _get_resource_by_name(client.networks, res_type,
574 res['name'])
575 self.assertIsNotNone(
576 found,
577 "Couldn't find expected resource %s" % res['name'])
578
Sean Dague655e0af2014-05-29 09:00:22 -0400579
580#######################
581#
582# OBJECTS
583#
584#######################
585
586
587def _file_contents(fname):
588 with open(fname, 'r') as f:
589 return f.read()
590
591
592def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000593 if not objects:
594 return
Sean Dague655e0af2014-05-29 09:00:22 -0400595 LOG.info("Creating objects")
596 for obj in objects:
597 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200598 swift_role = obj.get('swift_role', 'Member')
599 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400600 client = client_for_user(obj['owner'])
601 client.containers.create_container(obj['container'])
602 client.objects.create_object(
603 obj['container'], obj['name'],
604 _file_contents(obj['file']))
605
Emilien Macchibb71e072014-07-05 19:18:52 +0200606
607def destroy_objects(objects):
608 for obj in objects:
609 client = client_for_user(obj['owner'])
610 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400611 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200612 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
613
614
Sean Dague655e0af2014-05-29 09:00:22 -0400615#######################
616#
617# IMAGES
618#
619#######################
620
621
Sean Dague319b37a2014-07-11 07:28:11 -0400622def _resolve_image(image, imgtype):
623 name = image[imgtype]
624 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
625 return name, fname
626
627
Joe Gordon6f0426c2014-07-25 01:10:28 +0000628def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000629 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000630 for image in body:
631 if name == image['name']:
632 return image
633 return None
634
635
Sean Dague655e0af2014-05-29 09:00:22 -0400636def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000637 if not images:
638 return
Joe Gordona18d6862014-07-24 22:55:46 +0000639 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400640 for image in images:
641 client = client_for_user(image['owner'])
642
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100643 # DEPRECATED: 'format' was used for ami images
644 # Use 'disk_format' and 'container_format' instead
645 if 'format' in image:
646 LOG.warning("Deprecated: 'format' is deprecated for images "
647 "description. Please use 'disk_format' and 'container_"
648 "format' instead.")
649 image['disk_format'] = image['format']
650 image['container_format'] = image['format']
651
Sean Dague655e0af2014-05-29 09:00:22 -0400652 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000653 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000654 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400655 continue
656
657 # special handling for 3 part image
658 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100659 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400660 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500661 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400662 'javelin_' + name, 'aki', 'aki')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000663 client.images.store_image_file(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400664 extras['kernel_id'] = aki.get('id')
665
Sean Dague319b37a2014-07-11 07:28:11 -0400666 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500667 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400668 'javelin_' + name, 'ari', 'ari')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000669 client.images.store_image_file(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400670 extras['ramdisk_id'] = ari.get('id')
671
Sean Dague319b37a2014-07-11 07:28:11 -0400672 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500673 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100674 image['name'], image['container_format'],
675 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400676 image_id = body.get('id')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000677 client.images.store_image_file(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400678
679
Joe Gordon6f0426c2014-07-25 01:10:28 +0000680def destroy_images(images):
681 if not images:
682 return
683 LOG.info("Destroying images")
684 for image in images:
685 client = client_for_user(image['owner'])
686
687 response = _get_image_by_name(client, image['name'])
688 if not response:
nayna-patel1dfbedb2015-08-04 11:07:56 +0000689 LOG.info("Image '%s' does not exist" % image['name'])
Joe Gordon6f0426c2014-07-25 01:10:28 +0000690 continue
691 client.images.delete_image(response['id'])
692
693
Sean Dague655e0af2014-05-29 09:00:22 -0400694#######################
695#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200696# NETWORKS
697#
698#######################
699
700def _get_router_namespace(client, network):
701 network_id = _get_resource_by_name(client.networks,
702 'networks', network)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000703 n_body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200704 for router in n_body['routers']:
705 router_id = router['id']
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700706 r_body = client.ports.list_ports(device_id=router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200707 for port in r_body['ports']:
708 if port['network_id'] == network_id:
709 return "qrouter-%s" % router_id
710
711
712def _get_resource_by_name(client, resource, name):
713 get_resources = getattr(client, 'list_%s' % resource)
714 if get_resources is None:
715 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500716 # Until all tempest client methods are changed to return only one value,
717 # we cannot assume they all have the same signature so we need to discard
718 # the unused response first value it two values are being returned.
719 body = get_resources()
Brandon Palmecd2ec02016-02-25 09:38:36 -0600720 if isinstance(body, tuple):
David Kranz34e88122014-12-11 15:24:05 -0500721 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200722 if isinstance(body, dict):
723 body = body[resource]
724 for res in body:
725 if name == res['name']:
726 return res
727 raise ValueError('%s not found in %s resources' % (name, resource))
728
729
730def create_networks(networks):
731 LOG.info("Creating networks")
732 for network in networks:
733 client = client_for_user(network['owner'])
734
735 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500736 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200737 if any(item['name'] == network['name'] for item in body['networks']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000738 LOG.warning("Duplicated network name: %s" % network['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200739 continue
740
741 client.networks.create_network(name=network['name'])
742
743
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100744def destroy_networks(networks):
745 LOG.info("Destroying subnets")
746 for network in networks:
747 client = client_for_user(network['owner'])
748 network_id = _get_resource_by_name(client.networks, 'networks',
749 network['name'])['id']
750 client.networks.delete_network(network_id)
751
752
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200753def create_subnets(subnets):
754 LOG.info("Creating subnets")
755 for subnet in subnets:
756 client = client_for_user(subnet['owner'])
757
758 network = _get_resource_by_name(client.networks, 'networks',
759 subnet['network'])
760 ip_version = netaddr.IPNetwork(subnet['range']).version
761 # ensure we don't overlap with another subnet in the network
762 try:
763 client.networks.create_subnet(network_id=network['id'],
764 cidr=subnet['range'],
765 name=subnet['name'],
766 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900767 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200768 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
769 if not is_overlapping_cidr:
770 raise
771
772
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100773def destroy_subnets(subnets):
774 LOG.info("Destroying subnets")
775 for subnet in subnets:
776 client = client_for_user(subnet['owner'])
John Warren3961acd2015-10-02 14:38:53 -0400777 subnet_id = _get_resource_by_name(client.subnets,
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100778 'subnets', subnet['name'])['id']
John Warren3961acd2015-10-02 14:38:53 -0400779 client.subnets.delete_subnet(subnet_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100780
781
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200782def create_routers(routers):
783 LOG.info("Creating routers")
784 for router in routers:
785 client = client_for_user(router['owner'])
786
787 # only create a router if the name isn't here
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000788 body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200789 if any(item['name'] == router['name'] for item in body['routers']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000790 LOG.warning("Duplicated router name: %s" % router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200791 continue
792
Ken'ichi Ohmichi6665c972016-02-24 13:09:09 -0800793 client.networks.create_router(name=router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200794
795
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100796def destroy_routers(routers):
797 LOG.info("Destroying routers")
798 for router in routers:
799 client = client_for_user(router['owner'])
800 router_id = _get_resource_by_name(client.networks,
801 'routers', router['name'])['id']
802 for subnet in router['subnet']:
803 subnet_id = _get_resource_by_name(client.networks,
804 'subnets', subnet)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000805 client.routers.remove_router_interface(router_id,
806 subnet_id=subnet_id)
807 client.routers.delete_router(router_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100808
809
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200810def add_router_interface(routers):
811 for router in routers:
812 client = client_for_user(router['owner'])
813 router_id = _get_resource_by_name(client.networks,
814 'routers', router['name'])['id']
815
816 for subnet in router['subnet']:
817 subnet_id = _get_resource_by_name(client.networks,
818 'subnets', subnet)['id']
819 # connect routers to their subnets
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000820 client.routers.add_router_interface(router_id,
821 subnet_id=subnet_id)
nayna-patel1dfbedb2015-08-04 11:07:56 +0000822 # connect routers to external network if set to "gateway"
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200823 if router['gateway']:
824 if CONF.network.public_network_id:
825 ext_net = CONF.network.public_network_id
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000826 client.routers._update_router(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200827 router_id, set_enable_snat=True,
828 external_gateway_info={"network_id": ext_net})
829 else:
830 raise ValueError('public_network_id is not configured.')
831
832
833#######################
834#
Sean Dague655e0af2014-05-29 09:00:22 -0400835# SERVERS
836#
837#######################
838
839def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500840 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400841 for server in body['servers']:
842 if name == server['name']:
843 return server
844 return None
845
846
Sean Dague655e0af2014-05-29 09:00:22 -0400847def _get_flavor_by_name(client, name):
ghanshyam19973be2015-08-18 15:46:42 +0900848 body = client.flavors.list_flavors()['flavors']
Sean Dague655e0af2014-05-29 09:00:22 -0400849 for flavor in body:
850 if name == flavor['name']:
851 return flavor
852 return None
853
854
855def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000856 if not servers:
857 return
Joe Gordona18d6862014-07-24 22:55:46 +0000858 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400859 for server in servers:
860 client = client_for_user(server['owner'])
861
862 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000863 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400864 continue
865
866 image_id = _get_image_by_name(client, server['image'])['id']
867 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200868 # validate neutron is enabled and ironic disabled
869 kwargs = dict()
870 if (CONF.service_available.neutron and
871 not CONF.baremetal.driver_enabled and server.get('networks')):
872 get_net_id = lambda x: (_get_resource_by_name(
873 client.networks, 'networks', x)['id'])
874 kwargs['networks'] = [{'uuid': get_net_id(network)}
875 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500876 body = client.servers.create_server(
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000877 name=server['name'], imageRef=image_id, flavorRef=flavor_id,
878 **kwargs)['server']
Joe Gordon10f260b2014-07-24 23:27:19 +0000879 server_id = body['id']
880 client.servers.wait_for_server_status(server_id, 'ACTIVE')
nayna-patel1dfbedb2015-08-04 11:07:56 +0000881 # create security group(s) after server spawning
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200882 for secgroup in server['secgroups']:
Ken'ichi Ohmichie6349f32015-12-09 06:47:54 +0000883 client.servers.add_security_group(server_id, name=secgroup)
lanoux283273b2015-12-04 03:01:54 -0800884 if CONF.validation.connect_method == 'floating':
Joe H. Rahme9350a102015-03-29 17:39:20 +0200885 floating_ip_pool = server.get('floating_ip_pool')
886 floating_ip = client.floating_ips.create_floating_ip(
ghanshyam9a3a9a22015-08-18 17:03:55 +0900887 pool_name=floating_ip_pool)['floating_ip']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400888 client.floating_ips.associate_floating_ip_to_server(
889 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400890
891
Joe Gordondb63b1c2014-07-24 23:21:21 +0000892def destroy_servers(servers):
893 if not servers:
894 return
895 LOG.info("Destroying servers")
896 for server in servers:
897 client = client_for_user(server['owner'])
898
Emilien Macchidc5bae22015-03-16 08:49:02 -0400899 response = _get_server_by_name(client, server['name'])
900 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000901 LOG.info("Server '%s' does not exist" % server['name'])
902 continue
903
Emilien Macchidc5bae22015-03-16 08:49:02 -0400904 # TODO(EmilienM): disassociate floating IP from server and release it.
905 client.servers.delete_server(response['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000906 waiters.wait_for_server_termination(client.servers, response['id'],
907 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000908
909
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200910def create_secgroups(secgroups):
911 LOG.info("Creating security groups")
912 for secgroup in secgroups:
913 client = client_for_user(secgroup['owner'])
914
915 # only create a security group if the name isn't here
916 # i.e. a security group may be used by another server
917 # only create a router if the name isn't here
ghanshyamb610b772015-08-24 17:29:38 +0900918 body = client.secgroups.list_security_groups()['security_groups']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200919 if any(item['name'] == secgroup['name'] for item in body):
920 LOG.warning("Security group '%s' already exists" %
921 secgroup['name'])
922 continue
923
David Kranz9964b4e2015-02-06 15:45:29 -0500924 body = client.secgroups.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900925 name=secgroup['name'],
926 description=secgroup['description'])['security_group']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200927 secgroup_id = body['id']
928 # for each security group, create the rules
929 for rule in secgroup['rules']:
930 ip_proto, from_port, to_port, cidr = rule.split()
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000931 client.secrules.create_security_group_rule(
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000932 parent_group_id=secgroup_id, ip_protocol=ip_proto,
933 from_port=from_port, to_port=to_port, cidr=cidr)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200934
935
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100936def destroy_secgroups(secgroups):
937 LOG.info("Destroying security groups")
938 for secgroup in secgroups:
939 client = client_for_user(secgroup['owner'])
940 sg_id = _get_resource_by_name(client.secgroups,
941 'security_groups',
942 secgroup['name'])
943 # sg rules are deleted automatically
944 client.secgroups.delete_security_group(sg_id['id'])
945
946
Sean Dague655e0af2014-05-29 09:00:22 -0400947#######################
948#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200949# VOLUMES
950#
951#######################
952
953def _get_volume_by_name(client, name):
John Warren6177c9e2015-08-19 20:00:17 +0000954 body = client.volumes.list_volumes()['volumes']
Emilien Macchid18fec12014-09-15 14:32:54 -0400955 for volume in body:
956 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200957 return volume
958 return None
959
960
961def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100962 if not volumes:
963 return
964 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200965 for volume in volumes:
966 client = client_for_user(volume['owner'])
967
968 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400969 if _get_volume_by_name(client, volume['name']):
970 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200971 continue
972
Emilien Macchid18fec12014-09-15 14:32:54 -0400973 size = volume['gb']
974 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000975 body = client.volumes.create_volume(size=size,
John Warren6177c9e2015-08-19 20:00:17 +0000976 display_name=v_name)['volume']
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500977 waiters.wait_for_volume_status(client.volumes, body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200978
979
Emilien Macchibb71e072014-07-05 19:18:52 +0200980def destroy_volumes(volumes):
981 for volume in volumes:
982 client = client_for_user(volume['owner'])
983 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400984 client.volumes.detach_volume(volume_id)
985 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200986
987
Emilien Macchi626b4f82014-06-15 21:44:29 +0200988def attach_volumes(volumes):
989 for volume in volumes:
990 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200991 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400992 volume_id = _get_volume_by_name(client, volume['name'])['id']
993 device = volume['device']
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900994 client.volumes.attach_volume(volume_id,
995 instance_uuid=server_id,
996 mountpoint=device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200997
998
999#######################
1000#
Sean Dague655e0af2014-05-29 09:00:22 -04001001# MAIN LOGIC
1002#
1003#######################
1004
1005def create_resources():
1006 LOG.info("Creating Resources")
1007 # first create keystone level resources, and we need to be admin
nayna-patel1dfbedb2015-08-04 11:07:56 +00001008 # for this.
Sean Dague655e0af2014-05-29 09:00:22 -04001009 create_tenants(RES['tenants'])
1010 create_users(RES['users'])
1011 collect_users(RES['users'])
1012
1013 # next create resources in a well known order
1014 create_objects(RES['objects'])
1015 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001016
1017 # validate neutron is enabled and ironic is disabled
1018 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1019 create_networks(RES['networks'])
1020 create_subnets(RES['subnets'])
1021 create_routers(RES['routers'])
1022 add_router_interface(RES['routers'])
1023
1024 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001025 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001026
1027 # Only attempt attaching the volumes if servers are defined in the
nayna-patel1dfbedb2015-08-04 11:07:56 +00001028 # resource file
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001029 if 'servers' in RES:
1030 create_servers(RES['servers'])
1031 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001032
1033
Joe Gordondb63b1c2014-07-24 23:21:21 +00001034def destroy_resources():
1035 LOG.info("Destroying Resources")
1036 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001037 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001038 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001039 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001040 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001041 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1042 destroy_routers(RES['routers'])
1043 destroy_subnets(RES['subnets'])
1044 destroy_networks(RES['networks'])
1045 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001046 destroy_users(RES['users'])
1047 destroy_tenants(RES['tenants'])
zhangguoqing6c096642016-01-04 06:17:21 +00001048 LOG.warning("Destroy mode incomplete")
Joe Gordon6f0426c2014-07-25 01:10:28 +00001049
Joe Gordondb63b1c2014-07-24 23:21:21 +00001050
Sean Dague655e0af2014-05-29 09:00:22 -04001051def get_options():
1052 global OPTS
1053 parser = argparse.ArgumentParser(
1054 description='Create and validate a fixed set of OpenStack resources')
1055 parser.add_argument('-m', '--mode',
1056 metavar='<create|check|destroy>',
1057 required=True,
1058 help=('One of (create, check, destroy)'))
1059 parser.add_argument('-r', '--resources',
1060 required=True,
1061 metavar='resourcefile.yaml',
1062 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001063
Sean Dague319b37a2014-07-11 07:28:11 -04001064 parser.add_argument(
1065 '-d', '--devstack-base',
1066 required=True,
1067 metavar='/opt/stack/old',
1068 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001069 parser.add_argument(
1070 '-c', '--config-file',
1071 metavar='/etc/tempest.conf',
1072 help='path to javelin2(tempest) config file')
1073
Sean Dague655e0af2014-05-29 09:00:22 -04001074 # auth bits, letting us also just source the devstack openrc
1075 parser.add_argument('--os-username',
1076 metavar='<auth-user-name>',
1077 default=os.environ.get('OS_USERNAME'),
1078 help=('Defaults to env[OS_USERNAME].'))
1079 parser.add_argument('--os-password',
1080 metavar='<auth-password>',
1081 default=os.environ.get('OS_PASSWORD'),
1082 help=('Defaults to env[OS_PASSWORD].'))
1083 parser.add_argument('--os-tenant-name',
1084 metavar='<auth-tenant-name>',
1085 default=os.environ.get('OS_TENANT_NAME'),
1086 help=('Defaults to env[OS_TENANT_NAME].'))
1087
1088 OPTS = parser.parse_args()
1089 if OPTS.mode not in ('create', 'check', 'destroy'):
1090 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1091 parser.print_help()
1092 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001093 if OPTS.config_file:
1094 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001095
1096
Joe Gordon915eb8e2014-07-17 11:25:46 +02001097def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001098 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001099 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001100 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001101
1102
1103def main():
Matthew Treinish0ee37442016-01-12 16:05:40 -05001104 print("Javelin is deprecated and will be removed from Tempest in the "
1105 "future.")
Sean Dague655e0af2014-05-29 09:00:22 -04001106 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())