class SolaceGetServiceAuthenticationLdapProfilesTask(SolaceGetTask):

    def __init__(self, module):
        super().__init__(module)
        self.config = SolaceTaskBrokerConfig(module)
        self.sempv1_get_paging_api = SolaceSempV1PagingGetApi(module)
        self.solace_cloud_api = SolaceCloudApi(module)

    def get_config(self) -> SolaceTaskBrokerConfig:
        return self.config

    def _get_list_solace_cloud(self):
        # GET services/{service-id}/requests/ldapAuthenticationProfile/default
        # only 1 exists, name=default
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
                      service_id, 'ldapAuthenticationProfile', 'default']
        return [self.solace_cloud_api.get_object_settings(self.get_config(), path_array)]

    def get_list(self):
        if self.get_config().is_solace_cloud():
            return self._get_list_solace_cloud()
        # SEMP V1
        params = self.get_config().get_params()
        rpc_dict = {
            'show': {
                'ldap-profile': {
                    'profile-name': params['where_name']
                }
            }
        }
        # test: paging
        # 'count': '',
        # 'num-elements': 1
        response_list_path_array = [
            'rpc-reply', 'rpc', 'show', 'ldap-profile', 'ldap-profile']
        return self.sempv1_get_paging_api.get_objects(self.get_config(), self.sempv1_get_paging_api.convertDict2Sempv1RpcXmlString(rpc_dict), response_list_path_array)

    def do_task(self):
        objects = self.get_list()
        result = self.create_result_with_list(objects)
        return None, result
 def __init__(self, module):
     super().__init__(module)
     self.config = SolaceTaskBrokerConfig(module)
     self.sempv1_get_paging_api = SolaceSempV1PagingGetApi(module)
     self.solace_cloud_api = SolaceCloudApi(module)
Ejemplo n.º 3
0
 def __init__(self, module):
     super().__init__(module)
     self.solace_cloud_api = SolaceCloudApi(module)
Ejemplo n.º 4
0
 def __init__(self, module: AnsibleModule):
     super().__init__(module)
     self.config = SolaceTaskSolaceCloudConfig(module)
     self.solace_cloud_api = SolaceCloudApi(module)
class SolaceCloudServiceTask(SolaceCloudCRUDTask):

    KEY_SERVICE_ID = 'serviceId'
    KEY_NAME = 'name'

    def __init__(self, module):
        super().__init__(module)
        self.solace_cloud_api = SolaceCloudApi(module)

    def validate_params(self):
        # state=present: name is required
        # state=absent: name or service_id required
        params = self.get_module().params
        name = params.get('name', None)
        service_id = params.get(self.get_config().PARAM_SERVICE_ID, None)
        state = params['state']
        if state == 'present' and not name:
            raise SolaceParamsValidationError(
                'name', name, "required for state='present'")
        if state == 'absent' and not name and not service_id:
            raise SolaceParamsValidationError(
                f"name, {self.get_config().PARAM_SERVICE_ID}", name, "at least one is required for state='absent'")

    def get_args(self):
        params = self.get_module().params
        service_id = params.get(self.get_config().PARAM_SERVICE_ID, None)
        if service_id:
            return self.KEY_SERVICE_ID, service_id
        name = params['name']
        return [self.KEY_NAME, name]

    def get_func(self, key, value):
        if key == self.KEY_NAME:
            services = self.solace_cloud_api.get_services(self.get_config())
            service = self.solace_cloud_api.find_service_by_name_in_services(
                services, value)
            if not service:
                return None
            service_id = service[self.KEY_SERVICE_ID]
        else:
            service_id = value
        # save service_id
        self._service_id = service_id
        service = self.solace_cloud_api.get_service(
            self.get_config(), self._service_id)
        if not service:
            return None
        if service['creationState'] == 'failed':
            logging.debug(
                "solace cloud service '%s' in failed state - deleting ...", value)
            _resp = self.solace_cloud_api.delete_service(
                self.get_config(), self._service_id)
            return None
        wait_timeout_minutes = self.get_module().params['wait_timeout_minutes']
        if service['creationState'] != 'completed' and wait_timeout_minutes > 0:
            logging.debug(
                "solace cloud service creationState not completed (creationState=%s) - waiting to complete ...", service['creationState'])
            service = self.solace_cloud_api.wait_for_service_create_completion(
                self.get_config(), wait_timeout_minutes, self._service_id)
        return service

    def create_func(self, key, name, settings=None):
        if not settings:
            raise SolaceParamsValidationError(
                'settings', settings, "required for creating a service")
        data = {
            'adminState': 'start',
            'partitionId': 'default',
            'name': name
        }
        data.update(settings)
        return self.solace_cloud_api.create_service(self.get_config(), self.get_module().params['wait_timeout_minutes'], data)

    # TODO: wait until implemented in Solace Cloud API
    # def update_func(self, key, name, settings=None, delta_settings=None):
    #     if not settings:
    #         raise SolaceParamsValidationError('settings', settings, "required for creating a service")
    #     data = {
    #         'adminState': 'start',
    #         'partitionId': 'default',
    #         'name': name
    #     }
    #     data.update(settings)
    #     return self.solace_cloud_api.create_service(self.get_config(), self.get_module().params['wait_timeout_minutes'], data)

    def update_func(self, key, value, settings=None, delta_settings=None):
        msg = [
            f"Solace Cloud Service '{key}={value}' already exists.",
            "You cannot update an existing service. Only option: delete & re-create.",
            "changes requested: see 'delta'"
        ]
        raise SolaceError(msg, dict(delta=delta_settings))

    def delete_func(self, key, value):
        return self.solace_cloud_api.delete_service(self.get_config(), self._service_id)
Ejemplo n.º 6
0
class SolaceCloudClientProfileTask(SolaceBrokerCRUDTask):

    OBJECT_KEY = 'clientProfileName'
    OPERATION = 'clientProfile'

    CREATE_DEFAULTS = {
        "allowGuaranteedMsgSendEnabled": "true",
        "allowGuaranteedMsgReceiveEnabled": "true",
        "allowUseCompression": "true",
        "replicationAllowClientConnectWhenStandbyEnabled": "false",
        "allowTransactedSessionsEnabled": "true",
        "allowBridgeConnectionsEnabled": "true",
        "allowGuaranteedEndpointCreateEnabled": "true",
        "allowSharedSubscriptionsEnabled": True,
        "apiQueueManagementCopyFromOnCreateName": "",
        "apiTopicEndpointManagementCopyFromOnCreateName": "",
        "serviceWebInactiveTimeout": "30",
        "serviceWebMaxPayload": "1000000",
        "maxConnectionCountPerClientUsername": "******",
        "serviceSmfMaxConnectionCountPerClientUsername": "******",
        "serviceWebMaxConnectionCountPerClientUsername": "******",
        "maxEndpointCountPerClientUsername": "******",
        "maxEgressFlowCount": "100",
        "maxIngressFlowCount": "100",
        "maxSubscriptionCount": "1000",
        "maxTransactedSessionCount": "100",
        "maxTransactionCount": "500",
        "queueGuaranteed1MaxDepth": "20000",
        "queueGuaranteed1MinMsgBurst": 66000,
        "queueDirect1MaxDepth": "20000",
        "queueDirect1MinMsgBurst": "4",
        "queueDirect2MaxDepth": "20000",
        "queueDirect2MinMsgBurst": "4",
        "queueDirect3MaxDepth": "20000",
        "queueDirect3MinMsgBurst": "4",
        "queueControl1MaxDepth": "20000",
        "queueControl1MinMsgBurst": "4",
        "tcpCongestionWindowSize": "2",
        "tcpKeepaliveCount": "5",
        "tcpKeepaliveIdleTime": "3",
        "tcpKeepaliveInterval": "1",
        "tcpMaxSegmentSize": "1460",
        "tcpMaxWindowSize": "256",
        "elidingDelay": 0,
        "elidingEnabled": True,
        "elidingMaxTopicCount": 256,
        "rejectMsgToSenderOnNoSubscriptionMatchEnabled": False,
        "tlsAllowDowngradeToPlainTextEnabled": True,
        "eventClientProvisionedEndpointSpoolUsageThreshold": {
            "setPercent": "80",
            "clearPercent": "60"
        }
    }

    def __init__(self, module):
        super().__init__(module)
        self.solace_cloud_api = SolaceCloudApi(module)

    def _adjust_settings_for_create(self, new_settings) -> dict:
        # placeholder in case customized data type transformation required for create operation
        return new_settings if new_settings else {}

    def _adjust_settings_for_update(self, new_settings, get_settings) -> dict:
        # add mandatory
        if 'eventClientProvisionedEndpointSpoolUsageThreshold' not in new_settings:
            new_settings[
                'eventClientProvisionedEndpointSpoolUsageThreshold'] = get_settings[
                    'eventClientProvisionedEndpointSpoolUsageThreshold']
        return new_settings

    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

    def normalize_current_settings(self, current_settings: dict,
                                   new_settings: dict) -> dict:
        normalized_current_settings = self.get_settings_type_conversion(
            current_settings) if current_settings else None
        return normalized_current_settings

    def normalize_new_settings(self, new_settings) -> dict:
        if new_settings:
            SolaceUtils.type_conversion(new_settings, False)
        return new_settings

    def get_args(self):
        params = self.get_module().params
        return [params['name']]

    def get_settings_arg_name(self) -> str:
        return 'solace_cloud_settings'

    def _compose_request_body(self, operation: str, operation_type: str,
                              settings: dict) -> dict:
        return {'operation': operation, operation_type: settings}

    def get_func(self, client_profile_name):
        # GET services/{paste-your-serviceId-here}/clientProfiles/{{clientProfileName}}
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, 'clientProfiles', client_profile_name
        ]
        return self.solace_cloud_api.get_object_settings(
            self.get_config(), path_array)

    def create_func(self, client_profile_name, settings=None):
        # POST services/{paste-your-serviceId-here}/requests/clientProfileRequests
        module_op = SolaceTaskOps.OP_CREATE_OBJECT
        data = {self.OBJECT_KEY: client_profile_name}
        data.update(self.CREATE_DEFAULTS)
        create_settings = self._adjust_settings_for_create(settings)
        data.update(create_settings)
        body = self._compose_request_body(operation='create',
                                          operation_type=self.OPERATION,
                                          settings=data)
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, SolaceCloudApi.API_REQUESTS, 'clientProfileRequests'
        ]
        return self.solace_cloud_api.make_service_post_request(
            self.get_config(),
            path_array,
            service_id,
            json_body=body,
            module_op=module_op)

    def update_func(self,
                    client_profile_name,
                    settings=None,
                    delta_settings=None):
        module_op = SolaceTaskOps.OP_UPDATE_OBJECT
        # POST services/{paste-your-serviceId-here}/requests/clientProfileRequests
        get_settings = self.get_func(client_profile_name)
        update_settings = self._adjust_settings_for_update(
            delta_settings, get_settings)
        mandatory = {self.OBJECT_KEY: client_profile_name}
        data = mandatory
        data.update(update_settings)
        body = self._compose_request_body(operation='update',
                                          operation_type=self.OPERATION,
                                          settings=data)
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, SolaceCloudApi.API_REQUESTS, 'clientProfileRequests'
        ]
        return self.solace_cloud_api.make_service_post_request(
            self.get_config(),
            path_array,
            service_id,
            json_body=body,
            module_op=module_op)

    def delete_func(self, client_profile_name):
        module_op = SolaceTaskOps.OP_DELETE_OBJECT
        # POST services/{paste-your-serviceId-here}/requests/clientProfileRequests
        data = {self.OBJECT_KEY: client_profile_name}
        body = self._compose_request_body(operation='delete',
                                          operation_type=self.OPERATION,
                                          settings=data)
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, SolaceCloudApi.API_REQUESTS, 'clientProfileRequests'
        ]
        return self.solace_cloud_api.make_service_post_request(
            self.get_config(),
            path_array,
            service_id,
            json_body=body,
            module_op=module_op)
 def __init__(self, module):
     super().__init__(module)
     self.sempv1_api = SolaceSempV1Api(module)
     self.solace_cloud_api = SolaceCloudApi(module)
     self.current_settings = None
class SolaceServiceAuthenticationLdapProfileTask(SolaceBrokerCRUDTask):

    MIN_SEMP_V1_VERSION = "9.1"

    def __init__(self, module):
        super().__init__(module)
        self.sempv1_api = SolaceSempV1Api(module)
        self.solace_cloud_api = SolaceCloudApi(module)
        self.current_settings = None

    def check_min_sempv1_supported_version(self):
        min_sempv1_version = SolaceUtils.create_version(
            self.MIN_SEMP_V1_VERSION)
        raw_api_version, version = self.sempv1_api.get_sempv1_version(
            self.get_config())
        if version < min_sempv1_version:
            raise SolaceSempv1VersionNotSupportedError(
                self.get_module()._name, f"{version}({raw_api_version})",
                min_sempv1_version)

    def normalize_current_settings(self, current_settings: dict,
                                   new_settings: dict) -> dict:
        if self.get_config().is_solace_cloud():
            # remember current_settings for update call: it needs it
            self.current_settings = current_settings
            return current_settings
        # SEMP V1
        # TODO: implement to test if changes are requested.
        # not trivial, what is the schema?
        # convert current_settings to same data structure as new_settings
        return current_settings

    def do_task_extension(self, args, new_state, new_settings,
                          current_settings):
        if not current_settings:
            name = self.get_module().params['name']
            usr_msg = f"ldap profile '{name}' does not exist; cannot enable/disable"
            raise SolaceModuleUsageError(self.get_module()._name, new_state,
                                         usr_msg)
        if self.get_config().is_solace_cloud():
            is_enabled = current_settings['enabled']
        else:
            is_enabled = True if current_settings['shutdown'] == 'No' else False
        if new_state == 'enabled':
            if is_enabled:
                return None, self.create_result(rc=0, changed=False)
            result = self.create_result(rc=0, changed=True)
            if not self.get_module().check_mode:
                result['response'] = self.enable_func(*args)
            return None, result
        if new_state == 'disabled':
            if not is_enabled:
                return None, self.create_result(rc=0, changed=False)
            result = self.create_result(rc=0, changed=True)
            if not self.get_module().check_mode:
                result['response'] = self.disable_func(*args)
            return None, result
        super().do_task_extension(args, new_state, new_settings,
                                  current_settings)

    def validate_params(self):
        params = self.get_module().params
        name = params.get('name', None)
        if self.get_config().is_solace_cloud() and name != 'default':
            raise SolaceParamsValidationError(
                'name', name,
                "ldap profile name for Solace Cloud must be 'default'.")
        invalid_chars = '-'
        if SolaceUtils.stringContainsAnyChars(name, invalid_chars):
            raise SolaceParamsValidationError(
                'name', name,
                f"contains 1 or more invalid chars from set: '{invalid_chars}'"
            )

    def get_args(self):
        params = self.get_module().params
        return [params['name']]

    def get_settings_arg_name(self) -> str:
        if self.get_config().is_solace_cloud():
            return 'solace_cloud_settings'
        else:
            return 'sempv1_settings'

    def _get_func_solace_cloud(self, ldap_profile_name):
        # GET services/{service-id}/requests/ldapAuthenticationProfile/default
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, 'ldapAuthenticationProfile', ldap_profile_name
        ]
        return self.solace_cloud_api.get_object_settings(
            self.get_config(), path_array)

    def get_func(self, ldap_profile_name):
        if self.get_config().is_solace_cloud():
            return self._get_func_solace_cloud(ldap_profile_name)
        # SEMP V1
        self.check_min_sempv1_supported_version()
        rpc_dict = {
            'show': {
                'ldap-profile': {
                    'profile-name': ldap_profile_name,
                    'detail': None
                }
            }
        }
        _resp = self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(rpc_dict),
            SolaceTaskOps.OP_READ_OBJECT)
        _resp_ldap_profile = _resp['rpc-reply']['rpc']['show']['ldap-profile']
        if _resp_ldap_profile:
            return _resp_ldap_profile['ldap-profile']
        else:
            return None

    def _disable_func_solace_cloud(self, ldap_profile_name):
        data = {'enabled': False}
        return self._make_solace_cloud_update_request(ldap_profile_name, data)

    def disable_func(self, ldap_profile_name):
        if self.get_config().is_solace_cloud():
            return self._disable_func_solace_cloud(ldap_profile_name)
        # SEMP V1
        rpc_dict = {
            'authentication': {
                'ldap-profile': {
                    'profile-name': ldap_profile_name,
                    'shutdown': None
                }
            }
        }
        _resp = self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(rpc_dict),
            SolaceTaskOps.OP_UPDATE_OBJECT)
        _call_log = {
            self.sempv1_api.getNextCallKey(): {
                'enable': {
                    'rpc': rpc_dict,
                    'response': _resp
                }
            }
        }
        return _call_log

    def _enable_func_solace_cloud(self, ldap_profile_name):
        data = {'enabled': True}
        return self._make_solace_cloud_update_request(ldap_profile_name, data)

    def enable_func(self, ldap_profile_name):
        if self.get_config().is_solace_cloud():
            return self._enable_func_solace_cloud(ldap_profile_name)
        # SEMP V1
        rpc_dict = {
            'authentication': {
                'ldap-profile': {
                    'profile-name': ldap_profile_name,
                    'no': {
                        'shutdown': None
                    }
                }
            }
        }
        _resp = self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(rpc_dict),
            SolaceTaskOps.OP_UPDATE_OBJECT)
        _call_log = {
            self.sempv1_api.getNextCallKey(): {
                'enable': {
                    'rpc': rpc_dict,
                    'response': _resp
                }
            }
        }
        return _call_log

    def _compose_solace_cloud_request_body(self, operation: str,
                                           settings: dict) -> dict:
        return {'operation': operation, 'ldapAuthenticationProfile': settings}

    def _make_solace_cloud_update_request(self, ldap_profile_name, settings):
        module_op = SolaceTaskOps.OP_UPDATE_OBJECT
        # POST services/{service-id}/requests/ldapAuthenticationProfileRequests
        data = self.current_settings if self.current_settings else {}
        data.update(settings if settings else {})
        body = self._compose_solace_cloud_request_body(operation='update',
                                                       settings=data)
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, SolaceCloudApi.API_REQUESTS,
            'ldapAuthenticationProfileRequests'
        ]
        return self.solace_cloud_api.make_service_post_request(
            self.get_config(),
            path_array,
            service_id,
            json_body=body,
            module_op=module_op)

    def _create_func_solace_cloud(self, ldap_profile_name, settings):
        data = {
            'profileName': ldap_profile_name,
            "searchDeref": "ALWAYS",
            "searchFilter": "(cn=$CLIENT_USERNAME)",
            "searchScope": "SUBTREE",
            "searchTimeout": 5,
            "groupMembershipSecondarySearchDeref": "ALWAYS",
            "groupMembershipSecondarySearchFilter":
            "(member=$ATTRIBUTE_VALUE_FROM_PRIMARY_SEARCH)",
            "groupMembershipSecondarySearchScope": "SUBTREE",
            "groupMembershipSecondarySearchTimeout": 5
        }
        data.update(settings if settings else {})
        return self._make_solace_cloud_update_request(ldap_profile_name, data)

    def create_func(self, ldap_profile_name, settings=None):
        if self.get_config().is_solace_cloud():
            return self._create_func_solace_cloud(ldap_profile_name, settings)
        # SEMP V1
        create_rpc_dict = {
            'authentication': {
                'create': {
                    'ldap-profile': {
                        'profile-name': ldap_profile_name
                    }
                }
            }
        }
        resp = self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(create_rpc_dict),
            SolaceTaskOps.OP_CREATE_OBJECT)
        if settings:
            resp = self._update_func_sempv1(ldap_profile_name, settings,
                                            settings,
                                            SolaceTaskOps.OP_CREATE_OBJECT)
        return resp

    def _update_func_solace_cloud(self, ldap_profile_name, settings,
                                  delta_settings):
        return self._make_solace_cloud_update_request(ldap_profile_name,
                                                      settings)

    def _send_sempv1_update(self, ldap_profile_name, key, val, op):
        _rpc_update_dict = {'authentication': {'ldap-profile': {key: val}}}
        _rpc_dict = {
            'authentication': {
                'ldap-profile': {
                    'profile-name': ldap_profile_name
                }
            }
        }
        rpc_dict = SolaceUtils.merge_dicts_recursive(_rpc_dict,
                                                     _rpc_update_dict)
        return self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(rpc_dict), op)

    def _update_func_sempv1(self, ldap_profile_name, settings, delta_settings,
                            op):
        if not settings:
            return None
        combined_resps = {}
        # iterate over settings.keys and send 1 update after the other
        for key, val in settings.items():
            if val:
                if key == 'search' and isinstance(val, dict):
                    # iterate through sarch
                    for skey, sval in val.items():
                        _resp = self._send_sempv1_update(
                            ldap_profile_name, key, {skey: sval}, op)
                        _call_log = {
                            self.sempv1_api.getNextCallKey(): {
                                key: {
                                    skey: sval,
                                    'response': _resp
                                }
                            }
                        }
                        combined_resps = SolaceUtils.merge_dicts_recursive(
                            combined_resps, _call_log)
                else:
                    _resp = self._send_sempv1_update(ldap_profile_name, key,
                                                     val, op)
                    _call_log = {
                        self.sempv1_api.getNextCallKey(): {
                            key: val,
                            'response': _resp
                        }
                    }
                    combined_resps = SolaceUtils.merge_dicts_recursive(
                        combined_resps, _call_log)
        return combined_resps

    def update_func(self,
                    ldap_profile_name,
                    settings=None,
                    delta_settings=None):
        if self.get_config().is_solace_cloud():
            return self._update_func_solace_cloud(ldap_profile_name, settings,
                                                  delta_settings)
        return self._update_func_sempv1(ldap_profile_name, settings,
                                        delta_settings,
                                        SolaceTaskOps.OP_UPDATE_OBJECT)

    def _delete_func_solace_cloud(self, ldap_profile_name):
        raise SolaceNoModuleStateSupportError(
            self.get_module()._name,
            self.get_module().params['state'], 'Solace Cloud',
            'disable profile instead')

    def delete_func(self, ldap_profile_name):
        if self.get_config().is_solace_cloud():
            return self._delete_func_solace_cloud(ldap_profile_name)
        # SEMP V1
        rpc_dict = {
            'authentication': {
                'no': {
                    'ldap-profile': {
                        'profile-name': ldap_profile_name
                    }
                }
            }
        }
        return self.sempv1_api.make_post_request(
            self.get_config(),
            self.sempv1_api.convertDict2Sempv1RpcXmlString(rpc_dict),
            SolaceTaskOps.OP_DELETE_OBJECT)
 def __init__(self, module):
     super().__init__(module)
     self.sempv2_api = SolaceSempV2Api(module)
     self.sempv1_api = SolaceSempV1Api(module)
     self.solace_cloud_api = SolaceCloudApi(module)
class SolaceGatherFactsTask(SolaceBrokerGetTask):
    def __init__(self, module):
        super().__init__(module)
        self.sempv2_api = SolaceSempV2Api(module)
        self.sempv1_api = SolaceSempV1Api(module)
        self.solace_cloud_api = SolaceCloudApi(module)

    def add_path_value(self, dictionary, path_array, value):
        if len(path_array) > 1:
            if path_array[0] not in dictionary.keys():
                dictionary[path_array[0]] = {}
            self.add_path_value(dictionary[path_array[0]], path_array[1:],
                                value)
        else:
            if (path_array[0] == ''):
                dictionary['broker'] = value
            else:
                dictionary[path_array[0]] = value

    def get_about_info(self):
        # GET /about, /about/api, /about/user, /about/user/msgVpns
        about_info = {}
        path_array_list = [["about"], ["about", "user"],
                           ["about", "user", "msgVpns"], ["about", "api"]]
        for path_array in path_array_list:
            resp = self.sempv2_api.make_get_request(
                self.get_config(),
                [SolaceSempV2Api.API_BASE_SEMPV2_CONFIG] + path_array)
            self.add_path_value(about_info, path_array, resp)
        about_info['isSolaceCloud'] = self.get_config().is_solace_cloud()
        return about_info

    def get_service_info(self) -> dict:
        use_sempv1_also = self.get_config().get_params()['use_sempv1_also']
        resp = dict(vpns={})
        # get service info
        if self.get_config().is_solace_cloud():
            resp['solace_cloud_service'] = self.solace_cloud_api.get_service(
                self.get_config(),
                self.get_module().params['solace_cloud_service_id'])
            resp['virtualRouterName'] = "n/a"
        else:
            path_array = [SolaceSempV2Api.API_BASE_SEMPV2_CONFIG]
            resp['sempv2_service'] = self.sempv2_api.get_object_settings(
                self.get_config(), path_array)
            if use_sempv1_also:
                # get virtual router
                xml_post_cmd = "<rpc><show><router-name></router-name></show></rpc>"
                resp_virtual_router = self.sempv1_api.make_post_request(
                    self.get_config(), xml_post_cmd,
                    SolaceTaskOps.OP_READ_OBJECT)
                resp['virtualRouterName'] = resp_virtual_router['rpc-reply'][
                    'rpc']['show']['router-name']['router-name']

        # get vpns info
        msg_vpns = self.sempv2_api.make_get_request(self.get_config(), [
            SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, "about", "user", "msgVpns"
        ])
        for msg_vpn in msg_vpns:
            # GET /msgVpns/{msgVpnName}
            vpn_name = msg_vpn['msgVpnName']
            path_array = [
                SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, 'msgVpns', vpn_name
            ]
            msg_vpn_info = self.sempv2_api.get_object_settings(
                self.get_config(), path_array)
            resp['vpns'].update({vpn_name: msg_vpn_info})

        return resp

    def do_task(self):

        ansible_facts = dict(solace={})
        about_info = self.get_about_info()
        service_info = self.get_service_info()
        ansible_facts['solace'].update(about_info)
        ansible_facts['solace'].update(service_info)

        result = self.create_result()
        result.update(dict(ansible_facts=ansible_facts))
        return None, result
Ejemplo n.º 11
0
class SolaceVpnTask(SolaceBrokerCRUDTask):

    OBJECT_KEY = 'msgVpnName'
    SOLACE_CLOUD_SETTINGS = {
        'authenticationBasicEnabled':
        False,
        'authenticationBasicType': ['LDAP', 'INTERNAL', 'NONE'],
        'authenticationClientCertEnabled':
        False,
        'authenticationClientCertValidateDateEnabled':
        False,
        'authenticationOauthEnabled':
        False,
        'authenticationClientCertAllowApiProvidedUsernameEnabled':
        False,
        'authenticationClientCertUsernameSource':
        ['COMMON_NAME', 'SUBJECT_ALTERNATE_NAME_MSUPN']
    }

    def __init__(self, module):
        super().__init__(module)
        self.sempv2_api = SolaceSempV2Api(module)
        self.solace_cloud_api = SolaceCloudApi(module)
        self.current_settings = None

    def validate_params(self):
        pass

    def get_args(self):
        params = self.get_module().params
        return [params['name']]

    def get_settings_arg_name(self) -> str:
        return 'sempv2_settings'

    def normalize_current_settings(self, current_settings: dict,
                                   new_settings: dict) -> dict:
        if self.get_config().is_solace_cloud():
            # remember current_settings for update call: it needs it
            self.current_settings = current_settings
        return current_settings

    def _remove_solace_cloud_keys(self, settings):
        _settings = SolaceUtils.deep_copy(settings)
        for key in self.SOLACE_CLOUD_SETTINGS.keys():
            _settings.pop(key, None)
        return _settings

    def _convert_new_settings_to_solace_cloud_api(self, new_settings):
        val = new_settings.get('authenticationBasicType', None)
        if val:
            new_val = val.upper().replace('-', '_')
            new_settings['authenticationBasicType'] = new_val
        val = new_settings.get('authenticationClientCertUsernameSource', None)
        if val:
            new_val = val.upper().replace('-', '_')
            new_settings['authenticationClientCertUsernameSource'] = new_val
        return new_settings

    def _normalize_new_settings_solace_cloud(self, new_settings):
        val = new_settings.get('authenticationBasicType', None)
        if val:
            new_val = val.lower().replace('_', '-')
            new_settings['authenticationBasicType'] = new_val
        val = new_settings.get('authenticationClientCertUsernameSource', None)
        if val:
            new_val = val.lower().replace('_', '-')
            new_settings['authenticationClientCertUsernameSource'] = new_val
        return new_settings

    def normalize_new_settings(self, new_settings) -> dict:
        # solace cloud and self-hosted broker return the same types
        if new_settings:
            SolaceUtils.type_conversion(new_settings, False)
            if self.get_config().is_solace_cloud():
                new_settings = self._normalize_new_settings_solace_cloud(
                    new_settings)
        return new_settings

    def get_func(self, vpn_name):
        # notes:
        # - solace-cloud: could get the settings via: GET the service: msgVpnAttributes. but looks like they are the same
        # GET /msgVpns/{msgVpnName}
        path_array = [
            SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, 'msgVpns', vpn_name
        ]
        return self.sempv2_api.get_object_settings(self.get_config(),
                                                   path_array)

    def create_func(self, vpn_name, settings=None):
        if self.get_config().is_solace_cloud():
            raise SolaceModuleUsageError(
                self.get_module()._name,
                self.get_module().params['state'],
                "cannot create a new message vpn on a Solace Cloud service")
        # POST /msgVpns
        data = {self.OBJECT_KEY: vpn_name}
        data.update(settings if settings else {})
        path_array = [SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, 'msgVpns']
        return self.sempv2_api.make_post_request(self.get_config(), path_array,
                                                 data)

    def _update_func_solace_cloud(self, vpn_name, settings, delta_settings):
        # extract solace cloud api settings from settings -> send via solace cloud api
        # rest: send via sempv2 api
        _solace_cloud_api_settings = {}
        for key in self.SOLACE_CLOUD_SETTINGS.keys():
            _solace_cloud_api_settings.update({
                key:
                settings[key]
                if key in settings else self.current_settings[key]
            })
        _solace_cloud_api_settings = self._convert_new_settings_to_solace_cloud_api(
            _solace_cloud_api_settings)
        # POST: services/{service-id}}/requests/updateAuthenticationRequests
        module_op = SolaceTaskOps.OP_UPDATE_OBJECT
        service_id = self.get_config().get_params()['solace_cloud_service_id']
        path_array = [
            SolaceCloudApi.API_BASE_PATH, SolaceCloudApi.API_SERVICES,
            service_id, SolaceCloudApi.API_REQUESTS,
            'updateAuthenticationRequests'
        ]
        solace_cloud_resp = self.solace_cloud_api.make_service_post_request(
            self.get_config(),
            path_array,
            service_id,
            json_body=_solace_cloud_api_settings,
            module_op=module_op)
        # check for sempv2 settings, extract and send
        _sempv2_api_settings = self._remove_solace_cloud_keys(settings)
        sempv2_resp = {}
        if _sempv2_api_settings:
            sempv2_resp = self._update_func_sempv2(vpn_name,
                                                   _sempv2_api_settings)
        resp = {'solace-cloud': solace_cloud_resp, 'semp-v2': sempv2_resp}
        return resp

    def _update_func_sempv2(self,
                            vpn_name,
                            settings=None,
                            delta_settings=None):
        # PATCH /msgVpns/{msgVpnName}
        path_array = [
            SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, 'msgVpns', vpn_name
        ]
        return self.sempv2_api.make_patch_request(self.get_config(),
                                                  path_array, settings)

    def update_func(self, vpn_name, settings=None, delta_settings=None):
        if self.get_config().is_solace_cloud():
            return self._update_func_solace_cloud(vpn_name, settings,
                                                  delta_settings)
        return self._update_func_sempv2(vpn_name, settings, delta_settings)

    def delete_func(self, vpn_name):
        if self.get_config().is_solace_cloud():
            raise SolaceModuleUsageError(
                self.get_module()._name,
                self.get_module().params['state'],
                "cannot delete a message vpn on a Solace Cloud service")
        # DELETE /msgVpns/{msgVpnName}
        path_array = [
            SolaceSempV2Api.API_BASE_SEMPV2_CONFIG, 'msgVpns', vpn_name
        ]
        return self.sempv2_api.make_delete_request(self.get_config(),
                                                   path_array)