blob: 2a4e314023af74cc929c09b6fe306234657b811b [file] [log] [blame]
Sean Dague655e0af2014-05-29 09:00:22 -04001#!/usr/bin/env python
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Joe H. Rahme61469fd2014-12-02 17:09:17 +010015"""Javelin is a tool for creating, verifying, and deleting a small set of
Sean Dague655e0af2014-05-29 09:00:22 -040016resources in a declarative way.
17
Joe H. Rahme61469fd2014-12-02 17:09:17 +010018Javelin is meant to be used as a way to validate quickly that resources can
19survive an upgrade process.
20
21Authentication
22--------------
23
24Javelin will be creating (and removing) users and tenants so it needs the admin
25credentials of your cloud to operate properly. The corresponding info can be
26given the usual way, either through CLI options or environment variables.
27
28You're probably familiar with these, but just in case::
29
30 +----------+------------------+----------------------+
31 | Param | CLI | Environment Variable |
32 +----------+------------------+----------------------+
33 | Username | --os-username | OS_USERNAME |
34 | Password | --os-password | OS_PASSWORD |
35 | Tenant | --os-tenant-name | OS_TENANT_NAME |
36 +----------+------------------+----------------------+
37
38
39Runtime Arguments
40-----------------
41
42**-m/--mode**: (Required) Has to be one of 'check', 'create' or 'destroy'. It
43indicates which actions javelin is going to perform.
44
45**-r/--resources**: (Required) The path to a YAML file describing the resources
46used by Javelin.
47
48**-d/--devstack-base**: (Required) The path to the devstack repo used to
49retrieve artefacts (like images) that will be referenced in the resource files.
50
51**-c/--config-file**: (Optional) The path to a valid Tempest config file
52describing your cloud. Javelin may use this to determine if certain services
53are enabled and modify its behavior accordingly.
54
55
56Resource file
57-------------
58
59The resource file is a valid YAML file describing the resources that will be
60created, checked and destroyed by javelin. Here's a canonical example of a
61resource file::
62
63 tenants:
64 - javelin
65 - discuss
66
67 users:
68 - name: javelin
69 pass: gungnir
70 tenant: javelin
71 - name: javelin2
72 pass: gungnir2
73 tenant: discuss
74
75 # resources that we want to create
76 images:
77 - name: javelin_cirros
78 owner: javelin
79 file: cirros-0.3.2-x86_64-blank.img
Joe H. Rahme4352d5d2015-03-09 17:41:18 +010080 disk_format: ami
81 container_format: ami
Joe H. Rahme61469fd2014-12-02 17:09:17 +010082 aki: cirros-0.3.2-x86_64-vmlinuz
83 ari: cirros-0.3.2-x86_64-initrd
84
85 servers:
86 - name: peltast
87 owner: javelin
88 flavor: m1.small
89 image: javelin_cirros
Joe H. Rahme9350a102015-03-29 17:39:20 +020090 floating_ip_pool: public
Joe H. Rahme61469fd2014-12-02 17:09:17 +010091 - name: hoplite
92 owner: javelin
93 flavor: m1.medium
94 image: javelin_cirros
95
96
97An important piece of the resource definition is the *owner* field, which is
98the user (that we've created) that is the owner of that resource. All
99operations on that resource will happen as that regular user to ensure that
100admin level access does not mask issues.
101
102The check phase will act like a unit test, using well known assert methods to
103verify that the correct resources exist.
104
Sean Dague655e0af2014-05-29 09:00:22 -0400105"""
106
Matthew Treinish96e9e882014-06-09 18:37:19 -0400107import argparse
Chris Dent51e76de2014-10-01 12:07:14 +0100108import collections
Chris Dent878f3782014-06-30 17:04:15 +0100109import datetime
Sean Dague655e0af2014-05-29 09:00:22 -0400110import os
111import sys
112import unittest
Sean Dague655e0af2014-05-29 09:00:22 -0400113
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200114import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +0000115from oslo_log import log as logging
116from oslo_utils import timeutils
Matthew Treinish71426682015-04-23 11:19:38 -0400117import six
Matthew Treinish96e9e882014-06-09 18:37:19 -0400118import yaml
Sean Dague655e0af2014-05-29 09:00:22 -0400119
Ken'ichi Ohmichi6ea3f982015-11-09 12:41:13 +0000120from tempest.common import identity
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000121from tempest.common import waiters
Joe Gordon28a84ae2014-07-17 15:38:28 +0000122from tempest import config
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500123from tempest.lib import auth
124from tempest.lib import exceptions as lib_exc
125from tempest.lib.services.compute import flavors_client
126from tempest.lib.services.compute import floating_ips_client
127from tempest.lib.services.compute import security_group_rules_client
128from tempest.lib.services.compute import security_groups_client
129from tempest.lib.services.compute import servers_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
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500132from tempest.lib.services.network import subnets_client
Jamie Lennoxc429e6a2015-02-24 10:42:42 +1100133from tempest.services.identity.v2.json import identity_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000134from tempest.services.identity.v2.json import roles_client
Daniel Melladob04da902015-11-20 17:43:12 +0100135from tempest.services.identity.v2.json import tenants_client
Daniel Mellado82c83a52015-12-09 15:16:49 +0000136from tempest.services.identity.v2.json import users_client
Ken'ichi Ohmichi69dcf442015-11-30 11:48:01 +0000137from tempest.services.image.v2.json import images_client
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000138from tempest.services.network.json import routers_client
Sean Dague655e0af2014-05-29 09:00:22 -0400139from tempest.services.object_storage import container_client
140from tempest.services.object_storage import object_client
liu-sheng67b730e2015-07-16 15:19:33 +0800141from tempest.services.telemetry.json import alarming_client
Chris Dent878f3782014-06-30 17:04:15 +0100142from tempest.services.telemetry.json import telemetry_client
Yaroslav Lobankovdb4a2e12015-11-28 20:04:54 +0300143from tempest.services.volume.v1.json import volumes_client
Sean Dague655e0af2014-05-29 09:00:22 -0400144
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200145CONF = config.CONF
Sean Dague655e0af2014-05-29 09:00:22 -0400146OPTS = {}
147USERS = {}
Chris Dent51e76de2014-10-01 12:07:14 +0100148RES = collections.defaultdict(list)
Sean Dague655e0af2014-05-29 09:00:22 -0400149
150LOG = None
151
Chris Dent878f3782014-06-30 17:04:15 +0100152JAVELIN_START = datetime.datetime.utcnow()
153
Sean Dague655e0af2014-05-29 09:00:22 -0400154
155class OSClient(object):
156 _creds = None
157 identity = None
158 servers = None
159
160 def __init__(self, user, pw, tenant):
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000161 default_params = {
162 'disable_ssl_certificate_validation':
163 CONF.identity.disable_ssl_certificate_validation,
164 'ca_certs': CONF.identity.ca_certificates_file,
165 'trace_requests': CONF.debug.trace_requests
166 }
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000167 default_params_with_timeout_values = {
168 'build_interval': CONF.compute.build_interval,
169 'build_timeout': CONF.compute.build_timeout
170 }
171 default_params_with_timeout_values.update(default_params)
172
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000173 compute_params = {
174 'service': CONF.compute.catalog_type,
175 'region': CONF.compute.region or CONF.identity.region,
176 'endpoint_type': CONF.compute.endpoint_type,
177 'build_interval': CONF.compute.build_interval,
178 'build_timeout': CONF.compute.build_timeout
179 }
180 compute_params.update(default_params)
181
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000182 object_storage_params = {
183 'service': CONF.object_storage.catalog_type,
184 'region': CONF.object_storage.region or CONF.identity.region,
185 'endpoint_type': CONF.object_storage.endpoint_type
186 }
187 object_storage_params.update(default_params)
188
andreafb8a52282015-03-19 22:21:54 +0000189 _creds = auth.KeystoneV2Credentials(
Sean Dague655e0af2014-05-29 09:00:22 -0400190 username=user,
191 password=pw,
192 tenant_name=tenant)
Andrea Frittoli90012352015-02-25 21:58:02 +0000193 auth_provider_params = {
194 'disable_ssl_certificate_validation':
195 CONF.identity.disable_ssl_certificate_validation,
196 'ca_certs': CONF.identity.ca_certificates_file,
197 'trace_requests': CONF.debug.trace_requests
198 }
andreafb8a52282015-03-19 22:21:54 +0000199 _auth = auth.KeystoneV2AuthProvider(
Andrea Frittoli90012352015-02-25 21:58:02 +0000200 _creds, CONF.identity.uri, **auth_provider_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000201 self.identity = identity_client.IdentityClient(
ghanshyamd26b5cd2015-02-09 14:48:58 +0900202 _auth,
203 CONF.identity.catalog_type,
204 CONF.identity.region,
205 endpoint_type='adminURL',
206 **default_params_with_timeout_values)
Daniel Melladob04da902015-11-20 17:43:12 +0100207 self.tenants = tenants_client.TenantsClient(
208 _auth,
209 CONF.identity.catalog_type,
210 CONF.identity.region,
211 endpoint_type='adminURL',
212 **default_params_with_timeout_values)
Daniel Mellado6b16b922015-12-07 12:43:08 +0000213 self.roles = roles_client.RolesClient(
214 _auth,
215 CONF.identity.catalog_type,
216 CONF.identity.region,
217 endpoint_type='adminURL',
218 **default_params_with_timeout_values)
Daniel Mellado82c83a52015-12-09 15:16:49 +0000219 self.users = users_client.UsersClient(
220 _auth,
221 CONF.identity.catalog_type,
222 CONF.identity.region,
223 endpoint_type='adminURL',
224 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000225 self.servers = servers_client.ServersClient(_auth,
226 **compute_params)
227 self.flavors = flavors_client.FlavorsClient(_auth,
228 **compute_params)
229 self.floating_ips = floating_ips_client.FloatingIPsClient(
Emilien Macchic3e3e292015-03-11 17:42:08 -0400230 _auth, **compute_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000231 self.secgroups = security_groups_client.SecurityGroupsClient(
Ken'ichi Ohmichi4771cbc2015-01-19 23:45:23 +0000232 _auth, **compute_params)
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000233 self.secrules = security_group_rules_client.SecurityGroupRulesClient(
234 _auth, **compute_params)
Ken'ichi Ohmichi564b2ad2015-01-22 02:08:59 +0000235 self.objects = object_client.ObjectClient(_auth,
236 **object_storage_params)
237 self.containers = container_client.ContainerClient(
238 _auth, **object_storage_params)
Ken'ichi Ohmichi69dcf442015-11-30 11:48:01 +0000239 self.images = images_client.ImagesClientV2(
Masayuki Igawabc7e1892015-03-03 11:46:48 +0900240 _auth,
241 CONF.image.catalog_type,
242 CONF.image.region or CONF.identity.region,
243 endpoint_type=CONF.image.endpoint_type,
244 build_interval=CONF.image.build_interval,
245 build_timeout=CONF.image.build_timeout,
246 **default_params)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000247 self.telemetry = telemetry_client.TelemetryClient(
Ken'ichi Ohmichid5dba1c2015-01-23 02:23:22 +0000248 _auth,
249 CONF.telemetry.catalog_type,
250 CONF.identity.region,
251 endpoint_type=CONF.telemetry.endpoint_type,
252 **default_params_with_timeout_values)
liu-sheng67b730e2015-07-16 15:19:33 +0800253 self.alarming = alarming_client.AlarmingClient(
254 _auth,
255 CONF.alarm.catalog_type,
256 CONF.identity.region,
257 endpoint_type=CONF.alarm.endpoint_type,
258 **default_params_with_timeout_values)
Ken'ichi Ohmichia6287072015-07-02 02:43:15 +0000259 self.volumes = volumes_client.VolumesClient(
Ken'ichi Ohmichif85e9bd2015-01-27 12:51:47 +0000260 _auth,
261 CONF.volume.catalog_type,
262 CONF.volume.region or CONF.identity.region,
263 endpoint_type=CONF.volume.endpoint_type,
264 build_interval=CONF.volume.build_interval,
265 build_timeout=CONF.volume.build_timeout,
266 **default_params)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700267 self.networks = networks_client.NetworksClient(
Ken'ichi Ohmichia182e862015-01-21 01:16:37 +0000268 _auth,
269 CONF.network.catalog_type,
270 CONF.network.region or CONF.identity.region,
271 endpoint_type=CONF.network.endpoint_type,
272 build_interval=CONF.network.build_interval,
273 build_timeout=CONF.network.build_timeout,
274 **default_params)
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700275 self.ports = ports_client.PortsClient(
276 _auth,
277 CONF.network.catalog_type,
278 CONF.network.region or CONF.identity.region,
279 endpoint_type=CONF.network.endpoint_type,
280 build_interval=CONF.network.build_interval,
281 build_timeout=CONF.network.build_timeout,
282 **default_params)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000283 self.routers = routers_client.RoutersClient(
284 _auth,
285 CONF.network.catalog_type,
286 CONF.network.region or CONF.identity.region,
287 endpoint_type=CONF.network.endpoint_type,
288 build_interval=CONF.network.build_interval,
289 build_timeout=CONF.network.build_timeout,
290 **default_params)
John Warren3961acd2015-10-02 14:38:53 -0400291 self.subnets = subnets_client.SubnetsClient(
292 _auth,
293 CONF.network.catalog_type,
294 CONF.network.region or CONF.identity.region,
295 endpoint_type=CONF.network.endpoint_type,
296 build_interval=CONF.network.build_interval,
297 build_timeout=CONF.network.build_timeout,
298 **default_params)
Sean Dague655e0af2014-05-29 09:00:22 -0400299
300
301def load_resources(fname):
Joe H. Rahme02736732015-01-27 18:33:09 +0100302 """Load the expected resources from a yaml file."""
Sean Dague655e0af2014-05-29 09:00:22 -0400303 return yaml.load(open(fname, 'r'))
304
305
306def keystone_admin():
307 return OSClient(OPTS.os_username, OPTS.os_password, OPTS.os_tenant_name)
308
309
310def client_for_user(name):
311 LOG.debug("Entering client_for_user")
312 if name in USERS:
313 user = USERS[name]
314 LOG.debug("Created client for user %s" % user)
315 return OSClient(user['name'], user['pass'], user['tenant'])
316 else:
317 LOG.error("%s not found in USERS: %s" % (name, USERS))
318
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200319
Sean Dague655e0af2014-05-29 09:00:22 -0400320###################
321#
322# TENANTS
323#
324###################
325
326
327def create_tenants(tenants):
328 """Create tenants from resource definition.
329
330 Don't create the tenants if they already exist.
331 """
332 admin = keystone_admin()
Daniel Melladob04da902015-11-20 17:43:12 +0100333 body = admin.tenants.list_tenants()['tenants']
Sean Dague655e0af2014-05-29 09:00:22 -0400334 existing = [x['name'] for x in body]
335 for tenant in tenants:
336 if tenant not in existing:
Daniel Melladob04da902015-11-20 17:43:12 +0100337 admin.tenants.create_tenant(tenant)['tenant']
Sean Dague655e0af2014-05-29 09:00:22 -0400338 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000339 LOG.warning("Tenant '%s' already exists in this environment"
340 % tenant)
Sean Dague655e0af2014-05-29 09:00:22 -0400341
Emilien Macchibb71e072014-07-05 19:18:52 +0200342
343def destroy_tenants(tenants):
344 admin = keystone_admin()
345 for tenant in tenants:
Daniel Melladob04da902015-11-20 17:43:12 +0100346 tenant_id = identity.get_tenant_by_name(admin.tenant, tenant)['id']
347 admin.tenants.delete_tenant(tenant_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200348
Sean Dague655e0af2014-05-29 09:00:22 -0400349##############
350#
351# USERS
352#
353##############
354
355
356def _users_for_tenant(users, tenant):
357 u_for_t = []
358 for user in users:
359 for n in user:
360 if user[n]['tenant'] == tenant:
361 u_for_t.append(user[n])
362 return u_for_t
363
364
365def _tenants_from_users(users):
366 tenants = set()
367 for user in users:
368 for n in user:
369 tenants.add(user[n]['tenant'])
370 return tenants
371
372
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200373def _assign_swift_role(user, swift_role):
Sean Dague655e0af2014-05-29 09:00:22 -0400374 admin = keystone_admin()
Daniel Mellado6b16b922015-12-07 12:43:08 +0000375 roles = admin.roles.list_roles()
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200376 role = next(r for r in roles if r['name'] == swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400377 LOG.debug(USERS[user])
378 try:
Daniel Mellado6b16b922015-12-07 12:43:08 +0000379 admin.roles.assign_user_role(
Sean Dague655e0af2014-05-29 09:00:22 -0400380 USERS[user]['tenant_id'],
381 USERS[user]['id'],
382 role['id'])
Masayuki Igawad9388762015-01-20 14:56:42 +0900383 except lib_exc.Conflict:
Sean Dague655e0af2014-05-29 09:00:22 -0400384 # don't care if it's already assigned
385 pass
386
387
388def create_users(users):
389 """Create tenants from resource definition.
390
391 Don't create the tenants if they already exist.
392 """
393 global USERS
394 LOG.info("Creating users")
395 admin = keystone_admin()
396 for u in users:
397 try:
Daniel Melladob04da902015-11-20 17:43:12 +0100398 tenant = identity.get_tenant_by_name(admin.tenants, u['tenant'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900399 except lib_exc.NotFound:
Sean Dague655e0af2014-05-29 09:00:22 -0400400 LOG.error("Tenant: %s - not found" % u['tenant'])
401 continue
402 try:
Daniel Mellado82c83a52015-12-09 15:16:49 +0000403 identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000404 tenant['id'], u['name'])
zhangguoqing6c096642016-01-04 06:17:21 +0000405 LOG.warning("User '%s' already exists in this environment"
406 % u['name'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900407 except lib_exc.NotFound:
Daniel Mellado82c83a52015-12-09 15:16:49 +0000408 admin.users.create_user(
Sean Dague655e0af2014-05-29 09:00:22 -0400409 u['name'], u['pass'], tenant['id'],
410 "%s@%s" % (u['name'], tenant['id']),
411 enabled=True)
412
413
Emilien Macchibb71e072014-07-05 19:18:52 +0200414def destroy_users(users):
415 admin = keystone_admin()
416 for user in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100417 tenant_id = identity.get_tenant_by_name(admin.tenants,
Ken'ichi Ohmichi6ea3f982015-11-09 12:41:13 +0000418 user['tenant'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000419 user_id = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000420 tenant_id, user['name'])['id']
Daniel Mellado82c83a52015-12-09 15:16:49 +0000421 admin.users.delete_user(user_id)
Emilien Macchibb71e072014-07-05 19:18:52 +0200422
423
Sean Dague655e0af2014-05-29 09:00:22 -0400424def collect_users(users):
425 global USERS
Joe Gordon618c9fb2014-07-16 15:40:01 +0200426 LOG.info("Collecting users")
Sean Dague655e0af2014-05-29 09:00:22 -0400427 admin = keystone_admin()
428 for u in users:
Daniel Melladob04da902015-11-20 17:43:12 +0100429 tenant = identity.get_tenant_by_name(admin.tenants, u['tenant'])
Sean Dague655e0af2014-05-29 09:00:22 -0400430 u['tenant_id'] = tenant['id']
431 USERS[u['name']] = u
Daniel Mellado82c83a52015-12-09 15:16:49 +0000432 body = identity.get_user_by_username(admin.tenants,
Ken'ichi Ohmichid9fed312015-11-09 13:05:32 +0000433 tenant['id'], u['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400434 USERS[u['name']]['id'] = body['id']
435
436
437class JavelinCheck(unittest.TestCase):
438 def __init__(self, users, resources):
439 super(JavelinCheck, self).__init__()
440 self.users = users
441 self.res = resources
442
443 def runTest(self, *args):
444 pass
445
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200446 def _ping_ip(self, ip_addr, count, namespace=None):
447 if namespace is None:
448 ping_cmd = "ping -c1 " + ip_addr
449 else:
450 ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
451 ip_addr)
452 for current in range(count):
453 return_code = os.system(ping_cmd)
454 if return_code is 0:
455 break
456 self.assertNotEqual(current, count - 1,
457 "Server is not pingable at %s" % ip_addr)
458
Sean Dague655e0af2014-05-29 09:00:22 -0400459 def check(self):
460 self.check_users()
461 self.check_objects()
462 self.check_servers()
Emilien Macchid18fec12014-09-15 14:32:54 -0400463 self.check_volumes()
Chris Dent878f3782014-06-30 17:04:15 +0100464 self.check_telemetry()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200465 self.check_secgroups()
466
467 # validate neutron is enabled and ironic disabled:
468 # Tenant network isolation is not supported when using ironic.
469 # "admin" has set up a neutron flat network environment within a shared
470 # fixed network for all tenants to use.
471 # In this case, network/subnet/router creation can be skipped and the
472 # server booted the same as nova network.
473 if (CONF.service_available.neutron and
474 not CONF.baremetal.driver_enabled):
475 self.check_networking()
Sean Dague655e0af2014-05-29 09:00:22 -0400476
477 def check_users(self):
478 """Check that the users we expect to exist, do.
479
480 We don't use the resource list for this because we need to validate
481 that things like tenantId didn't drift across versions.
482 """
Joe Gordon618c9fb2014-07-16 15:40:01 +0200483 LOG.info("checking users")
Matthew Treinish71426682015-04-23 11:19:38 -0400484 for name, user in six.iteritems(self.users):
Sean Dague655e0af2014-05-29 09:00:22 -0400485 client = keystone_admin()
Daniel Mellado82c83a52015-12-09 15:16:49 +0000486 found = client.users.show_user(user['id'])['user']
Sean Dague655e0af2014-05-29 09:00:22 -0400487 self.assertEqual(found['name'], user['name'])
488 self.assertEqual(found['tenantId'], user['tenant_id'])
489
490 # also ensure we can auth with that user, and do something
491 # on the cloud. We don't care about the results except that it
492 # remains authorized.
493 client = client_for_user(user['name'])
David Kranzae99b9a2015-02-16 13:37:01 -0500494 client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400495
496 def check_objects(self):
497 """Check that the objects created are still there."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000498 if not self.res.get('objects'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000499 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200500 LOG.info("checking objects")
Sean Dague655e0af2014-05-29 09:00:22 -0400501 for obj in self.res['objects']:
502 client = client_for_user(obj['owner'])
503 r, contents = client.objects.get_object(
504 obj['container'], obj['name'])
505 source = _file_contents(obj['file'])
506 self.assertEqual(contents, source)
507
508 def check_servers(self):
509 """Check that the servers are still up and running."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000510 if not self.res.get('servers'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000511 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200512 LOG.info("checking servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400513 for server in self.res['servers']:
514 client = client_for_user(server['owner'])
515 found = _get_server_by_name(client, server['name'])
516 self.assertIsNotNone(
517 found,
518 "Couldn't find expected server %s" % server['name'])
519
ghanshyam0f825252015-08-25 16:02:50 +0900520 found = client.servers.show_server(found['id'])['server']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200521 # validate neutron is enabled and ironic disabled:
522 if (CONF.service_available.neutron and
523 not CONF.baremetal.driver_enabled):
Emilien Macchic3e3e292015-03-11 17:42:08 -0400524 _floating_is_alive = False
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200525 for network_name, body in found['addresses'].items():
526 for addr in body:
527 ip = addr['addr']
lanoux283273b2015-12-04 03:01:54 -0800528 # Use floating IP, fixed IP or other type to
529 # reach the server.
Emilien Macchic3e3e292015-03-11 17:42:08 -0400530 # This is useful in multi-node environment.
lanoux283273b2015-12-04 03:01:54 -0800531 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400532 if addr.get('OS-EXT-IPS:type',
533 'floating') == 'floating':
534 self._ping_ip(ip, 60)
535 _floating_is_alive = True
lanoux283273b2015-12-04 03:01:54 -0800536 elif CONF.validation.connect_method == 'fixed':
537 if addr.get('OS-EXT-IPS:type',
538 'fixed') == 'fixed':
539 namespace = _get_router_namespace(client,
540 network_name)
541 self._ping_ip(ip, 60, namespace)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200542 else:
543 self._ping_ip(ip, 60)
lanoux283273b2015-12-04 03:01:54 -0800544 # If CONF.validation.connect_method is floating, validate
545 # that the floating IP is attached to the server and the
546 # the server is pingable.
547 if CONF.validation.connect_method == 'floating':
Emilien Macchic3e3e292015-03-11 17:42:08 -0400548 self.assertTrue(_floating_is_alive,
549 "Server %s has no floating IP." %
550 server['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200551 else:
552 addr = found['addresses']['private'][0]['addr']
553 self._ping_ip(addr, 60)
554
555 def check_secgroups(self):
Joe H. Rahme02736732015-01-27 18:33:09 +0100556 """Check that the security groups still exist."""
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200557 LOG.info("Checking security groups")
558 for secgroup in self.res['secgroups']:
559 client = client_for_user(secgroup['owner'])
560 found = _get_resource_by_name(client.secgroups, 'security_groups',
561 secgroup['name'])
562 self.assertIsNotNone(
563 found,
564 "Couldn't find expected secgroup %s" % secgroup['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400565
Chris Dent878f3782014-06-30 17:04:15 +0100566 def check_telemetry(self):
567 """Check that ceilometer provides a sane sample.
568
nayna-patel1dfbedb2015-08-04 11:07:56 +0000569 Confirm that there is more than one sample and that they have the
Chris Dent878f3782014-06-30 17:04:15 +0100570 expected metadata.
571
572 If in check mode confirm that the oldest sample available is from
573 before the upgrade.
574 """
Chris Dent0b76f2f2014-10-10 14:24:28 +0100575 if not self.res.get('telemetry'):
576 return
Chris Dent878f3782014-06-30 17:04:15 +0100577 LOG.info("checking telemetry")
578 for server in self.res['servers']:
579 client = client_for_user(server['owner'])
David Kranz20d06f42015-02-09 14:54:15 -0500580 body = client.telemetry.list_samples(
Chris Dent878f3782014-06-30 17:04:15 +0100581 'instance',
582 query=('metadata.display_name', 'eq', server['name'])
583 )
Chris Dent878f3782014-06-30 17:04:15 +0100584 self.assertTrue(len(body) >= 1, 'expecting at least one sample')
585 self._confirm_telemetry_sample(server, body[-1])
586
Emilien Macchi626b4f82014-06-15 21:44:29 +0200587 def check_volumes(self):
588 """Check that the volumes are still there and attached."""
Joe Gordon22cd6de2014-07-25 00:16:17 +0000589 if not self.res.get('volumes'):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000590 return
Joe Gordon618c9fb2014-07-16 15:40:01 +0200591 LOG.info("checking volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +0200592 for volume in self.res['volumes']:
593 client = client_for_user(volume['owner'])
Emilien Macchid18fec12014-09-15 14:32:54 -0400594 vol_body = _get_volume_by_name(client, volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200595 self.assertIsNotNone(
Emilien Macchid18fec12014-09-15 14:32:54 -0400596 vol_body,
Emilien Macchi626b4f82014-06-15 21:44:29 +0200597 "Couldn't find expected volume %s" % volume['name'])
598
599 # Verify that a volume's attachment retrieved
600 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -0400601 attachment = client.volumes.get_attachment_from_volume(vol_body)
602 self.assertEqual(vol_body['id'], attachment['volume_id'])
Emilien Macchi626b4f82014-06-15 21:44:29 +0200603 self.assertEqual(server_id, attachment['server_id'])
604
Chris Dent878f3782014-06-30 17:04:15 +0100605 def _confirm_telemetry_sample(self, server, sample):
606 """Check this sample matches the expected resource metadata."""
607 # Confirm display_name
608 self.assertEqual(server['name'],
609 sample['resource_metadata']['display_name'])
610 # Confirm instance_type of flavor
611 flavor = sample['resource_metadata'].get(
612 'flavor.name',
613 sample['resource_metadata'].get('instance_type')
614 )
615 self.assertEqual(server['flavor'], flavor)
616 # Confirm the oldest sample was created before upgrade.
617 if OPTS.mode == 'check':
618 oldest_timestamp = timeutils.normalize_time(
619 timeutils.parse_isotime(sample['timestamp']))
620 self.assertTrue(
621 oldest_timestamp < JAVELIN_START,
622 'timestamp should come before start of second javelin run'
623 )
624
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200625 def check_networking(self):
626 """Check that the networks are still there."""
627 for res_type in ('networks', 'subnets', 'routers'):
628 for res in self.res[res_type]:
629 client = client_for_user(res['owner'])
630 found = _get_resource_by_name(client.networks, res_type,
631 res['name'])
632 self.assertIsNotNone(
633 found,
634 "Couldn't find expected resource %s" % res['name'])
635
Sean Dague655e0af2014-05-29 09:00:22 -0400636
637#######################
638#
639# OBJECTS
640#
641#######################
642
643
644def _file_contents(fname):
645 with open(fname, 'r') as f:
646 return f.read()
647
648
649def create_objects(objects):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000650 if not objects:
651 return
Sean Dague655e0af2014-05-29 09:00:22 -0400652 LOG.info("Creating objects")
653 for obj in objects:
654 LOG.debug("Object %s" % obj)
Joe H. Rahme9c9fc4d2015-03-31 00:35:05 +0200655 swift_role = obj.get('swift_role', 'Member')
656 _assign_swift_role(obj['owner'], swift_role)
Sean Dague655e0af2014-05-29 09:00:22 -0400657 client = client_for_user(obj['owner'])
658 client.containers.create_container(obj['container'])
659 client.objects.create_object(
660 obj['container'], obj['name'],
661 _file_contents(obj['file']))
662
Emilien Macchibb71e072014-07-05 19:18:52 +0200663
664def destroy_objects(objects):
665 for obj in objects:
666 client = client_for_user(obj['owner'])
667 r, body = client.objects.delete_object(obj['container'], obj['name'])
Emilien Macchid70f5102014-09-10 09:54:49 -0400668 if not (200 <= int(r['status']) < 299):
Emilien Macchibb71e072014-07-05 19:18:52 +0200669 raise ValueError("unable to destroy object: [%s] %s" % (r, body))
670
671
Sean Dague655e0af2014-05-29 09:00:22 -0400672#######################
673#
674# IMAGES
675#
676#######################
677
678
Sean Dague319b37a2014-07-11 07:28:11 -0400679def _resolve_image(image, imgtype):
680 name = image[imgtype]
681 fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
682 return name, fname
683
684
Joe Gordon6f0426c2014-07-25 01:10:28 +0000685def _get_image_by_name(client, name):
Ken'ichi Ohmichie3acc122015-05-22 00:32:54 +0000686 body = client.images.list_images()
Joe Gordon6f0426c2014-07-25 01:10:28 +0000687 for image in body:
688 if name == image['name']:
689 return image
690 return None
691
692
Sean Dague655e0af2014-05-29 09:00:22 -0400693def create_images(images):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000694 if not images:
695 return
Joe Gordona18d6862014-07-24 22:55:46 +0000696 LOG.info("Creating images")
Sean Dague655e0af2014-05-29 09:00:22 -0400697 for image in images:
698 client = client_for_user(image['owner'])
699
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100700 # DEPRECATED: 'format' was used for ami images
701 # Use 'disk_format' and 'container_format' instead
702 if 'format' in image:
703 LOG.warning("Deprecated: 'format' is deprecated for images "
704 "description. Please use 'disk_format' and 'container_"
705 "format' instead.")
706 image['disk_format'] = image['format']
707 image['container_format'] = image['format']
708
Sean Dague655e0af2014-05-29 09:00:22 -0400709 # only upload a new image if the name isn't there
Joe Gordon6f0426c2014-07-25 01:10:28 +0000710 if _get_image_by_name(client, image['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000711 LOG.info("Image '%s' already exists" % image['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400712 continue
713
714 # special handling for 3 part image
715 extras = {}
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100716 if image['disk_format'] == 'ami':
Sean Dague319b37a2014-07-11 07:28:11 -0400717 name, fname = _resolve_image(image, 'aki')
David Kranz34f18782015-01-06 13:43:55 -0500718 aki = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400719 'javelin_' + name, 'aki', 'aki')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000720 client.images.store_image_file(aki.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400721 extras['kernel_id'] = aki.get('id')
722
Sean Dague319b37a2014-07-11 07:28:11 -0400723 name, fname = _resolve_image(image, 'ari')
David Kranz34f18782015-01-06 13:43:55 -0500724 ari = client.images.create_image(
Sean Dague319b37a2014-07-11 07:28:11 -0400725 'javelin_' + name, 'ari', 'ari')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000726 client.images.store_image_file(ari.get('id'), open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400727 extras['ramdisk_id'] = ari.get('id')
728
Sean Dague319b37a2014-07-11 07:28:11 -0400729 _, fname = _resolve_image(image, 'file')
David Kranz34f18782015-01-06 13:43:55 -0500730 body = client.images.create_image(
Joe H. Rahme4352d5d2015-03-09 17:41:18 +0100731 image['name'], image['container_format'],
732 image['disk_format'], **extras)
Sean Dague655e0af2014-05-29 09:00:22 -0400733 image_id = body.get('id')
Ken'ichi Ohmichi66494e92015-06-08 04:28:10 +0000734 client.images.store_image_file(image_id, open(fname, 'r'))
Sean Dague655e0af2014-05-29 09:00:22 -0400735
736
Joe Gordon6f0426c2014-07-25 01:10:28 +0000737def destroy_images(images):
738 if not images:
739 return
740 LOG.info("Destroying images")
741 for image in images:
742 client = client_for_user(image['owner'])
743
744 response = _get_image_by_name(client, image['name'])
745 if not response:
nayna-patel1dfbedb2015-08-04 11:07:56 +0000746 LOG.info("Image '%s' does not exist" % image['name'])
Joe Gordon6f0426c2014-07-25 01:10:28 +0000747 continue
748 client.images.delete_image(response['id'])
749
750
Sean Dague655e0af2014-05-29 09:00:22 -0400751#######################
752#
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200753# NETWORKS
754#
755#######################
756
757def _get_router_namespace(client, network):
758 network_id = _get_resource_by_name(client.networks,
759 'networks', network)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000760 n_body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200761 for router in n_body['routers']:
762 router_id = router['id']
Ken'ichi Ohmichif3110f02016-03-21 12:29:03 -0700763 r_body = client.ports.list_ports(device_id=router_id)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200764 for port in r_body['ports']:
765 if port['network_id'] == network_id:
766 return "qrouter-%s" % router_id
767
768
769def _get_resource_by_name(client, resource, name):
770 get_resources = getattr(client, 'list_%s' % resource)
771 if get_resources is None:
772 raise AttributeError("client doesn't have method list_%s" % resource)
David Kranz34e88122014-12-11 15:24:05 -0500773 # Until all tempest client methods are changed to return only one value,
774 # we cannot assume they all have the same signature so we need to discard
775 # the unused response first value it two values are being returned.
776 body = get_resources()
Brandon Palmecd2ec02016-02-25 09:38:36 -0600777 if isinstance(body, tuple):
David Kranz34e88122014-12-11 15:24:05 -0500778 body = body[1]
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200779 if isinstance(body, dict):
780 body = body[resource]
781 for res in body:
782 if name == res['name']:
783 return res
784 raise ValueError('%s not found in %s resources' % (name, resource))
785
786
787def create_networks(networks):
788 LOG.info("Creating networks")
789 for network in networks:
790 client = client_for_user(network['owner'])
791
792 # only create a network if the name isn't here
David Kranz34e88122014-12-11 15:24:05 -0500793 body = client.networks.list_networks()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200794 if any(item['name'] == network['name'] for item in body['networks']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000795 LOG.warning("Duplicated network name: %s" % network['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200796 continue
797
798 client.networks.create_network(name=network['name'])
799
800
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100801def destroy_networks(networks):
802 LOG.info("Destroying subnets")
803 for network in networks:
804 client = client_for_user(network['owner'])
805 network_id = _get_resource_by_name(client.networks, 'networks',
806 network['name'])['id']
807 client.networks.delete_network(network_id)
808
809
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200810def create_subnets(subnets):
811 LOG.info("Creating subnets")
812 for subnet in subnets:
813 client = client_for_user(subnet['owner'])
814
815 network = _get_resource_by_name(client.networks, 'networks',
816 subnet['network'])
817 ip_version = netaddr.IPNetwork(subnet['range']).version
818 # ensure we don't overlap with another subnet in the network
819 try:
820 client.networks.create_subnet(network_id=network['id'],
821 cidr=subnet['range'],
822 name=subnet['name'],
823 ip_version=ip_version)
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900824 except lib_exc.BadRequest as e:
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200825 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
826 if not is_overlapping_cidr:
827 raise
828
829
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100830def destroy_subnets(subnets):
831 LOG.info("Destroying subnets")
832 for subnet in subnets:
833 client = client_for_user(subnet['owner'])
John Warren3961acd2015-10-02 14:38:53 -0400834 subnet_id = _get_resource_by_name(client.subnets,
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100835 'subnets', subnet['name'])['id']
John Warren3961acd2015-10-02 14:38:53 -0400836 client.subnets.delete_subnet(subnet_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100837
838
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200839def create_routers(routers):
840 LOG.info("Creating routers")
841 for router in routers:
842 client = client_for_user(router['owner'])
843
844 # only create a router if the name isn't here
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000845 body = client.routers.list_routers()
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200846 if any(item['name'] == router['name'] for item in body['routers']):
nayna-patel1dfbedb2015-08-04 11:07:56 +0000847 LOG.warning("Duplicated router name: %s" % router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200848 continue
849
Ken'ichi Ohmichi6665c972016-02-24 13:09:09 -0800850 client.networks.create_router(name=router['name'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200851
852
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100853def destroy_routers(routers):
854 LOG.info("Destroying routers")
855 for router in routers:
856 client = client_for_user(router['owner'])
857 router_id = _get_resource_by_name(client.networks,
858 'routers', router['name'])['id']
859 for subnet in router['subnet']:
860 subnet_id = _get_resource_by_name(client.networks,
861 'subnets', subnet)['id']
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000862 client.routers.remove_router_interface(router_id,
863 subnet_id=subnet_id)
864 client.routers.delete_router(router_id)
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100865
866
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200867def add_router_interface(routers):
868 for router in routers:
869 client = client_for_user(router['owner'])
870 router_id = _get_resource_by_name(client.networks,
871 'routers', router['name'])['id']
872
873 for subnet in router['subnet']:
874 subnet_id = _get_resource_by_name(client.networks,
875 'subnets', subnet)['id']
876 # connect routers to their subnets
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000877 client.routers.add_router_interface(router_id,
878 subnet_id=subnet_id)
nayna-patel1dfbedb2015-08-04 11:07:56 +0000879 # connect routers to external network if set to "gateway"
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200880 if router['gateway']:
881 if CONF.network.public_network_id:
882 ext_net = CONF.network.public_network_id
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000883 client.routers._update_router(
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200884 router_id, set_enable_snat=True,
885 external_gateway_info={"network_id": ext_net})
886 else:
887 raise ValueError('public_network_id is not configured.')
888
889
890#######################
891#
Sean Dague655e0af2014-05-29 09:00:22 -0400892# SERVERS
893#
894#######################
895
896def _get_server_by_name(client, name):
David Kranzae99b9a2015-02-16 13:37:01 -0500897 body = client.servers.list_servers()
Sean Dague655e0af2014-05-29 09:00:22 -0400898 for server in body['servers']:
899 if name == server['name']:
900 return server
901 return None
902
903
Sean Dague655e0af2014-05-29 09:00:22 -0400904def _get_flavor_by_name(client, name):
ghanshyam19973be2015-08-18 15:46:42 +0900905 body = client.flavors.list_flavors()['flavors']
Sean Dague655e0af2014-05-29 09:00:22 -0400906 for flavor in body:
907 if name == flavor['name']:
908 return flavor
909 return None
910
911
912def create_servers(servers):
Joe Gordonb9bcdd82014-07-17 15:44:57 +0000913 if not servers:
914 return
Joe Gordona18d6862014-07-24 22:55:46 +0000915 LOG.info("Creating servers")
Sean Dague655e0af2014-05-29 09:00:22 -0400916 for server in servers:
917 client = client_for_user(server['owner'])
918
919 if _get_server_by_name(client, server['name']):
Joe Gordona18d6862014-07-24 22:55:46 +0000920 LOG.info("Server '%s' already exists" % server['name'])
Sean Dague655e0af2014-05-29 09:00:22 -0400921 continue
922
923 image_id = _get_image_by_name(client, server['image'])['id']
924 flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200925 # validate neutron is enabled and ironic disabled
926 kwargs = dict()
927 if (CONF.service_available.neutron and
928 not CONF.baremetal.driver_enabled and server.get('networks')):
929 get_net_id = lambda x: (_get_resource_by_name(
930 client.networks, 'networks', x)['id'])
931 kwargs['networks'] = [{'uuid': get_net_id(network)}
932 for network in server['networks']]
David Kranz0fb14292015-02-11 15:55:20 -0500933 body = client.servers.create_server(
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000934 name=server['name'], imageRef=image_id, flavorRef=flavor_id,
935 **kwargs)['server']
Joe Gordon10f260b2014-07-24 23:27:19 +0000936 server_id = body['id']
937 client.servers.wait_for_server_status(server_id, 'ACTIVE')
nayna-patel1dfbedb2015-08-04 11:07:56 +0000938 # create security group(s) after server spawning
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200939 for secgroup in server['secgroups']:
Ken'ichi Ohmichie6349f32015-12-09 06:47:54 +0000940 client.servers.add_security_group(server_id, name=secgroup)
lanoux283273b2015-12-04 03:01:54 -0800941 if CONF.validation.connect_method == 'floating':
Joe H. Rahme9350a102015-03-29 17:39:20 +0200942 floating_ip_pool = server.get('floating_ip_pool')
943 floating_ip = client.floating_ips.create_floating_ip(
ghanshyam9a3a9a22015-08-18 17:03:55 +0900944 pool_name=floating_ip_pool)['floating_ip']
Emilien Macchic3e3e292015-03-11 17:42:08 -0400945 client.floating_ips.associate_floating_ip_to_server(
946 floating_ip['ip'], server_id)
Sean Dague655e0af2014-05-29 09:00:22 -0400947
948
Joe Gordondb63b1c2014-07-24 23:21:21 +0000949def destroy_servers(servers):
950 if not servers:
951 return
952 LOG.info("Destroying servers")
953 for server in servers:
954 client = client_for_user(server['owner'])
955
Emilien Macchidc5bae22015-03-16 08:49:02 -0400956 response = _get_server_by_name(client, server['name'])
957 if not response:
Joe Gordondb63b1c2014-07-24 23:21:21 +0000958 LOG.info("Server '%s' does not exist" % server['name'])
959 continue
960
Emilien Macchidc5bae22015-03-16 08:49:02 -0400961 # TODO(EmilienM): disassociate floating IP from server and release it.
962 client.servers.delete_server(response['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000963 waiters.wait_for_server_termination(client.servers, response['id'],
964 ignore_error=True)
Joe Gordondb63b1c2014-07-24 23:21:21 +0000965
966
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200967def create_secgroups(secgroups):
968 LOG.info("Creating security groups")
969 for secgroup in secgroups:
970 client = client_for_user(secgroup['owner'])
971
972 # only create a security group if the name isn't here
973 # i.e. a security group may be used by another server
974 # only create a router if the name isn't here
ghanshyamb610b772015-08-24 17:29:38 +0900975 body = client.secgroups.list_security_groups()['security_groups']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200976 if any(item['name'] == secgroup['name'] for item in body):
977 LOG.warning("Security group '%s' already exists" %
978 secgroup['name'])
979 continue
980
David Kranz9964b4e2015-02-06 15:45:29 -0500981 body = client.secgroups.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900982 name=secgroup['name'],
983 description=secgroup['description'])['security_group']
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200984 secgroup_id = body['id']
985 # for each security group, create the rules
986 for rule in secgroup['rules']:
987 ip_proto, from_port, to_port, cidr = rule.split()
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000988 client.secrules.create_security_group_rule(
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000989 parent_group_id=secgroup_id, ip_protocol=ip_proto,
990 from_port=from_port, to_port=to_port, cidr=cidr)
Emilien Macchi7a2348b2014-06-16 07:32:11 +0200991
992
Jakub Libosvar3791ac92014-11-11 13:23:44 +0100993def destroy_secgroups(secgroups):
994 LOG.info("Destroying security groups")
995 for secgroup in secgroups:
996 client = client_for_user(secgroup['owner'])
997 sg_id = _get_resource_by_name(client.secgroups,
998 'security_groups',
999 secgroup['name'])
1000 # sg rules are deleted automatically
1001 client.secgroups.delete_security_group(sg_id['id'])
1002
1003
Sean Dague655e0af2014-05-29 09:00:22 -04001004#######################
1005#
Emilien Macchi626b4f82014-06-15 21:44:29 +02001006# VOLUMES
1007#
1008#######################
1009
1010def _get_volume_by_name(client, name):
John Warren6177c9e2015-08-19 20:00:17 +00001011 body = client.volumes.list_volumes()['volumes']
Emilien Macchid18fec12014-09-15 14:32:54 -04001012 for volume in body:
1013 if name == volume['display_name']:
Emilien Macchi626b4f82014-06-15 21:44:29 +02001014 return volume
1015 return None
1016
1017
1018def create_volumes(volumes):
Chris Dent51e76de2014-10-01 12:07:14 +01001019 if not volumes:
1020 return
1021 LOG.info("Creating volumes")
Emilien Macchi626b4f82014-06-15 21:44:29 +02001022 for volume in volumes:
1023 client = client_for_user(volume['owner'])
1024
1025 # only create a volume if the name isn't here
Emilien Macchid18fec12014-09-15 14:32:54 -04001026 if _get_volume_by_name(client, volume['name']):
1027 LOG.info("volume '%s' already exists" % volume['name'])
Emilien Macchi626b4f82014-06-15 21:44:29 +02001028 continue
1029
Emilien Macchid18fec12014-09-15 14:32:54 -04001030 size = volume['gb']
1031 v_name = volume['name']
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001032 body = client.volumes.create_volume(size=size,
John Warren6177c9e2015-08-19 20:00:17 +00001033 display_name=v_name)['volume']
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -05001034 waiters.wait_for_volume_status(client.volumes, body['id'], 'available')
Emilien Macchi626b4f82014-06-15 21:44:29 +02001035
1036
Emilien Macchibb71e072014-07-05 19:18:52 +02001037def destroy_volumes(volumes):
1038 for volume in volumes:
1039 client = client_for_user(volume['owner'])
1040 volume_id = _get_volume_by_name(client, volume['name'])['id']
Emilien Macchi5ebc27b2014-09-15 14:30:35 -04001041 client.volumes.detach_volume(volume_id)
1042 client.volumes.delete_volume(volume_id)
Emilien Macchibb71e072014-07-05 19:18:52 +02001043
1044
Emilien Macchi626b4f82014-06-15 21:44:29 +02001045def attach_volumes(volumes):
1046 for volume in volumes:
1047 client = client_for_user(volume['owner'])
Emilien Macchi626b4f82014-06-15 21:44:29 +02001048 server_id = _get_server_by_name(client, volume['server'])['id']
Emilien Macchid18fec12014-09-15 14:32:54 -04001049 volume_id = _get_volume_by_name(client, volume['name'])['id']
1050 device = volume['device']
Ghanshyam8fc0ed22015-12-18 10:25:14 +09001051 client.volumes.attach_volume(volume_id,
1052 instance_uuid=server_id,
1053 mountpoint=device)
Emilien Macchi626b4f82014-06-15 21:44:29 +02001054
1055
1056#######################
1057#
Sean Dague655e0af2014-05-29 09:00:22 -04001058# MAIN LOGIC
1059#
1060#######################
1061
1062def create_resources():
1063 LOG.info("Creating Resources")
1064 # first create keystone level resources, and we need to be admin
nayna-patel1dfbedb2015-08-04 11:07:56 +00001065 # for this.
Sean Dague655e0af2014-05-29 09:00:22 -04001066 create_tenants(RES['tenants'])
1067 create_users(RES['users'])
1068 collect_users(RES['users'])
1069
1070 # next create resources in a well known order
1071 create_objects(RES['objects'])
1072 create_images(RES['images'])
Emilien Macchi7a2348b2014-06-16 07:32:11 +02001073
1074 # validate neutron is enabled and ironic is disabled
1075 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1076 create_networks(RES['networks'])
1077 create_subnets(RES['subnets'])
1078 create_routers(RES['routers'])
1079 add_router_interface(RES['routers'])
1080
1081 create_secgroups(RES['secgroups'])
Emilien Macchid18fec12014-09-15 14:32:54 -04001082 create_volumes(RES['volumes'])
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001083
1084 # Only attempt attaching the volumes if servers are defined in the
nayna-patel1dfbedb2015-08-04 11:07:56 +00001085 # resource file
Joe H. Rahmec96129b2015-03-30 11:23:31 +02001086 if 'servers' in RES:
1087 create_servers(RES['servers'])
1088 attach_volumes(RES['volumes'])
Sean Dague655e0af2014-05-29 09:00:22 -04001089
1090
Joe Gordondb63b1c2014-07-24 23:21:21 +00001091def destroy_resources():
1092 LOG.info("Destroying Resources")
1093 # Destroy in inverse order of create
Joe Gordondb63b1c2014-07-24 23:21:21 +00001094 destroy_servers(RES['servers'])
Joe Gordon6f0426c2014-07-25 01:10:28 +00001095 destroy_images(RES['images'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001096 destroy_objects(RES['objects'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001097 destroy_volumes(RES['volumes'])
Jakub Libosvar3791ac92014-11-11 13:23:44 +01001098 if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
1099 destroy_routers(RES['routers'])
1100 destroy_subnets(RES['subnets'])
1101 destroy_networks(RES['networks'])
1102 destroy_secgroups(RES['secgroups'])
Emilien Macchibb71e072014-07-05 19:18:52 +02001103 destroy_users(RES['users'])
1104 destroy_tenants(RES['tenants'])
zhangguoqing6c096642016-01-04 06:17:21 +00001105 LOG.warning("Destroy mode incomplete")
Joe Gordon6f0426c2014-07-25 01:10:28 +00001106
Joe Gordondb63b1c2014-07-24 23:21:21 +00001107
Sean Dague655e0af2014-05-29 09:00:22 -04001108def get_options():
1109 global OPTS
1110 parser = argparse.ArgumentParser(
1111 description='Create and validate a fixed set of OpenStack resources')
1112 parser.add_argument('-m', '--mode',
1113 metavar='<create|check|destroy>',
1114 required=True,
1115 help=('One of (create, check, destroy)'))
1116 parser.add_argument('-r', '--resources',
1117 required=True,
1118 metavar='resourcefile.yaml',
1119 help='Resources definition yaml file')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001120
Sean Dague319b37a2014-07-11 07:28:11 -04001121 parser.add_argument(
1122 '-d', '--devstack-base',
1123 required=True,
1124 metavar='/opt/stack/old',
1125 help='Devstack base directory for retrieving artifacts')
Joe Gordon28a84ae2014-07-17 15:38:28 +00001126 parser.add_argument(
1127 '-c', '--config-file',
1128 metavar='/etc/tempest.conf',
1129 help='path to javelin2(tempest) config file')
1130
Sean Dague655e0af2014-05-29 09:00:22 -04001131 # auth bits, letting us also just source the devstack openrc
1132 parser.add_argument('--os-username',
1133 metavar='<auth-user-name>',
1134 default=os.environ.get('OS_USERNAME'),
1135 help=('Defaults to env[OS_USERNAME].'))
1136 parser.add_argument('--os-password',
1137 metavar='<auth-password>',
1138 default=os.environ.get('OS_PASSWORD'),
1139 help=('Defaults to env[OS_PASSWORD].'))
1140 parser.add_argument('--os-tenant-name',
1141 metavar='<auth-tenant-name>',
1142 default=os.environ.get('OS_TENANT_NAME'),
1143 help=('Defaults to env[OS_TENANT_NAME].'))
1144
1145 OPTS = parser.parse_args()
1146 if OPTS.mode not in ('create', 'check', 'destroy'):
1147 print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
1148 parser.print_help()
1149 sys.exit(1)
Joe Gordon28a84ae2014-07-17 15:38:28 +00001150 if OPTS.config_file:
1151 config.CONF.set_config_path(OPTS.config_file)
Sean Dague655e0af2014-05-29 09:00:22 -04001152
1153
Joe Gordon915eb8e2014-07-17 11:25:46 +02001154def setup_logging():
Sean Dague655e0af2014-05-29 09:00:22 -04001155 global LOG
Doug Hellmann583ce2c2015-03-11 14:55:46 +00001156 logging.setup(CONF, __name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001157 LOG = logging.getLogger(__name__)
Sean Dague655e0af2014-05-29 09:00:22 -04001158
1159
1160def main():
Matthew Treinish0ee37442016-01-12 16:05:40 -05001161 print("Javelin is deprecated and will be removed from Tempest in the "
1162 "future.")
Sean Dague655e0af2014-05-29 09:00:22 -04001163 global RES
1164 get_options()
1165 setup_logging()
Chris Dent51e76de2014-10-01 12:07:14 +01001166 RES.update(load_resources(OPTS.resources))
Sean Dague655e0af2014-05-29 09:00:22 -04001167
1168 if OPTS.mode == 'create':
1169 create_resources()
Joe Gordon1a097002014-07-24 23:44:08 +00001170 # Make sure the resources we just created actually work
1171 checker = JavelinCheck(USERS, RES)
1172 checker.check()
Sean Dague655e0af2014-05-29 09:00:22 -04001173 elif OPTS.mode == 'check':
1174 collect_users(RES['users'])
1175 checker = JavelinCheck(USERS, RES)
1176 checker.check()
1177 elif OPTS.mode == 'destroy':
Joe Gordondb63b1c2014-07-24 23:21:21 +00001178 collect_users(RES['users'])
1179 destroy_resources()
Sean Dague655e0af2014-05-29 09:00:22 -04001180 else:
1181 LOG.error('Unknown mode %s' % OPTS.mode)
1182 return 1
Joe Gordon246353a2014-07-18 00:10:28 +02001183 LOG.info('javelin2 successfully finished')
Sean Dague655e0af2014-05-29 09:00:22 -04001184 return 0
1185
1186if __name__ == "__main__":
1187 sys.exit(main())