#!/usr/bin/env python # 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. try: import glanceclient.v2.client as glanceclient except ImportError: print("failed=True msg='module glanceclient is required for this module'") try: from keystoneclient.v3 import client as ksclient except ImportError: print( "failed=True msg='module keystoneclient is required for this module'" ) import hashlib import os try: from novaclient.v1_1 import client as nova_client from novaclient import exceptions except ImportError: print("failed=True msg='module novaclient is required for this module'") import time DOCUMENTATION = ''' --- module: glance_download short_description: Download file from Glance description: - Return the requested file from Glance to a location defined by the user. options: login_username: description: - login username to authenticate to keystone required: true default: admin login_password: description: - Password of login user required: true default: 'yes' login_tenant_name: description: - The tenant name of the login user required: true default: 'yes' auth_url: description: - The keystone url for authentication required: false default: 'http://127.0.0.1:35357/v2.0/' region_name: description: - Name of the region required: false default: None image_id: description: - Glance file ID that you wish to download. required: true default: None path: description: - Location where to save the file from Glance to required: true default: None requirements: ["glanceclient"] ''' EXAMPLES = ''' # Downloads a glance image to the defined path - glance_download: login_username: admin login_password: admin login_tenant_name: admin image_id: 4f905f38-e52a-43d2-b6ec-754a13ffb529 path: /tmp/4f905f38-e52a-43d2-b6ec-754a13ffb529.qcow2 ''' # The following openstack_ is a copy paste from an upcoming # core module "lib/ansible/module_utils/openstack.py" Once that's landed, # these should be replaced with a line at the bottom of the file: # from ansible.module_utils.openstack import * 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 def _glance_get_image_checksum(glance, image_id): return glance.images.get(image_id).checksum def _md5sum_file(path): try: with open(path) as file_object: checksum = hashlib.md5() while True: data = file_object.read(65535) if not data: break checksum.update(data) return checksum.hexdigest() except Excption, e: print("Checksum operaction failed: %s" % e.message) def _glance_download(module, glance, image_id, path): image_checksum = _glance_get_image_checksum(glance, image_id) if os.path.isfile(path): file_checksum = _md5sum_file(path) if image_checksum == file_checksum: module.exit_json( ansible_facts={ 'returned_checksum': file_checksum } ) try: file_data = glance.images.data(image_id) glanceclient.utils.save_image(file_data, path) except: module.fail_json( msg="Retrieval of image from Glance failed." ) file_checksum = _md5sum_file(path) if image_checksum == file_checksum: module.exit_json( ansible_facts={ 'returned_checksum': file_checksum } ) else: module.fail_json( msg="Glance checksum %s != %s checksum %s" % ( image_checksum, path, file_checksum ) ) def main(): argument_spec = openstack_argument_spec() argument_spec.update(dict( image_id=dict(required=True), path=dict(required=True) )) module = AnsibleModule(argument_spec=argument_spec) try: if '/v2.0' in module.params['auth_url']: module.params['auth_url'] = module.params['auth_url'].replace( '/v2.0', '/v3' ) keystone = ksclient.Client( username=module.params['login_username'], password=module.params['login_password'], tenant=module.params['login_tenant_name'], auth_url=module.params['auth_url'], region_name=module.params['region_name'] ) keystone.authenticate() except: module.fail_json( msg="Failed to Authenticate to Keystone" ) try: glance_endpoint = keystone.service_catalog.url_for( service_type='image', endpoint_type='publicURL' ) except: module.fail_json( msg="Failed to retrieve image server URL" ) try: glance = glanceclient.Client( endpoint=glance_endpoint, token=keystone.auth_token ) except: module.fail_json( msg="Failed to connect to Glance" ) _glance_download( module, glance, module.params['image_id'], module.params['path'] ) from ansible.module_utils.basic import * main()