#!/usr/bin/env python # Copyright 2016, 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. from magnumclient import client as magnum_client from ansible.module_utils.basic import * DOCUMENTATION = """ --- module: magnum version_added: "1.9.4" short_description: - Manage OpenStack Magnum Cluster Templates description: - Manage OpenStack Magnum Cluster Templates options: action: description: - Indicate the desired state of the resource choices: ['template-present', 'template-absent'] required: true name: description: - Name of the resource required: true openrc_path: description: - Path to OpenRC file required: true insecure: description: - Explicitly allow client to perform "insecure" TLS choices: - false - true default: false keypair: description: - Keypair for Cluster Template required: false image: description: - Image for Cluster Template required: false external_network: description: - External Network for Cluster Template required: false dns_nameserver: description: - DNS Nameserver for Cluster Template required: false flavor: description: - Flavor for Cluster Template required: false docker_volume_size: description: - Volume size (in GB) for Cluster Template required: false coe: description: - Container Orchestration Engine for Cluster Template required: false public: description: - Whether or not Cluster Template should be visible to all users required: false requirements: [ python-magnumclient ] author: Christopher Hultin """ EXAMPLES = """ #Create Swarm Template - magnum: action: 'template-present' name: 'swarm-dev-test' openrc_path: '/root/openrc' insecure: True keypair: 'testkey' image: 'fedora-atomic-latest' external_network: 'public' dns_nameserver: '8.8.8.8' flavor: 'm1.small' docker_volume_size: 5 coe: 'swarm' public: 'false' #Change the DNS Nameserver - magnum: action: 'template-present' name: 'swarm-dev-test' openrc_path: '/root/openrc' insecure: True keypair: 'testkey' image: 'fedora-atomic-latest' external_network: 'public' dns_nameserver: '8.8.4.4' flavor: 'm1.small' docker_volume_size: 5 coe: 'swarm' public: 'false' #Delete Template - magnum: action: 'template-absent' name: 'swarm-dev-test' openrc_path: '/root/openrc' insecure: True """ COMMAND_MAP = { 'template-present': 'template_present', 'template-absent': 'template_absent', } class ManageMagnum(object): def __init__(self, module): self.state_change = False self.magnum = None self.module = module try: self._init_magnum() 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 _init_magnum(self): openrc = self._parse_openrc() self.magnum = magnum_client.Client( username=openrc['OS_USERNAME'], password=openrc['OS_PASSWORD'], project_name=openrc['OS_PROJECT_NAME'], auth_url=openrc['OS_AUTH_URL'], service_type='container-infra', insecure=self.module.params['insecure'], user_domain_name=openrc['OS_USER_DOMAIN_NAME'], project_domain_name=openrc['OS_PROJECT_DOMAIN_NAME'] ) def route(self): """Run the command specified by the command parameter.""" getattr(self, COMMAND_MAP[self.module.params['action']])() def template_present(self): p = self.module.params template_name = p['name'] template_opts = dict( name=template_name, image_id=p['image'], keypair_id=p['keypair'], external_network_id=p['external_network'], dns_nameserver=p['dns_nameserver'], flavor_id=p['flavor'], docker_volume_size=p['docker_volume_size'], coe=p['coe'], public=p['public'] ) template_found = False updates = [] for template in self.magnum.cluster_templates.list(detail=True): if template.name == template_name: template_found = True if not template_found: try: self.magnum.cluster_templates.create(**template_opts) except Exception as e: self.module.fail_json( msg="Failed to create template: {}".format(e) ) self.state_change = True self.module.exit_json( changed=self.state_change ) else: try: for opt, val in template_opts.iteritems(): if (val != getattr(template, opt) and val is not None): updates.append({opt: val}) except Exception as e: self.module.fail_json( msg="Error: Parameters are undefined: {}".format(e) ) if len(updates) >= 1: try: self.magnum.cluster_templates.update(template_name, updates) except Exception as e: self.module.fail_json( msg="Failed to update template: {}".format(e) ) self.state_change = True else: self.state_change = False self.module.exit_json( changed=self.state_change ) def template_absent(self): p = self.module.params template_name = p['name'] for template in self.magnum.cluster_templates.list(detail=True): if template.name == template_name: try: self.magnum.cluster_templates.delete(template_name) except Exception as e: self.module.fail_json( msg="Failed to delete template: {}".format(e) ) self.state_change = True self.module.exit_json( changed=self.state_change ) def main(): module = AnsibleModule( argument_spec={ "name": {"required": True, "type": "str"}, "image": {"required": False, "type": "str"}, "keypair": {"required": False, "type": "str"}, "external_network": {"required": False, "type": "str"}, "dns_nameserver": {"required": False, "type": "str"}, "flavor": {"required": False, "type": "str"}, "docker_volume_size": {"required": False, "type": "int"}, "coe": {"required": False, "type": "str"}, "public": {"required": False, "type": "bool"}, "openrc_path": {"required": True, "type": "str"}, "insecure": {"required": False, "default": False, "type": "bool"}, "action": { "choices": ['template-present', 'template-absent', 'cluster-present', 'cluster-absent'], "type": "str" }, }, supports_check_mode=False ) mg = ManageMagnum(module) mg.route() if __name__ == '__main__': main()