From 4012272fa2ae0a6caafad0e0783c8d8fcc3e852a Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sat, 2 Aug 2014 17:12:24 -0700 Subject: [PATCH] Add common auth handling across openstack modules Taking a page out of the ec2 config, make sure that all of the OpenStack modules handle the inbound auth config in the same way. The one outlier is keystone wrt auth_url. --- lib/ansible/module_utils/openstack.py | 56 +++++++++++++++++++++ library/cloud/glance_image | 36 +++++++------ library/cloud/keystone_user | 14 +++--- library/cloud/nova_compute | 35 +++---------- library/cloud/nova_keypair | 14 ++---- library/cloud/quantum_floating_ip | 14 ++---- library/cloud/quantum_floating_ip_associate | 14 ++---- library/cloud/quantum_network | 14 ++---- library/cloud/quantum_router | 14 ++---- library/cloud/quantum_router_gateway | 14 ++---- library/cloud/quantum_router_interface | 14 ++---- library/cloud/quantum_subnet | 14 ++---- 12 files changed, 127 insertions(+), 126 deletions(-) create mode 100644 lib/ansible/module_utils/openstack.py diff --git a/lib/ansible/module_utils/openstack.py b/lib/ansible/module_utils/openstack.py new file mode 100644 index 00000000000..c70eb9fbfa8 --- /dev/null +++ b/lib/ansible/module_utils/openstack.py @@ -0,0 +1,56 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os + + +def openstack_argument_spec(): + # Consume standard OpenStack environment variables. + # This is mainly only useful for ad-hoc command line operation as + # in playbooks one would assume variables would be used appropriately + OS_AUTH_URL=os.environ.get('OS_AUTH_URL', 'http://127.0.0.1:35357/v2.0/') + OS_PASSWORD=os.environ.get('OS_PASSWORD', None) + OS_REGION_NAME=os.environ.get('OS_REGION_NAME', None) + OS_USERNAME=os.environ.get('OS_USERNAME', 'admin') + OS_TENANT_NAME=os.environ.get('OS_TENANT_NAME', OS_USERNAME) + + spec = dict( + login_username = dict(default=OS_USERNAME), + auth_url = dict(default=OS_AUTH_URL), + region_name = dict(default=OS_REGION_NAME), + availability_zone = dict(default=None), + ) + if OS_PASSWORD: + spec['login_password'] = dict(default=OS_PASSWORD) + else: + spec['login_password'] = dict(required=True) + if OS_TENANT_NAME: + spec['login_tenant_name'] = dict(default=OS_TENANT_NAME) + else: + spec['login_tenant_name'] = dict(required=True) + return spec diff --git a/library/cloud/glance_image b/library/cloud/glance_image index b73b3bfea7a..d8b02602feb 100644 --- a/library/cloud/glance_image +++ b/library/cloud/glance_image @@ -217,26 +217,23 @@ def _glance_delete_image(module, params, client): def main(): + argument_spec = openstack_argument_spec() + argument_spec.update(dict( + name = dict(required=True), + disk_format = dict(default='qcow2', choices=['aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso']), + container_format = dict(default='bare', choices=['aki', 'ari', 'bare', 'ovf']), + owner = dict(default=None), + min_disk = dict(default=None), + min_ram = dict(default=None), + is_public = dict(default=True), + copy_from = dict(default= None), + timeout = dict(default=180), + file = dict(default=None), + endpoint_type = dict(default='publicURL', choices=['publicURL', 'internalURL']), + state = dict(default='present', choices=['absent', 'present']) + )) module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required=True), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), - name = dict(required=True), - disk_format = dict(default='qcow2', choices=['aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso']), - container_format = dict(default='bare', choices=['aki', 'ari', 'bare', 'ovf']), - owner = dict(default=None), - min_disk = dict(default=None), - min_ram = dict(default=None), - is_public = dict(default=True), - copy_from = dict(default= None), - timeout = dict(default=180), - file = dict(default=None), - endpoint_type = dict(default='publicURL', choices=['publicURL', 'internalURL']), - state = dict(default='present', choices=['absent', 'present']) - ), + argument_spec=argument_spec, mutually_exclusive = [['file','copy_from']], ) if module.params['state'] == 'present': @@ -258,4 +255,5 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/keystone_user b/library/cloud/keystone_user index f3295b7f19b..a5d3aa940d8 100644 --- a/library/cloud/keystone_user +++ b/library/cloud/keystone_user @@ -287,11 +287,8 @@ def ensure_role_absent(keystone, uesr, tenant, role, check_mode): def main(): - module = AnsibleModule( - argument_spec=dict( - user=dict(required=False), - password=dict(required=False), - tenant=dict(required=False), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( tenant_description=dict(required=False), email=dict(required=False), role=dict(required=False), @@ -302,7 +299,11 @@ def main(): login_user=dict(required=False), login_password=dict(required=False), login_tenant_name=dict(required=False) - ), + )) + # keystone operations themselves take an endpoint, not a keystone auth_url + del(argument_spec['auth_url']) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[['token', 'login_user'], ['token', 'login_password'], @@ -388,5 +389,6 @@ def dispatch(keystone, user=None, password=None, tenant=None, # import module snippets from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * if __name__ == '__main__': main() diff --git a/library/cloud/nova_compute b/library/cloud/nova_compute index 8a3725ed2fc..86ea57d8996 100644 --- a/library/cloud/nova_compute +++ b/library/cloud/nova_compute @@ -226,32 +226,8 @@ def _get_server_state(module, nova): def main(): - # Consume standard OpenStack environment variables. - # This is mainly only useful for ad-hoc command line operation as - # in playbooks one would assume variables would be used appropriately - OS_USERNAME=os.environ.get('OS_USERNAME', 'admin') - OS_PASSWORD=os.environ.get('OS_PASSWORD', None) - login_password_arg = dict() - if OS_PASSWORD: - login_password_arg['default'] = OS_PASSWORD - else: - login_password_arg['required'] = True - OS_TENANT_NAME=os.environ.get('OS_TENANT_NAME', None) - tenant_name_arg = dict() - if OS_TENANT_NAME: - tenant_name_arg['default'] = OS_TENANT_NAME - else: - tenant_name_arg['required'] = True - OS_REGION_NAME=os.environ.get('OS_REGION_NAME', None) - OS_AUTH_URL=os.environ.get('OS_AUTH_URL', 'http://127.0.0.1:35357/v2.0/') - - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default=OS_USERNAME), - login_password = login_password_arg, - login_tenant_name = tenant_name_arg, - auth_url = dict(default=OS_AUTH_URL), - region_name = dict(default=OS_REGION_NAME), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( name = dict(required=True), image_id = dict(default=None), flavor_id = dict(default=1), @@ -262,9 +238,9 @@ def main(): wait = dict(default='yes', choices=['yes', 'no']), wait_for = dict(default=180), state = dict(default='present', choices=['absent', 'present']), - user_data = dict(default=None) - ), - ) + user_data = dict(default=None), + )) + module = AnsibleModule(argument_spec=argument_spec) nova = nova_client.Client(module.params['login_username'], module.params['login_password'], @@ -291,5 +267,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/nova_keypair b/library/cloud/nova_keypair index 553683d3a89..be2bbb1d93d 100644 --- a/library/cloud/nova_keypair +++ b/library/cloud/nova_keypair @@ -87,18 +87,13 @@ EXAMPLES = ''' ''' def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( name = dict(required=True), public_key = dict(default=None), state = dict(default='present', choices=['absent', 'present']) - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) nova = nova_client.Client(module.params['login_username'], module.params['login_password'], @@ -138,5 +133,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_floating_ip b/library/cloud/quantum_floating_ip index 9bde712576d..17f78effffd 100644 --- a/library/cloud/quantum_floating_ip +++ b/library/cloud/quantum_floating_ip @@ -220,19 +220,14 @@ def _update_floating_ip(neutron, module, port_id, floating_ip_id): def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( network_name = dict(required=True), instance_name = dict(required=True), state = dict(default='present', choices=['absent', 'present']), internal_network_name = dict(default=None), - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) try: nova = nova_client.Client(module.params['login_username'], module.params['login_password'], @@ -266,5 +261,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_floating_ip_associate b/library/cloud/quantum_floating_ip_associate index 29df6856571..91df2690b62 100644 --- a/library/cloud/quantum_floating_ip_associate +++ b/library/cloud/quantum_floating_ip_associate @@ -178,18 +178,13 @@ def _update_floating_ip(neutron, module, port_id, floating_ip_id): def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( ip_address = dict(required=True), instance_name = dict(required=True), state = dict(default='present', choices=['absent', 'present']) - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) try: nova = nova_client.Client(module.params['login_username'], module.params['login_password'], @@ -218,5 +213,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_network b/library/cloud/quantum_network index 744fe44d8dc..606c493f398 100644 --- a/library/cloud/quantum_network +++ b/library/cloud/quantum_network @@ -230,13 +230,8 @@ def _delete_network(module, net_id, neutron): def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( name = dict(required=True), tenant_name = dict(default=None), provider_network_type = dict(default=None, choices=['local', 'vlan', 'flat', 'gre']), @@ -246,8 +241,8 @@ def main(): shared = dict(default=False, type='bool'), admin_state_up = dict(default=True, type='bool'), state = dict(default='present', choices=['absent', 'present']) - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) if module.params['provider_network_type'] in ['vlan' , 'flat']: if not module.params['provider_physical_network']: @@ -279,5 +274,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_router b/library/cloud/quantum_router index 36e027eccd1..d5f5d56a362 100644 --- a/library/cloud/quantum_router +++ b/library/cloud/quantum_router @@ -175,19 +175,14 @@ def _delete_router(module, neutron, router_id): return True def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( name = dict(required=True), tenant_name = dict(default=None), state = dict(default='present', choices=['absent', 'present']), admin_state_up = dict(type='bool', default=True), - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) neutron = _get_neutron_client(module, module.params) _set_tenant_id(module) @@ -210,5 +205,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_router_gateway b/library/cloud/quantum_router_gateway index 55295f76e40..5de19fd4785 100644 --- a/library/cloud/quantum_router_gateway +++ b/library/cloud/quantum_router_gateway @@ -174,18 +174,13 @@ def _remove_gateway_router(neutron, module, router_id): def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( router_name = dict(required=True), network_name = dict(required=True), state = dict(default='present', choices=['absent', 'present']), - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) neutron = _get_neutron_client(module, module.params) router_id = _get_router_id(module, neutron) @@ -213,5 +208,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_router_interface b/library/cloud/quantum_router_interface index 47e5f6b211a..8fdad4f8954 100644 --- a/library/cloud/quantum_router_interface +++ b/library/cloud/quantum_router_interface @@ -208,19 +208,14 @@ def _remove_interface_router(neutron, module, router_id, subnet_id): return True def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( router_name = dict(required=True), subnet_name = dict(required=True), tenant_name = dict(default=None), state = dict(default='present', choices=['absent', 'present']), - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) neutron = _get_neutron_client(module, module.params) _set_tenant_id(module) @@ -249,5 +244,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main() diff --git a/library/cloud/quantum_subnet b/library/cloud/quantum_subnet index 5afe566c8f8..5034a736a10 100644 --- a/library/cloud/quantum_subnet +++ b/library/cloud/quantum_subnet @@ -252,13 +252,8 @@ def _delete_subnet(module, neutron, subnet_id): def main(): - module = AnsibleModule( - argument_spec = dict( - login_username = dict(default='admin'), - login_password = dict(required=True), - login_tenant_name = dict(required='True'), - auth_url = dict(default='http://127.0.0.1:35357/v2.0/'), - region_name = dict(default=None), + argument_spec = openstack_argument_spec() + argument_spec.update(dict( name = dict(required=True), network_name = dict(required=True), cidr = dict(required=True), @@ -270,8 +265,8 @@ def main(): dns_nameservers = dict(default=None), allocation_pool_start = dict(default=None), allocation_pool_end = dict(default=None), - ), - ) + )) + module = AnsibleModule(argument_spec=argument_spec) neutron = _get_neutron_client(module, module.params) _set_tenant_id(module) if module.params['state'] == 'present': @@ -291,5 +286,6 @@ def main(): # this is magic, see lib/ansible/module.params['common.py from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * main()