#!/usr/bin/python # -*- coding: utf-8 -*- # # (c) 2016, René Moser # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . DOCUMENTATION = ''' --- module: cs_router short_description: Manages routers on Apache CloudStack based clouds. description: - Start, restart, stop and destroy routers. - C(state=present) is not able to create routers, use M(cs_network) instead. version_added: "2.2" author: "René Moser (@resmo)" options: name: description: - Name of the router. required: true service_offering: description: - Name or id of the service offering of the router. required: false default: null domain: description: - Domain the router is related to. required: false default: null account: description: - Account the router is related to. required: false default: null project: description: - Name of the project the router is related to. required: false default: null state: description: - State of the router. required: false default: 'present' choices: [ 'present', 'absent', 'started', 'stopped', 'restarted' ] extends_documentation_fragment: cloudstack ''' EXAMPLES = ''' # Ensure the router has the desired service offering, no matter if # the router is running or not. - local_action: module: cs_router name: r-40-VM service_offering: System Offering for Software Router # Ensure started - local_action: module: cs_router name: r-40-VM state: started # Ensure started with desired service offering. # If the service offerings changes, router will be rebooted. - local_action: module: cs_router name: r-40-VM service_offering: System Offering for Software Router state: started # Ensure stopped - local_action: module: cs_router name: r-40-VM state: stopped # Remove a router - local_action: module: cs_router name: r-40-VM state: absent ''' RETURN = ''' --- id: description: UUID of the router. returned: success type: string sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 name: description: Name of the router. returned: success type: string sample: r-40-VM created: description: Date of the router was created. returned: success type: string sample: 2014-12-01T14:57:57+0100 template_version: description: Version of the system VM template. returned: success type: string sample: 4.5.1 requires_upgrade: description: Whether the router needs to be upgraded to the new template. returned: success type: bool sample: false redundant_state: description: Redundant state of the router. returned: success type: string sample: UNKNOWN role: description: Role of the router. returned: success type: string sample: VIRTUAL_ROUTER zone: description: Name of zone the router is in. returned: success type: string sample: ch-gva-2 service_offering: description: Name of the service offering the router has. returned: success type: string sample: System Offering For Software Router state: description: State of the router. returned: success type: string sample: Active domain: description: Domain the router is related to. returned: success type: string sample: ROOT account: description: Account the router is related to. returned: success type: string sample: admin ''' try: from cs import CloudStack, CloudStackException, read_config has_lib_cs = True except ImportError: has_lib_cs = False # import cloudstack common from ansible.module_utils.cloudstack import * class AnsibleCloudStackRouter(AnsibleCloudStack): def __init__(self, module): super(AnsibleCloudStackRouter, self).__init__(module) self.returns = { 'serviceofferingname': 'service_offering', 'version': 'template_version', 'requiresupgrade': 'requires_upgrade', 'redundantstate': 'redundant_state', 'role': 'role' } self.router = None def get_service_offering_id(self): service_offering = self.module.params.get('service_offering') if not service_offering: return None args = {} args['issystem'] = True service_offerings = self.cs.listServiceOfferings(**args) if service_offerings: for s in service_offerings['serviceoffering']: if service_offering in [ s['name'], s['id'] ]: return s['id'] self.module.fail_json(msg="Service offering '%s' not found" % service_offering) def get_router(self): if not self.router: router = self.module.params.get('name') args = {} args['projectid'] = self.get_project(key='id') args['account'] = self.get_account(key='name') args['domainid'] = self.get_domain(key='id') routers = self.cs.listRouters(**args) if routers: for r in routers['router']: if router.lower() in [ r['name'].lower(), r['id']]: self.router = r break return self.router def start_router(self): router = self.get_router() if not router: self.module.fail_json(msg="Router not found") if router['state'].lower() != "running": self.result['changed'] = True args = {} args['id'] = router['id'] if not self.module.check_mode: res = self.cs.startRouter(**args) if 'errortext' in res: self.module.fail_json(msg="Failed: '%s'" % res['errortext']) poll_async = self.module.params.get('poll_async') if poll_async: router = self._poll_job(res, 'router') return router def stop_router(self): router = self.get_router() if not router: self.module.fail_json(msg="Router not found") if router['state'].lower() != "stopped": self.result['changed'] = True args = {} args['id'] = router['id'] if not self.module.check_mode: res = self.cs.stopRouter(**args) if 'errortext' in res: self.module.fail_json(msg="Failed: '%s'" % res['errortext']) poll_async = self.module.params.get('poll_async') if poll_async: router = self._poll_job(res, 'router') return router def reboot_router(self): router = self.get_router() if not router: self.module.fail_json(msg="Router not found") self.result['changed'] = True args = {} args['id'] = router['id'] if not self.module.check_mode: res = self.cs.rebootRouter(**args) if 'errortext' in res: self.module.fail_json(msg="Failed: '%s'" % res['errortext']) poll_async = self.module.params.get('poll_async') if poll_async: router = self._poll_job(res, 'router') return router def absent_router(self): router = self.get_router() if router: self.result['changed'] = True args = {} args['id'] = router['id'] if not self.module.check_mode: res = self.cs.destroyRouter(**args) if 'errortext' in res: self.module.fail_json(msg="Failed: '%s'" % res['errortext']) poll_async = self.module.params.get('poll_async') if poll_async: self._poll_job(res, 'router') return router def present_router(self): router = self.get_router() if not router: self.module.fail_json(msg="Router can not be created using the API, see cs_network.") args = {} args['id'] = router['id'] args['serviceofferingid'] = self.get_service_offering_id() state = self.module.params.get('state') if self.has_changed(args, router): self.result['changed'] = True if not self.module.check_mode: current_state = router['state'].lower() self.stop_router() router = self.cs.changeServiceForRouter(**args) if 'errortext' in router: self.module.fail_json(msg="Failed: '%s'" % res['errortext']) if state in [ 'restarted', 'started' ]: router = self.start_router() # if state=present we get to the state before the service # offering change. elif state == "present" and current_state == "running": router = self.start_router() elif state == "started": router = self.start_router() elif state == "stopped": router = self.stop_router() elif state == "restarted": router = self.reboot_router() return router def main(): argument_spec = cs_argument_spec() argument_spec.update(dict( name = dict(required=True), service_offering = dict(default=None), state = dict(choices=['present', 'started', 'stopped', 'restarted', 'absent'], default="present"), domain = dict(default=None), account = dict(default=None), project = dict(default=None), poll_async = dict(type='bool', default=True), )) module = AnsibleModule( argument_spec=argument_spec, required_together=cs_required_together(), supports_check_mode=True ) if not has_lib_cs: module.fail_json(msg="python library cs required: pip install cs") try: acs_router = AnsibleCloudStackRouter(module) state = module.params.get('state') if state in ['absent']: router = acs_router.absent_router() else: router = acs_router.present_router() result = acs_router.get_result(router) except CloudStackException as e: module.fail_json(msg='CloudStackException: %s' % str(e)) module.exit_json(**result) # import module snippets from ansible.module_utils.basic import * if __name__ == '__main__': main()