blob: 08ad94fd464f24814e6ed174b818ebf61baf4dad [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 Ohmichi19d668e2016-06-09 14:35:14 -0700129from tempest.lib.services.image.v2 import images_client
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700130from tempest.lib.services.network import networks_client
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700131from tempest.lib.services.network import ports_client
Ken'ichi Ohmichi131799e2016-06-06 12:06:41 -0700132from tempest.lib.services.network import routers_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500133from tempest.lib.services.network import subnets_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100134from tempest.services.identity.v2.json import identity_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000135from tempest.services.identity.v2.json import roles_client
Daniel Melladob04da902015-11-20 17:43:12 +0100136from tempest.services.identity.v2.json import tenants_client
Daniel Mellado82c83a52015-12-09 15:16:49 +0000137from tempest.services.identity.v2.json import users_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)
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300236 self.images = images_client.ImagesClient(
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:
ghanshyam7668fad2016-06-15 18:17:39 +0900322 admin.tenants.create_tenant(name=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:
ghanshyam50894fc2016-06-17 13:20:25 +0900364 admin.roles.create_user_role_on_project(
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(
ghanshyame1c6c1c2016-06-15 14:50:41 +0900394 name=u['name'], password=u['pass'],
395 tenantId=tenant['id'],
396 email="%s@%s" % (u['name'], tenant['id']),
Sean Dague655e0af2014-05-29 09:00:22 -0400397 enabled=True)
398
399
Emilien Macchibb71e072014-07-05 19:18:52 +0200400def destroy_users(users):
401 admin = keystone_admin()
402 for user in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100403 tenant_id = identity.get_tenant_by_name(admin.tenants,
Ken'ichi Ohmichi6ea3f982015-11-09 12:41:13 +0000404 user['tenant'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000405 user_id = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000406 tenant_id, user['name'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000407 admin.users.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200408
409
Sean Dague655e0af2014-05-29 09:00:22 -0400410def collect_users(users):
411 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200412 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400413 admin = keystone_admin()
414 for u in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100415 tenant = identity.get_tenant_by_name(admin.tenants, u['tenant'])
Sean Dague655e0af2014-05-29 09:00:22 -0400416 u['tenant_id'] = tenant['id']
417 USERS[u['name']] = u
Daniel Mellado82c83a52015-12-09 15:16:49 +0000418 body = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000419 tenant['id'], u['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400420 USERS[u['name']]['id'] = body['id']
421
422
423class JavelinCheck(unittest.TestCase):
424 def __init__(self, users, resources):
425 super(JavelinCheck, self).__init__()
426 self.users = users
427 self.res = resources
428
429 def runTest(self, *args):
430 pass
431
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200432 def _ping_ip(self, ip_addr, count, namespace=None):
433 if namespace is None:
434 ping_cmd = "ping -c1 " + ip_addr
435 else:
436 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
437 ip_addr)
438 for current in range(count):
439 return_code = os.system(ping_cmd)
440 if return_code is 0:
441 break
442 self.assertNotEqual(current, count - 1,
443 "Server is not pingable at %s" % ip_addr)
444
Sean Dague655e0af2014-05-29 09:00:22 -0400445 def check(self):
446 self.check_users()
447 self.check_objects()
448 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400449 self.check_volumes()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200450 self.check_secgroups()
451
452 # validate neutron is enabled and ironic disabled:
453 # Tenant network isolation is not supported when using ironic.
454 # "admin" has set up a neutron flat network environment within a shared
455 # fixed network for all tenants to use.
456 # In this case, network/subnet/router creation can be skipped and the
457 # server booted the same as nova network.
458 if (CONF.service_available.neutron and
459 not CONF.baremetal.driver_enabled):
460 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400461
462 def check_users(self):
463 """Check that the users we expect to exist, do.
464
465 We don't use the resource list for this because we need to validate
466 that things like tenantId didn't drift across versions.
467 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200468 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400469 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400470 client = keystone_admin()
Daniel Mellado82c83a52015-12-09 15:16:49 +0000471 found = client.users.show_user(user['id'])['user']
Sean Dague655e0af2014-05-29 09:00:22 -0400472 self.assertEqual(found['name'], user['name'])
473 self.assertEqual(found['tenantId'], user['tenant_id'])
474
475 # also ensure we can auth with that user, and do something
476 # on the cloud. We don't care about the results except that it
477 # remains authorized.
478 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500479 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400480
481 def check_objects(self):
482 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000483 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000484 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200485 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400486 for obj in self.res['objects']:
487 client = client_for_user(obj['owner'])
488 r, contents = client.objects.get_object(
489 obj['container'], obj['name'])
490 source = _file_contents(obj['file'])
491 self.assertEqual(contents, source)
492
493 def check_servers(self):
494 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000495 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000496 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200497 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400498 for server in self.res['servers']:
499 client = client_for_user(server['owner'])
500 found = _get_server_by_name(client, server['name'])
501 self.assertIsNotNone(
502 found,
503 "Couldn't find expected server %s" % server['name'])
504
ghanshyam0f825252015-08-25 16:02:50 +0900505 found = client.servers.show_server(found['id'])['server']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200506 # validate neutron is enabled and ironic disabled:
507 if (CONF.service_available.neutron and
508 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400509 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200510 for network_name, body in found['addresses'].items():
511 for addr in body:
512 ip = addr['addr']
lanoux283273b2015-12-04 03:01:54 -0800513 # Use floating IP, fixed IP or other type to
514 # reach the server.
Emilien Macchic3e3e292015-03-11 17:42:08 -0400515 # This is useful in multi-node environment.
lanoux283273b2015-12-04 03:01:54 -0800516 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400517 if addr.get('OS-EXT-IPS:type',
518 'floating') == 'floating':
519 self._ping_ip(ip, 60)
520 _floating_is_alive = True
lanoux283273b2015-12-04 03:01:54 -0800521 elif CONF.validation.connect_method == 'fixed':
522 if addr.get('OS-EXT-IPS:type',
523 'fixed') == 'fixed':
524 namespace = _get_router_namespace(client,
525 network_name)
526 self._ping_ip(ip, 60, namespace)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200527 else:
528 self._ping_ip(ip, 60)
lanoux283273b2015-12-04 03:01:54 -0800529 # If CONF.validation.connect_method is floating, validate
530 # that the floating IP is attached to the server and the
531 # the server is pingable.
532 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400533 self.assertTrue(_floating_is_alive,
534 "Server %s has no floating IP." %
535 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200536 else:
537 addr = found['addresses']['private'][0]['addr']
538 self._ping_ip(addr, 60)
539
540 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100541 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200542 LOG.info("Checking security groups")
543 for secgroup in self.res['secgroups']:
544 client = client_for_user(secgroup['owner'])
545 found = _get_resource_by_name(client.secgroups, 'security_groups',
546 secgroup['name'])
547 self.assertIsNotNone(
548 found,
549 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400550
Emilien Macchi626b4f82014-06-15 21:44:29 +0200551 def check_volumes(self):
552 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000553 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000554 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200555 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200556 for volume in self.res['volumes']:
557 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400558 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200559 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400560 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200561 "Couldn't find expected volume %s" % volume['name'])
562
563 # Verify that a volume's attachment retrieved
564 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400565 attachment = client.volumes.get_attachment_from_volume(vol_body)
566 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200567 self.assertEqual(server_id, attachment['server_id'])
568
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200569 def check_networking(self):
570 """Check that the networks are still there."""
571 for res_type in ('networks', 'subnets', 'routers'):
572 for res in self.res[res_type]:
573 client = client_for_user(res['owner'])
574 found = _get_resource_by_name(client.networks, res_type,
575 res['name'])
576 self.assertIsNotNone(
577 found,
578 "Couldn't find expected resource %s" % res['name'])
579
Sean Dague655e0af2014-05-29 09:00:22 -0400580
581#######################
582#
583# OBJECTS
584#
585#######################
586
587
588def _file_contents(fname):
589 with open(fname, 'r') as f:
590 return f.read()
591
592
593def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000594 if not objects:
595 return
Sean Dague655e0af2014-05-29 09:00:22 -0400596 LOG.info("Creating objects")
597 for obj in objects:
598 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200599 swift_role = obj.get('swift_role', 'Member')
600 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400601 client = client_for_user(obj['owner'])
602 client.containers.create_container(obj['container'])
603 client.objects.create_object(
604 obj['container'], obj['name'],
605 _file_contents(obj['file']))
606
Emilien Macchibb71e072014-07-05 19:18:52 +0200607
608def destroy_objects(objects):
609 for obj in objects:
610 client = client_for_user(obj['owner'])
611 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400612 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200613 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
614
615
Sean Dague655e0af2014-05-29 09:00:22 -0400616#######################
617#
618# IMAGES
619#
620#######################
621
622
Sean Dague319b37a2014-07-11 07:28:11 -0400623def _resolve_image(image, imgtype):
624 name = image[imgtype]
625 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
626 return name, fname
627
628
Joe Gordon6f0426c2014-07-25 01:10:28 +0000629def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000630 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000631 for image in body:
632 if name == image['name']:
633 return image
634 return None
635
636
Sean Dague655e0af2014-05-29 09:00:22 -0400637def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000638 if not images:
639 return
Joe Gordona18d6862014-07-24 22:55:46 +0000640 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400641 for image in images:
642 client = client_for_user(image['owner'])
643
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100644 # DEPRECATED: 'format' was used for ami images
645 # Use 'disk_format' and 'container_format' instead
646 if 'format' in image:
647 LOG.warning("Deprecated: 'format' is deprecated for images "
648 "description. Please use 'disk_format' and 'container_"
649 "format' instead.")
650 image['disk_format'] = image['format']
651 image['container_format'] = image['format']
652
Sean Dague655e0af2014-05-29 09:00:22 -0400653 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000654 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000655 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400656 continue
657
658 # special handling for 3 part image
659 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100660 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400661 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500662 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400663 'javelin_' + name, 'aki', 'aki')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000664 client.images.store_image_file(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400665 extras['kernel_id'] = aki.get('id')
666
Sean Dague319b37a2014-07-11 07:28:11 -0400667 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500668 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400669 'javelin_' + name, 'ari', 'ari')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000670 client.images.store_image_file(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400671 extras['ramdisk_id'] = ari.get('id')
672
Sean Dague319b37a2014-07-11 07:28:11 -0400673 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500674 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100675 image['name'], image['container_format'],
676 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400677 image_id = body.get('id')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000678 client.images.store_image_file(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400679
680
Joe Gordon6f0426c2014-07-25 01:10:28 +0000681def destroy_images(images):
682 if not images:
683 return
684 LOG.info("Destroying images")
685 for image in images:
686 client = client_for_user(image['owner'])
687
688 response = _get_image_by_name(client, image['name'])
689 if not response:
nayna-patel1dfbedb2015-08-04 11:07:56 +0000690 LOG.info("Image '%s' does not exist" % image['name'])
Joe Gordon6f0426c2014-07-25 01:10:28 +0000691 continue
692 client.images.delete_image(response['id'])
693
694
Sean Dague655e0af2014-05-29 09:00:22 -0400695#######################
696#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200697# NETWORKS
698#
699#######################
700
701def _get_router_namespace(client, network):
702 network_id = _get_resource_by_name(client.networks,
703 'networks', network)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000704 n_body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200705 for router in n_body['routers']:
706 router_id = router['id']
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700707 r_body = client.ports.list_ports(device_id=router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200708 for port in r_body['ports']:
709 if port['network_id'] == network_id:
710 return "qrouter-%s" % router_id
711
712
713def _get_resource_by_name(client, resource, name):
714 get_resources = getattr(client, 'list_%s' % resource)
715 if get_resources is None:
716 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500717 # Until all tempest client methods are changed to return only one value,
718 # we cannot assume they all have the same signature so we need to discard
719 # the unused response first value it two values are being returned.
720 body = get_resources()
Brandon Palmecd2ec02016-02-25 09:38:36 -0600721 if isinstance(body, tuple):
David Kranz34e88122014-12-11 15:24:05 -0500722 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200723 if isinstance(body, dict):
724 body = body[resource]
725 for res in body:
726 if name == res['name']:
727 return res
728 raise ValueError('%s not found in %s resources' % (name, resource))
729
730
731def create_networks(networks):
732 LOG.info("Creating networks")
733 for network in networks:
734 client = client_for_user(network['owner'])
735
736 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500737 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200738 if any(item['name'] == network['name'] for item in body['networks']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000739 LOG.warning("Duplicated network name: %s" % network['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200740 continue
741
742 client.networks.create_network(name=network['name'])
743
744
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100745def destroy_networks(networks):
746 LOG.info("Destroying subnets")
747 for network in networks:
748 client = client_for_user(network['owner'])
749 network_id = _get_resource_by_name(client.networks, 'networks',
750 network['name'])['id']
751 client.networks.delete_network(network_id)
752
753
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200754def create_subnets(subnets):
755 LOG.info("Creating subnets")
756 for subnet in subnets:
757 client = client_for_user(subnet['owner'])
758
759 network = _get_resource_by_name(client.networks, 'networks',
760 subnet['network'])
761 ip_version = netaddr.IPNetwork(subnet['range']).version
762 # ensure we don't overlap with another subnet in the network
763 try:
764 client.networks.create_subnet(network_id=network['id'],
765 cidr=subnet['range'],
766 name=subnet['name'],
767 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900768 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200769 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
770 if not is_overlapping_cidr:
771 raise
772
773
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100774def destroy_subnets(subnets):
775 LOG.info("Destroying subnets")
776 for subnet in subnets:
777 client = client_for_user(subnet['owner'])
John Warren3961acd2015-10-02 14:38:53 -0400778 subnet_id = _get_resource_by_name(client.subnets,
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100779 'subnets', subnet['name'])['id']
John Warren3961acd2015-10-02 14:38:53 -0400780 client.subnets.delete_subnet(subnet_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100781
782
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200783def create_routers(routers):
784 LOG.info("Creating routers")
785 for router in routers:
786 client = client_for_user(router['owner'])
787
788 # only create a router if the name isn't here
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000789 body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200790 if any(item['name'] == router['name'] for item in body['routers']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000791 LOG.warning("Duplicated router name: %s" % router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200792 continue
793
Ken'ichi Ohmichi6665c972016-02-24 13:09:09 -0800794 client.networks.create_router(name=router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200795
796
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100797def destroy_routers(routers):
798 LOG.info("Destroying routers")
799 for router in routers:
800 client = client_for_user(router['owner'])
801 router_id = _get_resource_by_name(client.networks,
802 'routers', router['name'])['id']
803 for subnet in router['subnet']:
804 subnet_id = _get_resource_by_name(client.networks,
805 'subnets', subnet)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000806 client.routers.remove_router_interface(router_id,
807 subnet_id=subnet_id)
808 client.routers.delete_router(router_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100809
810
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200811def add_router_interface(routers):
812 for router in routers:
813 client = client_for_user(router['owner'])
814 router_id = _get_resource_by_name(client.networks,
815 'routers', router['name'])['id']
816
817 for subnet in router['subnet']:
818 subnet_id = _get_resource_by_name(client.networks,
819 'subnets', subnet)['id']
820 # connect routers to their subnets
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000821 client.routers.add_router_interface(router_id,
822 subnet_id=subnet_id)
nayna-patel1dfbedb2015-08-04 11:07:56 +0000823 # connect routers to external network if set to "gateway"
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200824 if router['gateway']:
825 if CONF.network.public_network_id:
826 ext_net = CONF.network.public_network_id
Ken'ichi Ohmichib7cdaae2016-05-04 15:41:07 -0700827 client.routers.update_router(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200828 router_id, set_enable_snat=True,
829 external_gateway_info={"network_id": ext_net})
830 else:
831 raise ValueError('public_network_id is not configured.')
832
833
834#######################
835#
Sean Dague655e0af2014-05-29 09:00:22 -0400836# SERVERS
837#
838#######################
839
840def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500841 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400842 for server in body['servers']:
843 if name == server['name']:
844 return server
845 return None
846
847
Sean Dague655e0af2014-05-29 09:00:22 -0400848def _get_flavor_by_name(client, name):
ghanshyam19973be2015-08-18 15:46:42 +0900849 body = client.flavors.list_flavors()['flavors']
Sean Dague655e0af2014-05-29 09:00:22 -0400850 for flavor in body:
851 if name == flavor['name']:
852 return flavor
853 return None
854
855
856def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000857 if not servers:
858 return
Joe Gordona18d6862014-07-24 22:55:46 +0000859 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400860 for server in servers:
861 client = client_for_user(server['owner'])
862
863 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000864 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400865 continue
866
867 image_id = _get_image_by_name(client, server['image'])['id']
868 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200869 # validate neutron is enabled and ironic disabled
870 kwargs = dict()
871 if (CONF.service_available.neutron and
872 not CONF.baremetal.driver_enabled and server.get('networks')):
873 get_net_id = lambda x: (_get_resource_by_name(
874 client.networks, 'networks', x)['id'])
875 kwargs['networks'] = [{'uuid': get_net_id(network)}
876 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500877 body = client.servers.create_server(
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000878 name=server['name'], imageRef=image_id, flavorRef=flavor_id,
879 **kwargs)['server']
Joe Gordon10f260b2014-07-24 23:27:19 +0000880 server_id = body['id']
881 client.servers.wait_for_server_status(server_id, 'ACTIVE')
nayna-patel1dfbedb2015-08-04 11:07:56 +0000882 # create security group(s) after server spawning
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200883 for secgroup in server['secgroups']:
Ken'ichi Ohmichie6349f32015-12-09 06:47:54 +0000884 client.servers.add_security_group(server_id, name=secgroup)
lanoux283273b2015-12-04 03:01:54 -0800885 if CONF.validation.connect_method == 'floating':
Joe H. Rahme9350a102015-03-29 17:39:20 +0200886 floating_ip_pool = server.get('floating_ip_pool')
887 floating_ip = client.floating_ips.create_floating_ip(
ghanshyam9a3a9a22015-08-18 17:03:55 +0900888 pool_name=floating_ip_pool)['floating_ip']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400889 client.floating_ips.associate_floating_ip_to_server(
890 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400891
892
Joe Gordondb63b1c2014-07-24 23:21:21 +0000893def destroy_servers(servers):
894 if not servers:
895 return
896 LOG.info("Destroying servers")
897 for server in servers:
898 client = client_for_user(server['owner'])
899
Emilien Macchidc5bae22015-03-16 08:49:02 -0400900 response = _get_server_by_name(client, server['name'])
901 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000902 LOG.info("Server '%s' does not exist" % server['name'])
903 continue
904
Emilien Macchidc5bae22015-03-16 08:49:02 -0400905 # TODO(EmilienM): disassociate floating IP from server and release it.
906 client.servers.delete_server(response['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000907 waiters.wait_for_server_termination(client.servers, response['id'],
908 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000909
910
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200911def create_secgroups(secgroups):
912 LOG.info("Creating security groups")
913 for secgroup in secgroups:
914 client = client_for_user(secgroup['owner'])
915
916 # only create a security group if the name isn't here
917 # i.e. a security group may be used by another server
918 # only create a router if the name isn't here
ghanshyamb610b772015-08-24 17:29:38 +0900919 body = client.secgroups.list_security_groups()['security_groups']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200920 if any(item['name'] == secgroup['name'] for item in body):
921 LOG.warning("Security group '%s' already exists" %
922 secgroup['name'])
923 continue
924
David Kranz9964b4e2015-02-06 15:45:29 -0500925 body = client.secgroups.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900926 name=secgroup['name'],
927 description=secgroup['description'])['security_group']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200928 secgroup_id = body['id']
929 # for each security group, create the rules
930 for rule in secgroup['rules']:
931 ip_proto, from_port, to_port, cidr = rule.split()
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000932 client.secrules.create_security_group_rule(
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000933 parent_group_id=secgroup_id, ip_protocol=ip_proto,
934 from_port=from_port, to_port=to_port, cidr=cidr)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200935
936
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100937def destroy_secgroups(secgroups):
938 LOG.info("Destroying security groups")
939 for secgroup in secgroups:
940 client = client_for_user(secgroup['owner'])
941 sg_id = _get_resource_by_name(client.secgroups,
942 'security_groups',
943 secgroup['name'])
944 # sg rules are deleted automatically
945 client.secgroups.delete_security_group(sg_id['id'])
946
947
Sean Dague655e0af2014-05-29 09:00:22 -0400948#######################
949#
Emilien Macchi626b4f82014-06-15 21:44:29 +0200950# VOLUMES
951#
952#######################
953
954def _get_volume_by_name(client, name):
John Warren6177c9e2015-08-19 20:00:17 +0000955 body = client.volumes.list_volumes()['volumes']
Emilien Macchid18fec12014-09-15 14:32:54 -0400956 for volume in body:
957 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +0200958 return volume
959 return None
960
961
962def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +0100963 if not volumes:
964 return
965 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200966 for volume in volumes:
967 client = client_for_user(volume['owner'])
968
969 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -0400970 if _get_volume_by_name(client, volume['name']):
971 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200972 continue
973
Emilien Macchid18fec12014-09-15 14:32:54 -0400974 size = volume['gb']
975 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000976 body = client.volumes.create_volume(size=size,
John Warren6177c9e2015-08-19 20:00:17 +0000977 display_name=v_name)['volume']
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -0500978 waiters.wait_for_volume_status(client.volumes, body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +0200979
980
Emilien Macchibb71e072014-07-05 19:18:52 +0200981def destroy_volumes(volumes):
982 for volume in volumes:
983 client = client_for_user(volume['owner'])
984 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -0400985 client.volumes.detach_volume(volume_id)
986 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200987
988
Emilien Macchi626b4f82014-06-15 21:44:29 +0200989def attach_volumes(volumes):
990 for volume in volumes:
991 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200992 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400993 volume_id = _get_volume_by_name(client, volume['name'])['id']
994 device = volume['device']
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900995 client.volumes.attach_volume(volume_id,
996 instance_uuid=server_id,
997 mountpoint=device)
Emilien Macchi626b4f82014-06-15 21:44:29 +0200998
999
1000#######################
1001#
Sean Dague655e0af2014-05-29 09:00:22 -04001002# MAIN LOGIC
1003#
1004#######################
1005
1006def create_resources():
1007 LOG.info("Creating Resources")
1008 # first create keystone level resources, and we need to be admin
nayna-patel1dfbedb2015-08-04 11:07:56 +00001009 # for this.
Sean Dague655e0af2014-05-29 09:00:22 -04001010 create_tenants(RES['tenants'])
1011 create_users(RES['users'])
1012 collect_users(RES['users'])
1013
1014 # next create resources in a well known order
1015 create_objects(RES['objects'])
1016 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001017
1018 # validate neutron is enabled and ironic is disabled
1019 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1020 create_networks(RES['networks'])
1021 create_subnets(RES['subnets'])
1022 create_routers(RES['routers'])
1023 add_router_interface(RES['routers'])
1024
1025 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001026 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001027
1028 # Only attempt attaching the volumes if servers are defined in the
nayna-patel1dfbedb2015-08-04 11:07:56 +00001029 # resource file
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001030 if 'servers' in RES:
1031 create_servers(RES['servers'])
1032 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001033
1034
Joe Gordondb63b1c2014-07-24 23:21:21 +00001035def destroy_resources():
1036 LOG.info("Destroying Resources")
1037 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001038 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001039 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001040 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001041 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001042 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1043 destroy_routers(RES['routers'])
1044 destroy_subnets(RES['subnets'])
1045 destroy_networks(RES['networks'])
1046 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001047 destroy_users(RES['users'])
1048 destroy_tenants(RES['tenants'])
zhangguoqing6c096642016-01-04 06:17:21 +00001049 LOG.warning("Destroy mode incomplete")
Joe Gordon6f0426c2014-07-25 01:10:28 +00001050
Joe Gordondb63b1c2014-07-24 23:21:21 +00001051
Sean Dague655e0af2014-05-29 09:00:22 -04001052def get_options():
1053 global OPTS
1054 parser = argparse.ArgumentParser(
1055 description='Create and validate a fixed set of OpenStack resources')
1056 parser.add_argument('-m', '--mode',
1057 metavar='<create|check|destroy>',
1058 required=True,
1059 help=('One of (create, check, destroy)'))
1060 parser.add_argument('-r', '--resources',
1061 required=True,
1062 metavar='resourcefile.yaml',
1063 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001064
Sean Dague319b37a2014-07-11 07:28:11 -04001065 parser.add_argument(
1066 '-d', '--devstack-base',
1067 required=True,
1068 metavar='/opt/stack/old',
1069 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001070 parser.add_argument(
1071 '-c', '--config-file',
1072 metavar='/etc/tempest.conf',
1073 help='path to javelin2(tempest) config file')
1074
Sean Dague655e0af2014-05-29 09:00:22 -04001075 # auth bits, letting us also just source the devstack openrc
1076 parser.add_argument('--os-username',
1077 metavar='<auth-user-name>',
1078 default=os.environ.get('OS_USERNAME'),
1079 help=('Defaults to env[OS_USERNAME].'))
1080 parser.add_argument('--os-password',
1081 metavar='<auth-password>',
1082 default=os.environ.get('OS_PASSWORD'),
1083 help=('Defaults to env[OS_PASSWORD].'))
1084 parser.add_argument('--os-tenant-name',
1085 metavar='<auth-tenant-name>',
1086 default=os.environ.get('OS_TENANT_NAME'),
1087 help=('Defaults to env[OS_TENANT_NAME].'))
1088
1089 OPTS = parser.parse_args()
1090 if OPTS.mode not in ('create', 'check', 'destroy'):
1091 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1092 parser.print_help()
1093 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001094 if OPTS.config_file:
1095 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001096
1097
Joe Gordon915eb8e2014-07-17 11:25:46 +02001098def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001099 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001100 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001101 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001102
1103
1104def main():
Matthew Treinish0ee37442016-01-12 16:05:40 -05001105 print("Javelin is deprecated and will be removed from Tempest in the "
1106 "future.")
Sean Dague655e0af2014-05-29 09:00:22 -04001107 global RES
1108 get_options()
1109 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001110 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001111
1112 if OPTS.mode == 'create':
1113 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001114 # Make sure the resources we just created actually work
1115 checker = JavelinCheck(USERS, RES)
1116 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001117 elif OPTS.mode == 'check':
1118 collect_users(RES['users'])
1119 checker = JavelinCheck(USERS, RES)
1120 checker.check()
1121 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001122 collect_users(RES['users'])
1123 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001124 else:
1125 LOG.error('Unknown mode %s' % OPTS.mode)
1126 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001127 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001128 return 0
1129
1130if __name__ == "__main__":
1131 sys.exit(main())