blob: 6fc5fcc5c73a494bfa0bde1c33aa71f77a307243 [file] [log] [blame]
sslypushenko0de7d052015-04-16 18:49:55 +03001#!/usr/bin/env python
2
3# Copyright 2015 Mirantis, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import argparse
David Kranz0aa4a7b2015-06-08 13:25:41 -040018import netaddr
sslypushenko0de7d052015-04-16 18:49:55 +030019import os
20
21from oslo_log import log as logging
22import yaml
23
24from tempest import config
25from tempest import exceptions
26from tempest.services.identity.v2.json import identity_client
David Kranz0aa4a7b2015-06-08 13:25:41 -040027from tempest.services.network.json import network_client
sslypushenko0de7d052015-04-16 18:49:55 +030028import tempest_lib.auth
29from tempest_lib.common.utils import data_utils
30import tempest_lib.exceptions
31
32LOG = None
33CONF = config.CONF
34
35
36def setup_logging():
37 global LOG
38 logging.setup(CONF, __name__)
39 LOG = logging.getLogger(__name__)
40
41
David Kranz0aa4a7b2015-06-08 13:25:41 -040042def get_admin_clients(opts):
sslypushenko0de7d052015-04-16 18:49:55 +030043 _creds = tempest_lib.auth.KeystoneV2Credentials(
44 username=opts.os_username,
45 password=opts.os_password,
46 tenant_name=opts.os_tenant_name)
47 auth_params = {
48 'disable_ssl_certificate_validation':
49 CONF.identity.disable_ssl_certificate_validation,
50 'ca_certs': CONF.identity.ca_certificates_file,
51 'trace_requests': CONF.debug.trace_requests
52 }
53 _auth = tempest_lib.auth.KeystoneV2AuthProvider(
54 _creds, CONF.identity.uri, **auth_params)
55 params = {
56 'disable_ssl_certificate_validation':
57 CONF.identity.disable_ssl_certificate_validation,
58 'ca_certs': CONF.identity.ca_certificates_file,
59 'trace_requests': CONF.debug.trace_requests,
60 'build_interval': CONF.compute.build_interval,
61 'build_timeout': CONF.compute.build_timeout
62 }
David Kranz0aa4a7b2015-06-08 13:25:41 -040063 identity_admin = identity_client.IdentityClientJSON(
sslypushenko0de7d052015-04-16 18:49:55 +030064 _auth,
65 CONF.identity.catalog_type,
66 CONF.identity.region,
67 endpoint_type='adminURL',
68 **params
69 )
David Kranz0aa4a7b2015-06-08 13:25:41 -040070 network_admin = None
71 if (CONF.service_available.neutron and
72 CONF.auth.create_isolated_networks):
73 network_admin = network_client.NetworkClientJSON(
74 _auth,
75 CONF.network.catalog_type,
76 CONF.network.region or CONF.identity.region,
77 endpoint_type='adminURL',
78 **params)
79 return identity_admin, network_admin
sslypushenko0de7d052015-04-16 18:49:55 +030080
81
82def create_resources(opts, resources):
David Kranz0aa4a7b2015-06-08 13:25:41 -040083 identity_admin, network_admin = get_admin_clients(opts)
84 roles = identity_admin.list_roles()
sslypushenko0de7d052015-04-16 18:49:55 +030085 for u in resources['users']:
86 u['role_ids'] = []
87 for r in u.get('roles', ()):
88 try:
89 role = filter(lambda r_: r_['name'] == r, roles)[0]
90 u['role_ids'] += [role['id']]
91 except IndexError:
92 raise exceptions.TempestException(
93 "Role: %s - doesn't exist" % r
94 )
David Kranz0aa4a7b2015-06-08 13:25:41 -040095 existing = [x['name'] for x in identity_admin.list_tenants()]
sslypushenko0de7d052015-04-16 18:49:55 +030096 for tenant in resources['tenants']:
97 if tenant not in existing:
David Kranz0aa4a7b2015-06-08 13:25:41 -040098 identity_admin.create_tenant(tenant)
sslypushenko0de7d052015-04-16 18:49:55 +030099 else:
100 LOG.warn("Tenant '%s' already exists in this environment" % tenant)
101 LOG.info('Tenants created')
102 for u in resources['users']:
103 try:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400104 tenant = identity_admin.get_tenant_by_name(u['tenant'])
sslypushenko0de7d052015-04-16 18:49:55 +0300105 except tempest_lib.exceptions.NotFound:
106 LOG.error("Tenant: %s - not found" % u['tenant'])
107 continue
108 while True:
109 try:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400110 identity_admin.get_user_by_username(tenant['id'], u['name'])
sslypushenko0de7d052015-04-16 18:49:55 +0300111 except tempest_lib.exceptions.NotFound:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400112 identity_admin.create_user(
sslypushenko0de7d052015-04-16 18:49:55 +0300113 u['name'], u['pass'], tenant['id'],
114 "%s@%s" % (u['name'], tenant['id']),
115 enabled=True)
116 break
117 else:
118 LOG.warn("User '%s' already exists in this environment. "
119 "New name generated" % u['name'])
120 u['name'] = random_user_name(opts.tag, u['prefix'])
121
122 LOG.info('Users created')
David Kranz0aa4a7b2015-06-08 13:25:41 -0400123 if network_admin:
124 for u in resources['users']:
125 tenant = identity_admin.get_tenant_by_name(u['tenant'])
126 network_name = create_network_resources(network_admin,
127 tenant['id'],
128 u['name'])
129 u['network'] = network_name
130 LOG.info('Networks created')
sslypushenko0de7d052015-04-16 18:49:55 +0300131 for u in resources['users']:
132 try:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400133 tenant = identity_admin.get_tenant_by_name(u['tenant'])
sslypushenko0de7d052015-04-16 18:49:55 +0300134 except tempest_lib.exceptions.NotFound:
135 LOG.error("Tenant: %s - not found" % u['tenant'])
136 continue
137 try:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400138 user = identity_admin.get_user_by_username(tenant['id'],
139 u['name'])
sslypushenko0de7d052015-04-16 18:49:55 +0300140 except tempest_lib.exceptions.NotFound:
141 LOG.error("User: %s - not found" % u['user'])
142 continue
143 for r in u['role_ids']:
144 try:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400145 identity_admin.assign_user_role(tenant['id'], user['id'], r)
sslypushenko0de7d052015-04-16 18:49:55 +0300146 except tempest_lib.exceptions.Conflict:
147 # don't care if it's already assigned
148 pass
149 LOG.info('Roles assigned')
150 LOG.info('Resources deployed successfully!')
151
152
David Kranz0aa4a7b2015-06-08 13:25:41 -0400153def create_network_resources(network_admin_client, tenant_id, name):
154
155 def _create_network(name):
156 resp_body = network_admin_client.create_network(
157 name=name, tenant_id=tenant_id)
158 return resp_body['network']
159
160 def _create_subnet(subnet_name, network_id):
161 base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
162 mask_bits = CONF.network.tenant_network_mask_bits
163 for subnet_cidr in base_cidr.subnet(mask_bits):
164 try:
165 resp_body = network_admin_client.\
166 create_subnet(
167 network_id=network_id, cidr=str(subnet_cidr),
168 name=subnet_name,
169 tenant_id=tenant_id,
170 enable_dhcp=True,
171 ip_version=4)
172 break
173 except tempest_lib.exceptions.BadRequest as e:
174 if 'overlaps with another subnet' not in str(e):
175 raise
176 else:
177 message = 'Available CIDR for subnet creation could not be found'
178 raise Exception(message)
179 return resp_body['subnet']
180
181 def _create_router(router_name):
182 external_net_id = dict(
183 network_id=CONF.network.public_network_id)
184 resp_body = network_admin_client.create_router(
185 router_name,
186 external_gateway_info=external_net_id,
187 tenant_id=tenant_id)
188 return resp_body['router']
189
190 def _add_router_interface(router_id, subnet_id):
191 network_admin_client.add_router_interface_with_subnet_id(
192 router_id, subnet_id)
193
194 network_name = name + "-network"
195 network = _create_network(network_name)
196 subnet_name = name + "-subnet"
197 subnet = _create_subnet(subnet_name, network['id'])
198 router_name = name + "-router"
199 router = _create_router(router_name)
200 _add_router_interface(router['id'], subnet['id'])
201 return network_name
202
203
sslypushenko0de7d052015-04-16 18:49:55 +0300204def random_user_name(tag, prefix):
205 if tag:
206 return data_utils.rand_name('-'.join((tag, prefix)))
207 else:
208 return data_utils.rand_name(prefix)
209
210
211def generate_resources(opts):
212 spec = [{'number': 1,
213 'prefix': 'primary',
214 'roles': (CONF.auth.tempest_roles +
215 [CONF.object_storage.operator_role])},
216 {'number': 1,
217 'prefix': 'alt',
218 'roles': (CONF.auth.tempest_roles +
219 [CONF.object_storage.operator_role])},
220 {'number': 1,
221 'prefix': 'swift_admin',
222 'roles': (CONF.auth.tempest_roles +
223 [CONF.object_storage.operator_role,
224 CONF.object_storage.reseller_admin_role])},
225 {'number': 1,
226 'prefix': 'stack_owner',
227 'roles': (CONF.auth.tempest_roles +
228 [CONF.orchestration.stack_owner_role])},
229 ]
230 if opts.admin:
231 spec.append({
232 'number': 1,
233 'prefix': 'admin',
234 'roles': (CONF.auth.tempest_roles +
235 [CONF.identity.admin_role])
236 })
237 resources = {'tenants': [],
238 'users': []}
239 for count in range(opts.concurrency):
240 for user_group in spec:
241 users = [random_user_name(opts.tag, user_group['prefix'])
242 for _ in range(user_group['number'])]
243 for user in users:
244 tenant = '-'.join((user, 'tenant'))
245 resources['tenants'].append(tenant)
246 resources['users'].append({
247 'tenant': tenant,
248 'name': user,
249 'pass': data_utils.rand_name(),
250 'prefix': user_group['prefix'],
251 'roles': user_group['roles']
252 })
253 return resources
254
255
256def dump_accounts(opts, resources):
257 accounts = []
258 for user in resources['users']:
David Kranz0aa4a7b2015-06-08 13:25:41 -0400259 account = {
sslypushenko0de7d052015-04-16 18:49:55 +0300260 'username': user['name'],
261 'tenant_name': user['tenant'],
262 'password': user['pass'],
263 'roles': user['roles']
David Kranz0aa4a7b2015-06-08 13:25:41 -0400264 }
265 if 'network' in user:
266 account['resources'] = {'network': user['network']}
267 accounts.append(account)
sslypushenko0de7d052015-04-16 18:49:55 +0300268 if os.path.exists(opts.accounts):
269 os.rename(opts.accounts, '.'.join((opts.accounts, 'bak')))
270 with open(opts.accounts, 'w') as f:
271 yaml.dump(accounts, f, default_flow_style=False)
272 LOG.info('%s generated successfully!' % opts.accounts)
273
274
275def get_options():
276 usage_string = ('account_generator [-h] <ARG> ...\n\n'
277 'To see help on specific argument, do:\n'
278 'account_generator <ARG> -h')
279 parser = argparse.ArgumentParser(
280 description='Create accounts.yaml file for concurrent test runs. '
281 'One primary user, one alt user, '
282 'one swift admin, one stack owner '
283 'and one admin (optionally) will be created '
284 'for each concurrent thread.',
285 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
286 usage=usage_string
287 )
288
289 parser.add_argument('-c', '--config-file',
290 metavar='/etc/tempest.conf',
291 help='path to tempest config file')
292 parser.add_argument('--os-username',
293 metavar='<auth-user-name>',
294 default=os.environ.get('OS_USERNAME'),
295 help='User should have permitions '
296 'to create new user accounts and '
297 'tenants. Defaults to env[OS_USERNAME].')
298 parser.add_argument('--os-password',
299 metavar='<auth-password>',
300 default=os.environ.get('OS_PASSWORD'),
301 help='Defaults to env[OS_PASSWORD].')
302 parser.add_argument('--os-tenant-name',
303 metavar='<auth-tenant-name>',
304 default=os.environ.get('OS_TENANT_NAME'),
305 help='Defaults to env[OS_TENANT_NAME].')
306 parser.add_argument('--tag',
307 default='',
308 required=False,
309 dest='tag',
310 help='Resources tag')
311 parser.add_argument('-r', '--concurrency',
312 default=1,
313 type=int,
314 required=True,
315 dest='concurrency',
316 help='Concurrency count')
317 parser.add_argument('--with-admin',
318 action='store_true',
319 dest='admin',
320 help='Create admin in every tenant')
321 parser.add_argument('accounts',
322 metavar='accounts_file.yaml',
323 help='Output accounts yaml file')
324
325 opts = parser.parse_args()
326 if opts.config_file:
327 config.CONF.set_config_path(opts.config_file)
328 return opts
329
330
331def main(opts=None):
332 if not opts:
333 opts = get_options()
334 setup_logging()
335 resources = generate_resources(opts)
336 create_resources(opts, resources)
337 dump_accounts(opts, resources)
338
339if __name__ == "__main__":
340 main()