diff --git a/v2/ansible/module_utils/cloudstack.py b/v2/ansible/module_utils/cloudstack.py new file mode 100644 index 0000000000..2c891434bd --- /dev/null +++ b/v2/ansible/module_utils/cloudstack.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# +# (c) 2015, René Moser +# +# 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. +# +# 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: + from cs import CloudStack, CloudStackException, read_config + has_lib_cs = True +except ImportError: + has_lib_cs = False + + +class AnsibleCloudStack: + + def __init__(self, module): + if not has_lib_cs: + module.fail_json(msg="python library cs required: pip install cs") + + self.module = module + self._connect() + + self.project_id = None + self.ip_address_id = None + self.zone_id = None + self.vm_id = None + self.os_type_id = None + self.hypervisor = None + + + def _connect(self): + api_key = self.module.params.get('api_key') + api_secret = self.module.params.get('secret_key') + api_url = self.module.params.get('api_url') + api_http_method = self.module.params.get('api_http_method') + + if api_key and api_secret and api_url: + self.cs = CloudStack( + endpoint=api_url, + key=api_key, + secret=api_secret, + method=api_http_method + ) + else: + self.cs = CloudStack(**read_config()) + + + def get_project_id(self): + if self.project_id: + return self.project_id + + project = self.module.params.get('project') + if not project: + return None + + projects = self.cs.listProjects() + if projects: + for p in projects['project']: + if project in [ p['name'], p['displaytext'], p['id'] ]: + self.project_id = p['id'] + return self.project_id + self.module.fail_json(msg="project '%s' not found" % project) + + + def get_ip_address_id(self): + if self.ip_address_id: + return self.ip_address_id + + ip_address = self.module.params.get('ip_address') + if not ip_address: + self.module.fail_json(msg="IP address param 'ip_address' is required") + + args = {} + args['ipaddress'] = ip_address + args['projectid'] = self.get_project_id() + ip_addresses = self.cs.listPublicIpAddresses(**args) + + if not ip_addresses: + self.module.fail_json(msg="IP address '%s' not found" % args['ipaddress']) + + self.ip_address_id = ip_addresses['publicipaddress'][0]['id'] + return self.ip_address_id + + + def get_vm_id(self): + if self.vm_id: + return self.vm_id + + vm = self.module.params.get('vm') + if not vm: + self.module.fail_json(msg="Virtual machine param 'vm' is required") + + args = {} + args['projectid'] = self.get_project_id() + vms = self.cs.listVirtualMachines(**args) + if vms: + for v in vms['virtualmachine']: + if vm in [ v['displayname'], v['name'], v['id'] ]: + self.vm_id = v['id'] + return self.vm_id + self.module.fail_json(msg="Virtual machine '%s' not found" % vm) + + + def get_zone_id(self): + if self.zone_id: + return self.zone_id + + zone = self.module.params.get('zone') + zones = self.cs.listZones() + + # use the first zone if no zone param given + if not zone: + self.zone_id = zones['zone'][0]['id'] + return self.zone_id + + if zones: + for z in zones['zone']: + if zone in [ z['name'], z['id'] ]: + self.zone_id = z['id'] + return self.zone_id + self.module.fail_json(msg="zone '%s' not found" % zone) + + + def get_os_type_id(self): + if self.os_type_id: + return self.os_type_id + + os_type = self.module.params.get('os_type') + if not os_type: + return None + + os_types = self.cs.listOsTypes() + if os_types: + for o in os_types['ostype']: + if os_type in [ o['description'], o['id'] ]: + self.os_type_id = o['id'] + return self.os_type_id + self.module.fail_json(msg="OS type '%s' not found" % os_type) + + + def get_hypervisor(self): + if self.hypervisor: + return self.hypervisor + + hypervisor = self.module.params.get('hypervisor') + hypervisors = self.cs.listHypervisors() + + # use the first hypervisor if no hypervisor param given + if not hypervisor: + self.hypervisor = hypervisors['hypervisor'][0]['name'] + return self.hypervisor + + for h in hypervisors['hypervisor']: + if hypervisor.lower() == h['name'].lower(): + self.hypervisor = h['name'] + return self.hypervisor + self.module.fail_json(msg="Hypervisor '%s' not found" % hypervisor) + + + def _poll_job(self, job=None, key=None): + if 'jobid' in job: + while True: + res = self.cs.queryAsyncJobResult(jobid=job['jobid']) + if res['jobstatus'] != 0 and 'jobresult' in res: + if 'errortext' in res['jobresult']: + self.module.fail_json(msg="Failed: '%s'" % res['jobresult']['errortext']) + if key and key in res['jobresult']: + job = res['jobresult'][key] + break + time.sleep(2) + return job