Merge "Tool for generation user accounts from spec"
This commit is contained in:
commit
f728beca05
@ -24,6 +24,7 @@ console_scripts =
|
|||||||
javelin2 = tempest.cmd.javelin:main
|
javelin2 = tempest.cmd.javelin:main
|
||||||
run-tempest-stress = tempest.cmd.run_stress:main
|
run-tempest-stress = tempest.cmd.run_stress:main
|
||||||
tempest-cleanup = tempest.cmd.cleanup:main
|
tempest-cleanup = tempest.cmd.cleanup:main
|
||||||
|
tempest-account-generator = tempest.cmd.account_generator:main
|
||||||
|
|
||||||
oslo.config.opts =
|
oslo.config.opts =
|
||||||
tempest.config = tempest.config:list_opts
|
tempest.config = tempest.config:list_opts
|
||||||
|
266
tempest/cmd/account_generator.py
Executable file
266
tempest/cmd/account_generator.py
Executable file
@ -0,0 +1,266 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright 2015 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
|
from tempest import exceptions
|
||||||
|
from tempest.services.identity.v2.json import identity_client
|
||||||
|
import tempest_lib.auth
|
||||||
|
from tempest_lib.common.utils import data_utils
|
||||||
|
import tempest_lib.exceptions
|
||||||
|
|
||||||
|
LOG = None
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging():
|
||||||
|
global LOG
|
||||||
|
logging.setup(CONF, __name__)
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def keystone_admin(opts):
|
||||||
|
_creds = tempest_lib.auth.KeystoneV2Credentials(
|
||||||
|
username=opts.os_username,
|
||||||
|
password=opts.os_password,
|
||||||
|
tenant_name=opts.os_tenant_name)
|
||||||
|
auth_params = {
|
||||||
|
'disable_ssl_certificate_validation':
|
||||||
|
CONF.identity.disable_ssl_certificate_validation,
|
||||||
|
'ca_certs': CONF.identity.ca_certificates_file,
|
||||||
|
'trace_requests': CONF.debug.trace_requests
|
||||||
|
}
|
||||||
|
_auth = tempest_lib.auth.KeystoneV2AuthProvider(
|
||||||
|
_creds, CONF.identity.uri, **auth_params)
|
||||||
|
params = {
|
||||||
|
'disable_ssl_certificate_validation':
|
||||||
|
CONF.identity.disable_ssl_certificate_validation,
|
||||||
|
'ca_certs': CONF.identity.ca_certificates_file,
|
||||||
|
'trace_requests': CONF.debug.trace_requests,
|
||||||
|
'build_interval': CONF.compute.build_interval,
|
||||||
|
'build_timeout': CONF.compute.build_timeout
|
||||||
|
}
|
||||||
|
return identity_client.IdentityClientJSON(
|
||||||
|
_auth,
|
||||||
|
CONF.identity.catalog_type,
|
||||||
|
CONF.identity.region,
|
||||||
|
endpoint_type='adminURL',
|
||||||
|
**params
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_resources(opts, resources):
|
||||||
|
admin = keystone_admin(opts)
|
||||||
|
roles = admin.list_roles()
|
||||||
|
for u in resources['users']:
|
||||||
|
u['role_ids'] = []
|
||||||
|
for r in u.get('roles', ()):
|
||||||
|
try:
|
||||||
|
role = filter(lambda r_: r_['name'] == r, roles)[0]
|
||||||
|
u['role_ids'] += [role['id']]
|
||||||
|
except IndexError:
|
||||||
|
raise exceptions.TempestException(
|
||||||
|
"Role: %s - doesn't exist" % r
|
||||||
|
)
|
||||||
|
existing = [x['name'] for x in admin.list_tenants()]
|
||||||
|
for tenant in resources['tenants']:
|
||||||
|
if tenant not in existing:
|
||||||
|
admin.create_tenant(tenant)
|
||||||
|
else:
|
||||||
|
LOG.warn("Tenant '%s' already exists in this environment" % tenant)
|
||||||
|
LOG.info('Tenants created')
|
||||||
|
for u in resources['users']:
|
||||||
|
try:
|
||||||
|
tenant = admin.get_tenant_by_name(u['tenant'])
|
||||||
|
except tempest_lib.exceptions.NotFound:
|
||||||
|
LOG.error("Tenant: %s - not found" % u['tenant'])
|
||||||
|
continue
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
admin.get_user_by_username(tenant['id'], u['name'])
|
||||||
|
except tempest_lib.exceptions.NotFound:
|
||||||
|
admin.create_user(
|
||||||
|
u['name'], u['pass'], tenant['id'],
|
||||||
|
"%s@%s" % (u['name'], tenant['id']),
|
||||||
|
enabled=True)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
LOG.warn("User '%s' already exists in this environment. "
|
||||||
|
"New name generated" % u['name'])
|
||||||
|
u['name'] = random_user_name(opts.tag, u['prefix'])
|
||||||
|
|
||||||
|
LOG.info('Users created')
|
||||||
|
for u in resources['users']:
|
||||||
|
try:
|
||||||
|
tenant = admin.get_tenant_by_name(u['tenant'])
|
||||||
|
except tempest_lib.exceptions.NotFound:
|
||||||
|
LOG.error("Tenant: %s - not found" % u['tenant'])
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
user = admin.get_user_by_username(tenant['id'],
|
||||||
|
u['name'])
|
||||||
|
except tempest_lib.exceptions.NotFound:
|
||||||
|
LOG.error("User: %s - not found" % u['user'])
|
||||||
|
continue
|
||||||
|
for r in u['role_ids']:
|
||||||
|
try:
|
||||||
|
admin.assign_user_role(tenant['id'], user['id'], r)
|
||||||
|
except tempest_lib.exceptions.Conflict:
|
||||||
|
# don't care if it's already assigned
|
||||||
|
pass
|
||||||
|
LOG.info('Roles assigned')
|
||||||
|
LOG.info('Resources deployed successfully!')
|
||||||
|
|
||||||
|
|
||||||
|
def random_user_name(tag, prefix):
|
||||||
|
if tag:
|
||||||
|
return data_utils.rand_name('-'.join((tag, prefix)))
|
||||||
|
else:
|
||||||
|
return data_utils.rand_name(prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_resources(opts):
|
||||||
|
spec = [{'number': 1,
|
||||||
|
'prefix': 'primary',
|
||||||
|
'roles': (CONF.auth.tempest_roles +
|
||||||
|
[CONF.object_storage.operator_role])},
|
||||||
|
{'number': 1,
|
||||||
|
'prefix': 'alt',
|
||||||
|
'roles': (CONF.auth.tempest_roles +
|
||||||
|
[CONF.object_storage.operator_role])},
|
||||||
|
{'number': 1,
|
||||||
|
'prefix': 'swift_admin',
|
||||||
|
'roles': (CONF.auth.tempest_roles +
|
||||||
|
[CONF.object_storage.operator_role,
|
||||||
|
CONF.object_storage.reseller_admin_role])},
|
||||||
|
{'number': 1,
|
||||||
|
'prefix': 'stack_owner',
|
||||||
|
'roles': (CONF.auth.tempest_roles +
|
||||||
|
[CONF.orchestration.stack_owner_role])},
|
||||||
|
]
|
||||||
|
if opts.admin:
|
||||||
|
spec.append({
|
||||||
|
'number': 1,
|
||||||
|
'prefix': 'admin',
|
||||||
|
'roles': (CONF.auth.tempest_roles +
|
||||||
|
[CONF.identity.admin_role])
|
||||||
|
})
|
||||||
|
resources = {'tenants': [],
|
||||||
|
'users': []}
|
||||||
|
for count in range(opts.concurrency):
|
||||||
|
for user_group in spec:
|
||||||
|
users = [random_user_name(opts.tag, user_group['prefix'])
|
||||||
|
for _ in range(user_group['number'])]
|
||||||
|
for user in users:
|
||||||
|
tenant = '-'.join((user, 'tenant'))
|
||||||
|
resources['tenants'].append(tenant)
|
||||||
|
resources['users'].append({
|
||||||
|
'tenant': tenant,
|
||||||
|
'name': user,
|
||||||
|
'pass': data_utils.rand_name(),
|
||||||
|
'prefix': user_group['prefix'],
|
||||||
|
'roles': user_group['roles']
|
||||||
|
})
|
||||||
|
return resources
|
||||||
|
|
||||||
|
|
||||||
|
def dump_accounts(opts, resources):
|
||||||
|
accounts = []
|
||||||
|
for user in resources['users']:
|
||||||
|
accounts.append({
|
||||||
|
'username': user['name'],
|
||||||
|
'tenant_name': user['tenant'],
|
||||||
|
'password': user['pass'],
|
||||||
|
'roles': user['roles']
|
||||||
|
})
|
||||||
|
if os.path.exists(opts.accounts):
|
||||||
|
os.rename(opts.accounts, '.'.join((opts.accounts, 'bak')))
|
||||||
|
with open(opts.accounts, 'w') as f:
|
||||||
|
yaml.dump(accounts, f, default_flow_style=False)
|
||||||
|
LOG.info('%s generated successfully!' % opts.accounts)
|
||||||
|
|
||||||
|
|
||||||
|
def get_options():
|
||||||
|
usage_string = ('account_generator [-h] <ARG> ...\n\n'
|
||||||
|
'To see help on specific argument, do:\n'
|
||||||
|
'account_generator <ARG> -h')
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Create accounts.yaml file for concurrent test runs. '
|
||||||
|
'One primary user, one alt user, '
|
||||||
|
'one swift admin, one stack owner '
|
||||||
|
'and one admin (optionally) will be created '
|
||||||
|
'for each concurrent thread.',
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
|
usage=usage_string
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument('-c', '--config-file',
|
||||||
|
metavar='/etc/tempest.conf',
|
||||||
|
help='path to tempest config file')
|
||||||
|
parser.add_argument('--os-username',
|
||||||
|
metavar='<auth-user-name>',
|
||||||
|
default=os.environ.get('OS_USERNAME'),
|
||||||
|
help='User should have permitions '
|
||||||
|
'to create new user accounts and '
|
||||||
|
'tenants. Defaults to env[OS_USERNAME].')
|
||||||
|
parser.add_argument('--os-password',
|
||||||
|
metavar='<auth-password>',
|
||||||
|
default=os.environ.get('OS_PASSWORD'),
|
||||||
|
help='Defaults to env[OS_PASSWORD].')
|
||||||
|
parser.add_argument('--os-tenant-name',
|
||||||
|
metavar='<auth-tenant-name>',
|
||||||
|
default=os.environ.get('OS_TENANT_NAME'),
|
||||||
|
help='Defaults to env[OS_TENANT_NAME].')
|
||||||
|
parser.add_argument('--tag',
|
||||||
|
default='',
|
||||||
|
required=False,
|
||||||
|
dest='tag',
|
||||||
|
help='Resources tag')
|
||||||
|
parser.add_argument('-r', '--concurrency',
|
||||||
|
default=1,
|
||||||
|
type=int,
|
||||||
|
required=True,
|
||||||
|
dest='concurrency',
|
||||||
|
help='Concurrency count')
|
||||||
|
parser.add_argument('--with-admin',
|
||||||
|
action='store_true',
|
||||||
|
dest='admin',
|
||||||
|
help='Create admin in every tenant')
|
||||||
|
parser.add_argument('accounts',
|
||||||
|
metavar='accounts_file.yaml',
|
||||||
|
help='Output accounts yaml file')
|
||||||
|
|
||||||
|
opts = parser.parse_args()
|
||||||
|
if opts.config_file:
|
||||||
|
config.CONF.set_config_path(opts.config_file)
|
||||||
|
return opts
|
||||||
|
|
||||||
|
|
||||||
|
def main(opts=None):
|
||||||
|
if not opts:
|
||||||
|
opts = get_options()
|
||||||
|
setup_logging()
|
||||||
|
resources = generate_resources(opts)
|
||||||
|
create_resources(opts, resources)
|
||||||
|
dump_accounts(opts, resources)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
x
Reference in New Issue
Block a user