ceph-ansible/library/ceph_add_users_buckets.py

572 lines
20 KiB
Python

#!/usr/bin/python
# Copyright 2018 Daniel Pivonka <dpivonka@redhat.com>
# Copyright 2018 Red Hat, Inc.
#
# GNU General Public License v3.0+
from ansible.module_utils.basic import AnsibleModule
from socket import error as socket_error
import boto
import radosgw
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: ceph_add_users_buckets
short_description: bulk create user and buckets
description:
- Bulk create Ceph Object Storage users and buckets
option:
rgw_host:
description:
- a radosgw host in the ceph cluster
required: true
port:
description:
- tcp port of the radosgw host
required: true
is_secure:
description:
- boolean indicating whether the instance is running over https
required: false
default: false
admin_access_key:
description:
- radosgw admin user's access key
required: true
admin_secret_key:
description:
- radosgw admin user's secret key
required: true
users:
description:
- list of users to be created containing sub options
required: false
sub_options:
username:
description:
- username for new user
required: true
fullname:
description:
- fullname for new user
required: true
email:
description:
- email for new user
required: false
maxbucket:
description:
- max bucket for new user
required: false
default: 1000
suspend:
description:
- suspend a new user apon creation
required: false
default: false
autogenkey:
description:
- auto generate keys for new user
required: false
default: true
accesskey:
description:
- access key for new user
required: false
secretkey:
description:
- secret key for new user
required: false
userquota:
description:
- enable/disable user quota for new user
required: false
default: false
usermaxsize:
description:
- with user quota enabled specify quota size in kb
required: false
default: unlimited
usermaxobjects:
description:
- with user quota enabled specify maximum number of objects
required: false
default: unlimited
bucketquota:
description:
- enable/disable bucket quota for new user
required: false
default: false
bucketmaxsize:
description:
- with bucket quota enabled specify bucket size in kb
required: false
default: unlimited
bucketmaxobjects:
description:
- with bucket quota enabled specify maximum number of objects # noqa: E501
required: false
default: unlimited
buckets:
description:
- list of buckets to be created containing sub options
required: false
sub_options:
bucket:
description:
- name for new bucket
required: true
user:
description:
- user new bucket will be linked too
required: true
requirements: ['radosgw', 'boto']
author:
- 'Daniel Pivonka'
'''
EXAMPLES = '''
# single basic user
- name: single basic user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
users:
- username: 'test1'
fullname: 'tester'
# single complex user
- name: single complex user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
users:
- username: 'test1'
fullname: 'tester'
email: 'dan@email.com'
maxbucket: 666
suspend: true
autogenkey: true
accesskey: 'B3AR4Q33L59YV56A9A2F'
secretkey: 'd84BRnMysnVGSyZiRlYUMduVgIarQWiNMdKzrF76'
userquota: true
usermaxsize: '1000'
usermaxobjects: 3
bucketquota: true
bucketmaxsize: '1000'
bucketmaxobjects: 3
# multi user
- name: multi user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
users:
- username: 'test1'
fullname: 'tester'
email: 'dan@email.com'
maxbucket: 666
suspend: true
autogenkey: true
accesskey: 'B3AR4Q33L59YV56A9A2F'
secretkey: 'd84BRnMysnVGSyZiRlYUMduVgIarQWiNMdKzrF76'
userquota: true
usermaxsize: '1000K'
usermaxobjects: 3
bucketquota: true
bucketmaxsize: '1000K'
bucketmaxobjects: 3
- username: 'test2'
fullname: 'tester'
# single bucket
- name: single basic user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
buckets:
- bucket: 'heyimabucket1'
user: 'test1'
# multi bucket
- name: single basic user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
buckets:
- bucket: 'heyimabucket1'
user: 'test1'
- bucket: 'heyimabucket2'
user: 'test2'
- bucket: 'heyimabucket3'
user: 'test2'
# buckets and users
- name: single basic user
ceph_add_users_buckets:
rgw_host: '172.16.0.12'
port: 8080
admin_access_key: 'N61I8625V4XTWGDTLBLL'
admin_secret_key: 'HZrkuHHO9usUurDWBQHTeLIjO325bIULaC7DxcoV'
users:
- username: 'test1'
fullname: 'tester'
email: 'dan@email.com'
maxbucket: 666
- username: 'test2'
fullname: 'tester'
email: 'dan1@email.com'
accesskey: 'B3AR4Q33L59YV56A9A2F'
secretkey: 'd84BRnMysnVGSyZiRlYUMduVgIarQWiNMdKzrF76'
userquota: true
usermaxsize: '1000'
usermaxobjects: 3
bucketquota: true
bucketmaxsize: '1000'
bucketmaxobjects: 3
buckets:
- bucket: 'heyimabucket1'
user: 'test1'
- bucket: 'heyimabucket2'
user: 'test2'
- bucket: 'heyimabucket3'
user: 'test2'
'''
RETURN = '''
error_messages:
description: error for failed user or bucket.
returned: always
type: list
sample: [
"test2: could not modify user: unable to modify user, cannot add duplicate email\n" # noqa: E501
]
failed_users:
description: users that were not created.
returned: always
type: str
sample: "test2"
added_users:
description: users that were created.
returned: always
type: str
sample: "test1"
failed_buckets:
description: buckets that were not created.
returned: always
type: str
sample: "heyimabucket3"
added_buckets:
description: buckets that were created.
returned: always
type: str
sample: "heyimabucket1, heyimabucket2"
'''
def create_users(rgw, users, result):
added_users = []
failed_users = []
for user in users:
# get info
username = user['username']
fullname = user['fullname']
email = user['email']
maxbucket = user['maxbucket']
suspend = user['suspend']
autogenkey = user['autogenkey']
accesskey = user['accesskey']
secretkey = user['secretkey']
userquota = user['userquota']
usermaxsize = user['usermaxsize']
usermaxobjects = user['usermaxobjects']
bucketquota = user['bucketquota']
bucketmaxsize = user['bucketmaxsize']
bucketmaxobjects = user['bucketmaxobjects']
fail_flag = False
# check if user exists
try:
user_info = rgw.get_user(uid=username)
except radosgw.exception.RadosGWAdminError:
# it doesnt exist
user_info = None
# user exists can not create
if user_info:
result['error_messages'].append(username + ' UserExists')
failed_users.append(username)
else:
# user doesnt exist create it
if email:
if autogenkey:
try:
rgw.create_user(username, fullname, email=email, key_type='s3', # noqa: E501
generate_key=autogenkey,
max_buckets=maxbucket, suspended=suspend) # noqa: E501
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
else:
try:
rgw.create_user(username, fullname, email=email, key_type='s3', # noqa: E501
access_key=accesskey, secret_key=secretkey, # noqa: E501
max_buckets=maxbucket, suspended=suspend) # noqa: E501
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
else:
if autogenkey:
try:
rgw.create_user(username, fullname, key_type='s3',
generate_key=autogenkey,
max_buckets=maxbucket, suspended=suspend) # noqa: E501
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
else:
try:
rgw.create_user(username, fullname, key_type='s3',
access_key=accesskey, secret_key=secretkey, # noqa: E501
max_buckets=maxbucket, suspended=suspend) # noqa: E501
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
if not fail_flag and userquota:
try:
rgw.set_quota(username, 'user', max_objects=usermaxobjects,
max_size_kb=usermaxsize, enabled=True)
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
if not fail_flag and bucketquota:
try:
rgw.set_quota(username, 'bucket', max_objects=bucketmaxobjects, # noqa: E501
max_size_kb=bucketmaxsize, enabled=True)
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(username + ' ' + e.get_code()) # noqa: E501
fail_flag = True
if fail_flag:
try:
rgw.delete_user(username)
except radosgw.exception.RadosGWAdminError:
pass
failed_users.append(username)
else:
added_users.append(username)
result['added_users'] = ", ".join(added_users)
result['failed_users'] = ", ".join(failed_users)
def create_buckets(rgw, buckets, result):
added_buckets = []
failed_buckets = []
for bucket_info in buckets:
bucket = bucket_info['bucket']
user = bucket_info['user']
# check if bucket exists
try:
bucket_info = rgw.get_bucket(bucket_name=bucket)
except TypeError:
# it doesnt exist
bucket_info = None
# if it exists add to failed list
if bucket_info:
failed_buckets.append(bucket)
result['error_messages'].append(bucket + ' BucketExists')
else:
# bucket doesn't exist, so we need to create it
bucket_info = create_bucket(rgw, bucket)
if bucket_info:
# bucket created ok, link to user
# check if user exists
try:
user_info = rgw.get_user(uid=user)
except radosgw.exception.RadosGWAdminError:
# it doesnt exist
user_info = None
# user exists, link
if user_info:
try:
rgw.link_bucket(bucket_name=bucket,
bucket_id=bucket_info.id,
uid=user)
added_buckets.append(bucket)
except radosgw.exception.RadosGWAdminError as e:
result['error_messages'].append(bucket + e.get_code())
try:
rgw.delete_bucket(bucket, purge_objects=True)
except radosgw.exception.RadosGWAdminError:
pass
failed_buckets.append(bucket)
else:
# user doesnt exist cant be link delete bucket
try:
rgw.delete_bucket(bucket, purge_objects=True)
except radosgw.exception.RadosGWAdminError:
pass
failed_buckets.append(bucket)
result['error_messages'].append(bucket + ' could not be linked' + ', NoSuchUser ' + user) # noqa: E501
else:
# something went wrong
failed_buckets.append(bucket)
result['error_messages'].append(bucket + ' could not be created') # noqa: E501
result['added_buckets'] = ", ".join(added_buckets)
result['failed_buckets'] = ", ".join(failed_buckets)
def create_bucket(rgw, bucket):
conn = boto.connect_s3(aws_access_key_id=rgw.provider._access_key,
aws_secret_access_key=rgw.provider._secret_key,
host=rgw._connection[0],
port=rgw.port,
is_secure=rgw.is_secure,
calling_format=boto.s3.connection.OrdinaryCallingFormat(), # noqa: E501
)
try:
conn.create_bucket(bucket_name=bucket)
bucket_info = rgw.get_bucket(bucket_name=bucket)
except boto.exception.S3ResponseError:
return None
else:
return bucket_info
def main():
# arguments/parameters that a user can pass to the module
fields = dict(rgw_host=dict(type='str', required=True),
port=dict(type='int', required=True),
is_secure=dict(type='bool',
required=False,
default=False),
admin_access_key=dict(type='str', required=True),
admin_secret_key=dict(type='str', required=True),
buckets=dict(type='list', required=False, elements='dict',
options=dict(bucket=dict(type='str', required=True), # noqa: E501
user=dict(type='str', required=True))), # noqa: E501
users=dict(type='list', required=False, elements='dict',
options=dict(username=dict(type='str', required=True), # noqa: E501
fullname=dict(type='str', required=True), # noqa: E501
email=dict(type='str', required=False), # noqa: E501
maxbucket=dict(type='int', required=False, default=1000), # noqa: E501
suspend=dict(type='bool', required=False, default=False), # noqa: E501
autogenkey=dict(type='bool', required=False, default=True), # noqa: E501
accesskey=dict(type='str', required=False), # noqa: E501
secretkey=dict(type='str', required=False), # noqa: E501
userquota=dict(type='bool', required=False, default=False), # noqa: E501
usermaxsize=dict(type='str', required=False, default='-1'), # noqa: E501
usermaxobjects=dict(type='int', required=False, default=-1), # noqa: E501
bucketquota=dict(type='bool', required=False, default=False), # noqa: E501
bucketmaxsize=dict(type='str', required=False, default='-1'), # noqa: E501
bucketmaxobjects=dict(type='int', required=False, default=-1)))) # noqa: E501
# the AnsibleModule object
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
# get vars
rgw_host = module.params.get('rgw_host')
port = module.params.get('port')
is_secure = module.params.get('is_secure')
admin_access_key = module.params.get('admin_access_key')
admin_secret_key = module.params.get('admin_secret_key')
users = module.params['users']
buckets = module.params.get('buckets')
# seed the result dict in the object
result = dict(
changed=False,
error_messages=[],
added_users='',
failed_users='',
added_buckets='',
failed_buckets='',
)
# radosgw connection
rgw = radosgw.connection.RadosGWAdminConnection(host=rgw_host,
port=port,
access_key=admin_access_key, # noqa: E501
secret_key=admin_secret_key, # noqa: E501
aws_signature='AWS4',
is_secure=is_secure)
# test connection
connected = True
try:
rgw.get_usage()
except radosgw.exception.RadosGWAdminError as e:
connected = False
result['error_messages'] = e.get_code()
except socket_error as e:
connected = False
result['error_messages'] = str(e)
if connected and users:
create_users(rgw, users, result)
if connected and buckets:
create_buckets(rgw, buckets, result)
if result['added_users'] != '' or result['added_buckets'] != '':
result['changed'] = True
# conditional state caused a failure
if result['added_users'] == '' and result['added_buckets'] == '':
module.fail_json(msg='No users or buckets were added successfully',
**result)
# EXIT
module.exit_json(**result)
if __name__ == '__main__':
main()