Example #1
0
    def do_task(self):
        self.validate_params()
        account_name = self.get_module().params['account_name']
        return_format = self.module.params['return_format']
        facts = {}
        if return_format == 'dict':
            facts = dict(data_centers={}, services={})
        elif return_format == 'list':
            facts = dict(data_centers=[], services=[])
        else:
            raise SolaceInternalError(
                f"arg 'return_format={return_format}' invalid")

        services = self.get_solace_cloud_api().get_services_with_details(
            self.get_config())
        data_centers = self.get_solace_cloud_api().get_data_centers(
            self.get_config())

        if return_format == 'dict':
            for service in services:
                name = service['name']
                facts['services'][name] = service
            for data_center in data_centers:
                id = data_center['id']
                facts['data_centers'][id] = data_center
        else:
            facts['services'] = services
            facts['data_centers'] = data_centers

        result = self.create_result()
        result.update(dict(solace_cloud_account={account_name: facts}))
        return None, result
Example #2
0
 def get_objects(self, config: SolaceTaskBrokerConfig, xml_cmd: str,
                 reponse_list_path_array: list) -> list:
     result_list = []
     hasNextPage = True
     while hasNextPage:
         semp_resp = self.make_post_request(
             config, xml_cmd, SolaceTaskOps.OP_READ_OBJECT_LIST)
         # extract the list
         _d = semp_resp
         for path in reponse_list_path_array:
             if _d and path in _d:
                 _d = _d[path]
             else:
                 # empty list / not found
                 return []
         if isinstance(_d, dict):
             resp = [_d]
         elif isinstance(_d, list):
             resp = _d
         else:
             raise SolaceInternalError(
                 f"unknown SEMP v1 return type: {type(_d)}")
         result_list.extend(resp)
         # see if there is more
         more_cookie = None
         if 'more-cookie' in semp_resp['rpc-reply']:
             more_cookie = semp_resp['rpc-reply']['more-cookie']
         if more_cookie:
             xml_cmd = xmltodict.unparse(more_cookie)
             hasNextPage = True
         else:
             hasNextPage = False
     return result_list
 def get_sempv2_version_map_key(self, semp_version):
     if semp_version <= SolaceUtils.create_version("2.13"):
         return '<=2.13'
     elif semp_version >= SolaceUtils.create_version("2.14"):
         return '>=2.14'
     raise SolaceInternalError(
         f"sempv2_version: {semp_version} not supported")
Example #4
0
    def get_settings_type_conversion(self, d):
        # everything is a string or null

        # import logging
        # import json
        # logging.debug(f"d={json.dumps(d, indent=2)}")

        for k, i in d.items():
            t = type(i)
            if t == dict:
                d[k] = self.get_settings_type_conversion(i)
            else:
                if i and t != str:
                    raise SolaceInternalError(
                        f"unhandled type, field={k}, value={i}, type={t}")
                if not i:
                    # placeholder, leave it for now
                    d[k] = None
                elif i == "":
                    # placeholder, leave it for now
                    d[k] = i
                elif i.lower() == 'false':
                    d[k] = False
                elif i.lower() == 'true':
                    d[k] = True
                elif re.search(r'^[0-9]+$', i):
                    d[k] = int(i)
                elif re.search(r'^[0-9]+\.[0-9]$', i):
                    d[k] = float(i)
                else:
                    # leave any other strings
                    d[k] = i
        return d
Example #5
0
 def _extract_msg_vpn_attributes(self) -> dict:
     vpn_attributes = SolaceBrokerFacts.get_field(self.input_dict,
                                                  "msgVpnAttributes")
     if not vpn_attributes:
         raise SolaceInternalError(
             "Could not find 'msgVpnAttributes' in 'ansible_facts.solace'. API may have changed."
         )
     return vpn_attributes
Example #6
0
 def _extract_messaging_protocols(self) -> dict:
     if self.messaging_protocols:
         return self.messaging_protocols
     mps = self.get_field(self.input_dict, "messagingProtocols")
     if not mps:
         raise SolaceInternalError(
             "Could not find 'messagingProtocols' in 'ansible_facts.solace'. API may have changed."
         )
     self.messaging_protocols = mps
     return self.messaging_protocols
Example #7
0
 def find_service_by_name_in_services(self, services, name):
     if isinstance(services, dict):
         if name == services.get('name'):
             return services
     elif isinstance(services, list):
         for service in services:
             if name == service.get('name'):
                 return service
     else:
         raise SolaceInternalError(
             f"solace cloud response not 'dict' nor 'list' but {type(services)}"
         )
     return None
Example #8
0
 def get_sempv2_version(self, config: SolaceTaskBrokerConfig):
     resp = self.make_get_request(config,
                                  [SolaceSempV2Api.API_BASE_SEMPV2_CONFIG] +
                                  ["about", "api"],
                                  query_params=None)
     raw_api_version = SolaceUtils.get_key(resp, "sempVersion")
     # format: 2.21
     try:
         v = SolaceUtils.create_version(raw_api_version)
     except SolaceInternalError as e:
         raise SolaceInternalError(
             f"sempv2 version parsing failed: {raw_api_version}") from e
     return raw_api_version, v
Example #9
0
 def get_sempv1_version(self, config: SolaceTaskBrokerConfig):
     rpc_xml = "<rpc><show><service></service></show></rpc>"
     resp = self.make_post_request(config, rpc_xml,
                                   SolaceTaskOps.OP_READ_SEMP_VERSION)
     rpc_reply = resp['rpc-reply']
     raw_api_version = SolaceUtils.get_key(rpc_reply, "@semp-version")
     # format: soltr/9_9VMR
     s = raw_api_version[6:9].replace('_', '.')
     try:
         v = SolaceUtils.create_version(s)
     except SolaceInternalError as e:
         raise SolaceInternalError(
             f"sempv1 version parsing failed: {raw_api_version}") from e
     return raw_api_version, v
Example #10
0
 def filter(self, settings: dict, query_params: dict) -> dict:
     if not query_params:
         return settings
     where_list = []
     if ("where" in query_params and query_params['where']
             and len(query_params['where']) > 0):
         where_list = query_params['where']
     is_match = True
     for where in where_list:
         # OP: ==
         where_elements = where.split('==')
         if len(where_elements) != 2:
             raise SolaceParamsValidationError(
                 'query_params.where', where,
                 "cannot parse where clause - must be in format '{key}=={pattern}' (other ops are not supported)"
             )
         sempv2_key = where_elements[0]
         pattern = where_elements[1]
         solace_cloud_key = self.MAPPINGS.get(sempv2_key, None)
         if not solace_cloud_key:
             raise SolaceParamsValidationError(
                 'query_params.where', where,
                 f"unknown key for solace cloud '{sempv2_key}' - check with Solace Cloud API settings"
             )
         # pattern match
         solace_cloud_value = settings.get(solace_cloud_key, None)
         if not solace_cloud_value:
             raise SolaceInternalError(
                 f"solace-cloud-key={solace_cloud_key} not found in solace cloud settings - likely a key map issue"
             )
         # create regex
         regex = pattern.replace("*", ".+")
         this_match = re.search(regex, solace_cloud_value)
         is_match = (is_match and this_match)
         if not is_match:
             break
     if is_match:
         return settings
     return None
Example #11
0
    def make_service_post_request(self, config: SolaceTaskBrokerConfig,
                                  path_array: list, service_id: str, json_body,
                                  module_op):
        resp = self.make_request(config, requests.post, path_array, json_body)
        # import logging, json
        # logging.debug(f"resp (make_request) = \n{json.dumps(resp, indent=2)}")
        request_id = resp['id']
        timeout_minutes = 2
        is_completed = False
        is_failed = False
        try_count = -1
        delay = 5  # seconds
        max_retries = (timeout_minutes * 60) // delay
        # wait 1 cycle before start polling
        time.sleep(delay)
        while not is_completed and not is_failed and try_count < max_retries:
            resp = self.get_service_request_status(config, service_id,
                                                   request_id)
            # import logging, json
            # logging.debug(f"resp (get_service_request_status)= \n{json.dumps(resp, indent=2)}")
            is_completed = (resp['adminProgress'] == 'completed')
            is_failed = (resp['adminProgress'] == 'failed')
            try_count += 1
            if timeout_minutes > 0:
                time.sleep(delay)

        if is_failed:
            raise SolaceApiError(resp, resp,
                                 self.get_module()._name, module_op)
        if not is_completed:
            msg = [
                f"timeout service post request - not completed, state={resp['adminProgress']}",
                str(resp)
            ]
            raise SolaceInternalError(msg)
        return resp
Example #12
0
    def do_task(self):
        self.validate_params()
        params = self.get_config().get_params()
        is_check_mode = self.get_module().check_mode

        self.existing_key_list = self.get_object_key_list(
            *self.get_objects_result_data_object_keys())
        # logging.debug(
        #     f"\n\n>>>>>>>>>>existing_key_list={json.dumps(self.existing_key_list, indent=2)}\n\n")
        target_key_list = self.deduplicate_keys(self.get_target_key_list())
        # logging.debug(
        #     f"\n\n>>>>>>>>>>target_key_list={json.dumps(target_key_list, indent=2)}\n\n")
        self.set_result(self.create_result(rc=0, changed=False))
        state_object_combination_error = False
        new_state = params['state']
        new_settings = self.get_new_settings()
        for target_key in target_key_list:
            crud_args = self.get_crud_args(target_key)
            target_key_exists = target_key in self.existing_key_list
            if (new_state == 'present' or new_state == 'exactly') and not target_key_exists:
                self.changed = True
                if not is_check_mode:
                    try:
                        _response = self.create_func(*crud_args, new_settings)
                        self.created_key_list.append(target_key)
                    except Exception as ex:
                        self.do_rollback_on_error(target_key, ex)

            elif new_state == 'present' and target_key_exists:
                pass
            elif new_state == 'absent' and target_key_exists:
                if not is_check_mode:
                    try:
                        _response = self.delete_func(*crud_args)
                        self.deleted_key_list.append(target_key)
                    except Exception as ex:
                        self.do_rollback_on_error(target_key, ex)
            elif new_state == 'absent' and not target_key_exists:
                pass
            elif new_state == 'exactly' and target_key_exists:
                pass
            elif new_state == 'exactly':
                pass
            else:
                state_object_combination_error = True

        if new_state == 'exactly':
            for existing_key in self.existing_key_list:
                crud_args = self.get_crud_args(existing_key)
                if new_state == 'exactly' and existing_key not in target_key_list:
                    if not is_check_mode:
                        try:
                            _response = self.delete_func(*crud_args)
                            self.deleted_key_list.append(existing_key)
                        except Exception as ex:
                            self.do_rollback_on_error(existing_key, ex)
                elif new_state == 'exactly' and existing_key in target_key_list:
                    pass
                else:
                    state_object_combination_error = True

        if state_object_combination_error:
            raise SolaceInternalError([
                "unsupported state / object combination",
                f"state={new_state}",
                f"target_key_list={target_key_list}",
                f"existing_key_list={self.existing_key_list}"
            ])

        response_list = []
        for k in self.created_key_list:
            response_list.append({'added': k})
        for k in self.deleted_key_list:
            response_list.append({'deleted': k})
        for k in self.duplicate_key_list:
            response_list.append({'duplicate': k})
        if len(response_list) > 0:
            self.changed = True
        self.update_result(
            {
                'changed': self.changed,
                'response': response_list
            })
        return None, self.get_result()
Example #13
0
 def call_dynamic_func(self, func_name, *args):
     try:
         return getattr(self, func_name)(*args)
     except AttributeError as e:
         raise SolaceInternalError(
             f"function '{func_name}' not found") from e
Example #14
0
 def get_key(d: dict, k: str):
     try:
         return d[k]
     except KeyError as e:
         raise SolaceInternalError(
             f"KeyError: dict has no key '{k}'") from e
Example #15
0
 def create_version(s: str):
     try:
         v = packaging.version.Version(s)
     except packaging.version.InvalidVersion as e:
         raise SolaceInternalError(f"version parsing failed: {s}") from e
     return v
Example #16
0
 def do_task_extension(self, args, new_state, new_settings, current_settings):
     raise SolaceInternalError(
         f"unhandled task-state combination, state={new_state}")
 def get_solace_cloud_auth(self) -> str:
     if not self.is_solace_cloud:
         raise SolaceInternalError(
             "config does not contain solace cloud parameters")
     return self.solace_cloud_auth