#!/usr/bin/env python # Copyright 2014, Rackspace US, 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. DOCUMENTATION = """ --- module: glance short_description: - Basic module for interacting with openstack glance description: - Basic module for interacting with openstack glance options: command: description: - Operation for the module to perform. Currently available choices: - image-list - image-create openrc_path: decription: - Path to openrc file from which credentials and keystoneclient - endpoint will be extracted image_name: description: - Name of the image to create image_url: description: - URL from which to download the image data image_container_format: description: - container format that the image uses (bare) image_disk_format: description: - disk format that the image uses image_is_public: description: - Should the image be visible to all tenants? choices: - true (public) - false (private) api_version: description: - which version of the glance api to use choices: - 1 - 2 default: 1 insecure: description: - Explicitly allow client to perform "insecure" TLS choices: - false - true default: false author: Hugh Saunders """ EXAMPLES = """ # Create an image - name: Ensure cirros image glance: command: 'image-create' openrc_path: /root/openrc image_name: cirros image_url: 'https://example-domain.com/cirros-0.3.2-source.tar.gz' image_container_format: bare image_disk_format: qcow2 image_is_public: True # Get facts about existing images - name: Get image facts glance: command: 'image-list' openrc_path: /root/openrc """ import glanceclient.client as glclient import keystoneclient.v3.client as ksclient COMMAND_MAP = {'image-list': 'list_images', 'image-create': 'create_image'} class ManageGlance(object): def __init__(self, module): self.state_change = False self.glance = None self.keystone = None self.module = module try: self._keystone_authenticate() self._init_glance() except Exception as e: self.module.fail_json( err="Initialisation Error: %s" % e, rc=2, msg=str(e)) def _parse_openrc(self): """Get credentials from an openrc file.""" openrc_path = self.module.params['openrc_path'] line_re = re.compile('^export (?POS_\w*)=(?P[^\n]*)') with open(openrc_path) as openrc: matches = [line_re.match(l) for l in openrc] return dict( (g.groupdict()['key'], g.groupdict()['value']) for g in matches if g ) def _keystone_authenticate(self): """Authenticate with Keystone.""" openrc = self._parse_openrc() insecure = self.module.params['insecure'] self.keystone = ksclient.Client(insecure=insecure, username=openrc['OS_USERNAME'], password=openrc['OS_PASSWORD'], project_name=openrc['OS_PROJECT_NAME'], auth_url=openrc['OS_AUTH_URL']) def _init_glance(self): """Create glance client object using token and url from keystone.""" openrc = self._parse_openrc() p = self.module.params v = p['api_version'] ep = self.keystone.service_catalog.url_for( service_type='image', endpoint_type=openrc['OS_ENDPOINT_TYPE'] ) self.glance = glclient.Client( endpoint='%s/v%s' % (ep, v), token=self.keystone.get_token(self.keystone.session) ) def route(self): """Run the command specified by the command parameter.""" getattr(self, COMMAND_MAP[self.module.params['command']])() def _get_image_facts(self): """Helper function to format image list as a dictionary.""" p = self.module.params v = p['api_version'] if v == '1': return dict( (i.name, i.to_dict()) for i in self.glance.images.list() ) elif v == '2': return dict( (i.name, i) for i in self.glance.images.list() ) def list_images(self): """Get information about available glance images. Returns as a fact dictionary glance_images """ self.module.exit_json( changed=self.state_change, ansible_facts=dict(glance_images=self._get_image_facts())) def create_image(self): """Create a glance image that references a remote url.""" p = self.module.params v = p['api_version'] image_name = p['image_name'] image_opts = dict( name=image_name, disk_format=p['image_disk_format'], container_format=p['image_container_format'], copy_from=p['image_url'] ) if v == '1': image_opts['is_public'] = p['image_is_public'] elif v == '2': if p['image_is_public']: vis = 'public' else: vis = 'private' image_opts['visibility'] = vis images = {i.name for i in self.glance.images.list()} if image_name in images: self.module.exit_json( changed=self.state_change, ansible_facts=dict( glance_images=self._get_image_facts() ) ) else: self.glance.images.create(**image_opts) self.state_change = True self.module.exit_json( changed=self.state_change, ansible_facts=dict( glance_images=self._get_image_facts() ) ) def main(): module = AnsibleModule( argument_spec=dict( command=dict(required=True, choices=COMMAND_MAP.keys()), openrc_path=dict(required=True), image_name=dict(required=False), image_url=dict(required=False), image_container_format=dict(required=False), image_disk_format=dict(required=False), image_is_public=dict(required=False, choices=BOOLEANS), api_version=dict(default='1', required=False, choices=['1', '2']), insecure=dict(default=False, required=False, choices=BOOLEANS + ['True', 'False']) ), supports_check_mode=False ) mg = ManageGlance(module) mg.route() from ansible.module_utils.basic import * if __name__ == '__main__': main()