|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +# Copyright (c) 2024, Lorenzo Tanganelli |
| 3 | +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) |
| 4 | + |
| 5 | +from __future__ import absolute_import, division, print_function |
| 6 | + |
| 7 | +__metaclass__ = type |
| 8 | + |
| 9 | + |
| 10 | +import os |
| 11 | +import re |
| 12 | +import sys |
| 13 | +import traceback |
| 14 | + |
| 15 | +from ansible.module_utils._text import to_native |
| 16 | +from ansible.module_utils.basic import missing_required_lib, AnsibleModule |
| 17 | + |
| 18 | +CS_IMP_ERR = None |
| 19 | +try: |
| 20 | + from cs import CloudStack, CloudStackException |
| 21 | + |
| 22 | + HAS_LIB_CS = True |
| 23 | +except ImportError: |
| 24 | + CS_IMP_ERR = traceback.format_exc() |
| 25 | + HAS_LIB_CS = False |
| 26 | + |
| 27 | + |
| 28 | +if sys.version_info > (3,): |
| 29 | + long = int |
| 30 | + |
| 31 | + |
| 32 | +class AnsibleCloudStackAPI(AnsibleModule): |
| 33 | + |
| 34 | + error_callback = None |
| 35 | + warn_callback = None |
| 36 | + AUTH_ARGSPEC = dict( |
| 37 | + api_key=os.getenv("CLOUDSTACK_KEY"), |
| 38 | + api_secret=os.getenv("CLOUDSTACK_SECRET"), |
| 39 | + api_url=os.getenv("CLOUDSTACK_ENDPOINT"), |
| 40 | + api_http_method=os.getenv("CLOUDSTACK_METHOD", "get"), |
| 41 | + api_timeout=os.getenv("CLOUDSTACK_TIMEOUT", 10), |
| 42 | + api_verify_ssl_cert=os.getenv("CLOUDSTACK_VERIFY"), |
| 43 | + validate_certs=os.getenv("CLOUDSTACK_DANGEROUS_NO_TLS_VERIFY", True), |
| 44 | + ) |
| 45 | + |
| 46 | + def __init__(self, argument_spec=None, direct_params=None, error_callback=None, warn_callback=None, **kwargs): |
| 47 | + |
| 48 | + if not HAS_LIB_CS: |
| 49 | + self.fail_json(msg=missing_required_lib("cs"), exception=CS_IMP_ERR) |
| 50 | + |
| 51 | + full_argspec = {} |
| 52 | + full_argspec.update(AnsibleCloudStackAPI.AUTH_ARGSPEC) |
| 53 | + full_argspec.update(argument_spec) |
| 54 | + kwargs["supports_check_mode"] = True |
| 55 | + |
| 56 | + self.error_callback = error_callback |
| 57 | + self.warn_callback = warn_callback |
| 58 | + |
| 59 | + self._cs = None |
| 60 | + self.result = {} |
| 61 | + |
| 62 | + if direct_params is not None: |
| 63 | + for param, value in full_argspec.items(): |
| 64 | + if param in direct_params: |
| 65 | + setattr(self, param, direct_params[param]) |
| 66 | + else: |
| 67 | + setattr(self, param, value) |
| 68 | + else: |
| 69 | + super(AnsibleCloudStackAPI, self).__init__(argument_spec=full_argspec, **kwargs) |
| 70 | + |
| 71 | + # Perform some basic validation |
| 72 | + if not re.match("^https{0,1}://", self.api_url): |
| 73 | + self.api_url = "https://{0}".format(self.api_url) |
| 74 | + |
| 75 | + def fail_json(self, **kwargs): |
| 76 | + if self.error_callback: |
| 77 | + self.error_callback(**kwargs) |
| 78 | + else: |
| 79 | + super().fail_json(**kwargs) |
| 80 | + |
| 81 | + def exit_json(self, **kwargs): |
| 82 | + super().exit_json(**kwargs) |
| 83 | + |
| 84 | + @property |
| 85 | + def cs(self): |
| 86 | + if self._cs is None: |
| 87 | + api_config = self.get_api_config() |
| 88 | + self._cs = CloudStack(**api_config) |
| 89 | + return self._cs |
| 90 | + |
| 91 | + def get_api_config(self): |
| 92 | + api_config = { |
| 93 | + "endpoint": self.api_url, |
| 94 | + "key": self.api_key, |
| 95 | + "secret": self.api_secret, |
| 96 | + "timeout": self.api_timeout, |
| 97 | + "method": self.api_http_method, |
| 98 | + "verify": self.api_verify_ssl_cert, |
| 99 | + "dangerous_no_tls_verify": not self.validate_certs, |
| 100 | + } |
| 101 | + |
| 102 | + return api_config |
| 103 | + |
| 104 | + def query_api(self, command, **args): |
| 105 | + |
| 106 | + try: |
| 107 | + res = getattr(self.cs, command)(**args) |
| 108 | + |
| 109 | + if "errortext" in res: |
| 110 | + self.fail_json(msg="Failed: '%s'" % res["errortext"]) |
| 111 | + |
| 112 | + except CloudStackException as e: |
| 113 | + self.fail_json(msg="CloudStackException: %s" % to_native(e)) |
| 114 | + |
| 115 | + except Exception as e: |
| 116 | + self.fail_json(msg=to_native(e)) |
| 117 | + |
| 118 | + # res.update({'params': self.result, 'query_params': args}) |
| 119 | + return res |
0 commit comments