blob: b2306154c3aab488f8f6aaac013f17a7adc3fa36 [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
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030017"""
Masayuki Igawabbbaad62017-11-21 16:04:03 +090018Utility for creating ``accounts.yaml`` file for concurrent test runs.
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030019Creates one primary user, one alt user, one swift admin, one stack owner
20and one admin (optionally) for each concurrent thread. The utility creates
Masayuki Igawabbbaad62017-11-21 16:04:03 +090021user for each tenant. The ``accounts.yaml`` file will be valid and contain
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030022credentials for created users, so each user will be in separate tenant and
23have the username, tenant_name, password and roles.
24
Masayuki Igawabbbaad62017-11-21 16:04:03 +090025**Usage:** ``tempest account-generator [-h] [OPTIONS] accounts_file.yaml``
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030026
27Positional Arguments
Matthew Treinishf45ba2e2015-08-24 15:05:01 -040028--------------------
Masayuki Igawabbbaad62017-11-21 16:04:03 +090029``accounts_file.yaml`` (Required) Provide an output accounts yaml file. Utility
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030030creates a .yaml file in the directory where the command is ran. The appropriate
31name for the file is *accounts.yaml* and it should be placed in *tempest/etc*
32directory.
33
34Authentication
35--------------
36
37Account generator creates users and tenants so it needs the admin credentials
38of your cloud to operate properly. The corresponding info can be given either
39through CLI options or environment variables.
40
Masayuki Igawa679e8642016-06-10 17:09:45 +090041You're probably familiar with these, but just to remind:
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030042
Masayuki Igawabbbaad62017-11-21 16:04:03 +090043======== ============================ ====================
44Param CLI Environment Variable
45======== ============================ ====================
46Username ``--os-username`` OS_USERNAME
47Password ``--os-password`` OS_PASSWORD
48Project ``--os-project-name`` OS_PROJECT_NAME
Masayuki Igawabbbaad62017-11-21 16:04:03 +090049Domain ``--os-domain-name`` OS_DOMAIN_NAME
50======== ============================ ====================
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030051
52Optional Arguments
Matthew Treinishf45ba2e2015-08-24 15:05:01 -040053------------------
Masayuki Igawabbbaad62017-11-21 16:04:03 +090054* ``-h, --help`` (Optional) Shows help message with the description of
55 utility and its arguments, and exits.
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030056
Masayuki Igawabbbaad62017-11-21 16:04:03 +090057* ``-c, --config-file /etc/tempest.conf`` (Optional) Path
58 to tempest config file. If not specified, it searches for tempest.conf in
59 these locations:
Martin Kopec14e0be12017-11-13 12:38:12 +000060
Masayuki Igawabbbaad62017-11-21 16:04:03 +090061 - ./etc/
62 - /etc/tempest
63 - ~/.tempest/
64 - ~/
65 - /etc/
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030066
Masayuki Igawabbbaad62017-11-21 16:04:03 +090067* ``--os-username <auth-user-name>`` (Optional) Name used for authentication
68 with the OpenStack Identity service. Defaults to env[OS_USERNAME]. Note: User
69 should have permissions to create new user accounts and tenants.
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030070
Masayuki Igawabbbaad62017-11-21 16:04:03 +090071* ``--os-password <auth-password>`` (Optional) Password used for authentication
72 with the OpenStack Identity service. Defaults to env[OS_PASSWORD].
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030073
Masayuki Igawabbbaad62017-11-21 16:04:03 +090074* ``--os-project-name <auth-project-name>`` (Optional) Project to request
75 authorization on. Defaults to env[OS_PROJECT_NAME].
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +010076
Masayuki Igawabbbaad62017-11-21 16:04:03 +090077* ``--os-domain-name <auth-domain-name>`` (Optional) Domain the user and
78 project belong to. Defaults to env[OS_DOMAIN_NAME].
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030079
Masayuki Igawabbbaad62017-11-21 16:04:03 +090080* ``--tag TAG`` (Optional) Resources tag. Each created resource (user, project)
81 will have the prefix with the given TAG in its name. Using tag is recommended
82 for the further using, cleaning resources.
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030083
Masayuki Igawabbbaad62017-11-21 16:04:03 +090084* ``-r, --concurrency CONCURRENCY`` (Optional) Concurrency count
85 (default: 1). The number of accounts required can be estimated as
86 CONCURRENCY x 2. Each user provided in *accounts.yaml* file will be in
87 a different tenant. This is required to provide isolation between test for
88 running in parallel.
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030089
Masayuki Igawabbbaad62017-11-21 16:04:03 +090090* ``--with-admin`` (Optional) Creates admin for each concurrent group
91 (default: False).
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030092
Masayuki Igawabbbaad62017-11-21 16:04:03 +090093* ``-i, --identity-version VERSION`` (Optional) Provisions accounts
94 using the specified version of the identity API. (default: '3').
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +010095
guo yunxian306a7de2016-10-20 18:33:21 +080096To see help on specific argument, please do: ``tempest account-generator
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +030097[OPTIONS] <accounts_file.yaml> -h``.
98"""
Soniya Vyasddcd4f42019-12-24 17:55:34 +053099
sslypushenko0de7d052015-04-16 18:49:55 +0300100import os
David Paterson68b8b9d2015-12-01 15:44:14 -0800101import traceback
sslypushenko0de7d052015-04-16 18:49:55 +0300102
David Paterson68b8b9d2015-12-01 15:44:14 -0800103from cliff import command
sslypushenko0de7d052015-04-16 18:49:55 +0300104from oslo_log import log as logging
105import yaml
106
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100107from tempest.common import credentials_factory
sslypushenko0de7d052015-04-16 18:49:55 +0300108from tempest import config
Matthew Treinishc51b7122017-07-17 12:28:07 -0400109from tempest.lib.common import dynamic_creds
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100110
sslypushenko0de7d052015-04-16 18:49:55 +0300111
112LOG = None
113CONF = config.CONF
David Paterson68b8b9d2015-12-01 15:44:14 -0800114DESCRIPTION = ('Create accounts.yaml file for concurrent test runs.%s'
115 'One primary user, one alt user, '
116 'one swift admin, one stack owner '
117 'and one admin (optionally) will be created '
118 'for each concurrent thread.' % os.linesep)
sslypushenko0de7d052015-04-16 18:49:55 +0300119
120
121def setup_logging():
122 global LOG
123 logging.setup(CONF, __name__)
124 LOG = logging.getLogger(__name__)
125
126
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100127def get_credential_provider(opts):
128 identity_version = "".join(['v', str(opts.identity_version)])
129 # NOTE(andreaf) For now tempest.conf controls whether resources will
130 # actually be created. Once we remove the dependency from tempest.conf
131 # we will need extra CLI option(s) to control this.
132 network_resources = {'router': True,
133 'network': True,
134 'subnet': True,
135 'dhcp': True}
136 admin_creds_dict = {'username': opts.os_username,
137 'password': opts.os_password}
Soniya Vyas195767a2019-12-24 19:20:43 +0530138 _project_name = opts.os_project_name
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100139 if opts.identity_version == 3:
140 admin_creds_dict['project_name'] = _project_name
141 admin_creds_dict['domain_name'] = opts.os_domain_name or 'Default'
142 elif opts.identity_version == 2:
143 admin_creds_dict['tenant_name'] = _project_name
144 admin_creds = credentials_factory.get_credentials(
145 fill_in=False, identity_version=identity_version, **admin_creds_dict)
146 return dynamic_creds.DynamicCredentialProvider(
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100147 name=opts.tag,
148 network_resources=network_resources,
Andrea Frittolid199caf2017-07-18 17:12:38 +0100149 **credentials_factory.get_dynamic_provider_params(
150 identity_version, admin_creds=admin_creds))
sslypushenko0de7d052015-04-16 18:49:55 +0300151
152
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100153def generate_resources(cred_provider, admin):
154 # Create the list of resources to be provisioned for each process
155 # NOTE(andreaf) get_credentials expects a string for types or a list for
156 # roles. Adding all required inputs to the spec list.
157 spec = ['primary', 'alt']
Matthew Treinish36c2e282015-08-25 00:30:15 -0400158 if CONF.service_available.swift:
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100159 spec.append([CONF.object_storage.operator_role])
160 spec.append([CONF.object_storage.reseller_admin_role])
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100161 if admin:
162 spec.append('admin')
163 resources = []
164 for cred_type in spec:
165 resources.append((cred_type, cred_provider.get_credentials(
166 credential_type=cred_type)))
sslypushenko0de7d052015-04-16 18:49:55 +0300167 return resources
168
169
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100170def dump_accounts(resources, identity_version, account_file):
sslypushenko0de7d052015-04-16 18:49:55 +0300171 accounts = []
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100172 for resource in resources:
173 cred_type, test_resource = resource
David Kranz0aa4a7b2015-06-08 13:25:41 -0400174 account = {
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100175 'username': test_resource.username,
176 'password': test_resource.password
David Kranz0aa4a7b2015-06-08 13:25:41 -0400177 }
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100178 if identity_version == 3:
179 account['project_name'] = test_resource.project_name
180 account['domain_name'] = test_resource.domain_name
181 else:
182 account['project_name'] = test_resource.tenant_name
183
184 # If the spec includes 'admin' credentials are defined via type,
185 # else they are defined via list of roles.
186 if cred_type == 'admin':
187 account['types'] = [cred_type]
188 elif cred_type not in ['primary', 'alt']:
189 account['roles'] = cred_type
190
191 if test_resource.network:
David Paterson15be99e2015-04-08 21:58:19 -0400192 account['resources'] = {}
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100193 account['resources']['network'] = test_resource.network['name']
David Kranz0aa4a7b2015-06-08 13:25:41 -0400194 accounts.append(account)
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100195 if os.path.exists(account_file):
196 os.rename(account_file, '.'.join((account_file, 'bak')))
197 with open(account_file, 'w') as f:
198 yaml.safe_dump(accounts, f, default_flow_style=False)
Jordan Pittier525ec712016-12-07 17:51:26 +0100199 LOG.info('%s generated successfully!', account_file)
sslypushenko0de7d052015-04-16 18:49:55 +0300200
201
David Paterson68b8b9d2015-12-01 15:44:14 -0800202def _parser_add_args(parser):
sslypushenko0de7d052015-04-16 18:49:55 +0300203 parser.add_argument('-c', '--config-file',
204 metavar='/etc/tempest.conf',
205 help='path to tempest config file')
206 parser.add_argument('--os-username',
207 metavar='<auth-user-name>',
208 default=os.environ.get('OS_USERNAME'),
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +0300209 help='User should have permissions '
sslypushenko0de7d052015-04-16 18:49:55 +0300210 'to create new user accounts and '
211 'tenants. Defaults to env[OS_USERNAME].')
212 parser.add_argument('--os-password',
213 metavar='<auth-password>',
214 default=os.environ.get('OS_PASSWORD'),
215 help='Defaults to env[OS_PASSWORD].')
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100216 parser.add_argument('--os-project-name',
217 metavar='<auth-project-name>',
218 default=os.environ.get('OS_PROJECT_NAME'),
219 help='Defaults to env[OS_PROJECT_NAME].')
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100220 parser.add_argument('--os-domain-name',
221 metavar='<auth-domain-name>',
222 default=os.environ.get('OS_DOMAIN_NAME'),
223 help='Defaults to env[OS_DOMAIN_NAME].')
sslypushenko0de7d052015-04-16 18:49:55 +0300224 parser.add_argument('--tag',
225 default='',
226 required=False,
227 dest='tag',
228 help='Resources tag')
229 parser.add_argument('-r', '--concurrency',
230 default=1,
231 type=int,
ghanshyam46545152016-06-13 12:57:42 +0900232 required=False,
sslypushenko0de7d052015-04-16 18:49:55 +0300233 dest='concurrency',
234 help='Concurrency count')
235 parser.add_argument('--with-admin',
236 action='store_true',
237 dest='admin',
Jane Zadorozhna00fc3dc2015-05-27 18:01:56 +0300238 help='Creates admin for each concurrent group')
Andrea Frittoli (andreaf)bd06f982016-06-02 17:26:51 +0100239 parser.add_argument('-i', '--identity-version',
240 default=3,
241 choices=[2, 3],
242 type=int,
243 required=False,
244 dest='identity_version',
245 help='Version of the Identity API to use')
sslypushenko0de7d052015-04-16 18:49:55 +0300246 parser.add_argument('accounts',
247 metavar='accounts_file.yaml',
248 help='Output accounts yaml file')
249
David Paterson68b8b9d2015-12-01 15:44:14 -0800250
David Paterson68b8b9d2015-12-01 15:44:14 -0800251class TempestAccountGenerator(command.Command):
252
253 def get_parser(self, prog_name):
254 parser = super(TempestAccountGenerator, self).get_parser(prog_name)
255 _parser_add_args(parser)
256 return parser
257
258 def take_action(self, parsed_args):
259 try:
Soniya Vyasddcd4f42019-12-24 17:55:34 +0530260 if parsed_args.config_file:
261 config.CONF.set_config_path(parsed_args.config_file)
262 setup_logging()
263 resources = []
264 for count in range(parsed_args.concurrency):
265 # Use N different cred_providers to obtain different
266 # sets of creds
267 cred_provider = get_credential_provider(parsed_args)
268 resources.extend(generate_resources(cred_provider,
269 parsed_args.admin))
270 dump_accounts(resources, parsed_args.identity_version,
271 parsed_args.accounts)
272
David Paterson68b8b9d2015-12-01 15:44:14 -0800273 except Exception:
274 LOG.exception("Failure generating test accounts.")
275 traceback.print_exc()
276 raise
David Paterson68b8b9d2015-12-01 15:44:14 -0800277
278 def get_description(self):
279 return DESCRIPTION