Exemple #1
0
    def resolve_entity(self,
                       entity_id: str,
                       entity_type_id: str = None) -> DefEntity:  # noqa: E501
        """Resolve the entity.

        Validates the entity against the schema. Based on the result, entity
        state will be either changed to "RESOLVED" (or) "RESOLUTION ERROR".

        :param str entity_id: Id of the entity
        :return: Defined entity with its state updated.
        :rtype: DefEntity
        """
        if not entity_type_id:
            rde: DefEntity = self.get_entity(entity_id)
            entity_type_id = rde.entityType
        response_body = self._cloudapi_client.do_request(
            method=RequestMethod.POST,
            cloudapi_version=CloudApiVersion.VERSION_1_0_0,
            resource_url_relative_path=f"{CloudApiResource.ENTITIES}/"
            f"{entity_id}/{CloudApiResource.ENTITY_RESOLVE}")  # noqa: E501
        msg = response_body[def_constants.DEF_ERROR_MESSAGE_KEY]
        del response_body[def_constants.DEF_ERROR_MESSAGE_KEY]
        entity = DefEntity(entityType=entity_type_id, **response_body)
        # TODO: Just record the error message; revisit after HTTP response code
        # is good enough to decide if exception should be thrown or not
        if entity.state != def_constants.DEF_RESOLVED_STATE:
            LOGGER.error(msg)
        return entity
def process_behavior_request(msg_json, mqtt_publisher: MQTTPublisher):
    # Extracting contents from headers
    task_id: str = msg_json['headers']['taskId']
    entity_id: str = msg_json['headers']['entityId']
    behavior_id: str = msg_json['headers']['behaviorId']
    usr_ctx: BehaviorUserContext = BehaviorUserContext(**msg_json['headers']['context'])  # noqa: E501

    # Extracting contents from the input payload
    payload: dict = json.loads(msg_json['payload'])
    entity: dict = payload['entity']
    entity_type_id: str = payload['typeId']
    api_version: str = payload['_metadata']['apiVersion']

    # This is needed to enable unified API endpoint workflows. Unified API
    # endpoint is currently exposed at 37.0.0-alpha (VCD 10.3 Andromeda).
    if api_version == API_VERSION_37_ALPHA:
        api_version = ApiVersion.VERSION_36.value
    auth_token: str = payload['_metadata']['actAsToken']
    request_id: str = payload['_metadata']['requestId']
    arguments: dict = payload['arguments']

    # Initializing Behavior operation context
    op_ctx = OperationContext(auth_token=auth_token, request_id=request_id)  # noqa: E501
    behavior_ctx = RequestContext(
        behavior_id=behavior_id,
        task_id=task_id,
        entity_id=entity_id,
        payload=payload,
        api_version=float(api_version),
        entity=entity,
        user_context=usr_ctx,
        entity_type_id=entity_type_id,
        request_id=request_id,
        op_ctx=op_ctx,
        mqtt_publisher=mqtt_publisher,
        arguments=arguments
    )

    # Invoke the handler method and return the response in the string format.
    try:
        return MAP_BEHAVIOR_ID_TO_HANDLER_METHOD[behavior_id](behavior_ctx)
    except CseRequestError as e:
        error_details = asdict(BehaviorError(majorErrorCode=e.status_code,
                                             minorErrorCode=e.minor_error_code,
                                             message=e.error_message))
        payload = mqtt_publisher. \
            construct_behavior_payload(status=BehaviorTaskStatus.ERROR.value,
                                       error_details=error_details)
        LOGGER.error(f"Error while executing handler: {error_details}", exc_info=True)  # noqa: E501
        return payload
    except Exception as e:
        error_details = asdict(BehaviorError(majorErrorCode='500',
                                             message=str(e)))
        payload = mqtt_publisher. \
            construct_behavior_payload(status=BehaviorTaskStatus.ERROR.value,
                                       error_details=error_details)
        LOGGER.error(f"Error while executing handler: {error_details}", exc_info=True)  # noqa: E501
        return payload
Exemple #3
0
def get_request_id(request_msg, fsencoding):
    """."""
    request_id = None
    try:
        msg_json = json.loads(request_msg.decode(fsencoding))[0]
        request_id = msg_json['id']
    except Exception:
        LOGGER.error(traceback.format_exc())
    return request_id
Exemple #4
0
 def exception_handler_wrapper(*args, **kwargs):
     try:
         result = func(*args, **kwargs)
     except (KeyError, TypeError, ValueError) as error:
         LOGGER.error(error)
         raise cse_exception.BadRequestError(error_message=str(error))
     except Exception as error:
         LOGGER.error(error)
         raise error
     return result
Exemple #5
0
 def exception_handler_wrapper(*args, **kwargs):
     try:
         result = func(*args, **kwargs)
     except (KeyError, TypeError, ValueError) as error:
         LOGGER.error(error)
         raise cse_exception.BadRequestError(error_message=str(error))
     except Exception as error:
         LOGGER.error(error)
         if not isinstance(error, cse_exception.CseRequestError):
             raise cse_exception.InternalServerRequestError(
                 error_message=str(error))  # noqa: E501
         raise error
     return result
Exemple #6
0
    def connect(self):
        def on_connect(mqtt_client, userdata, flags, rc):
            LOGGER.info(f'MQTT client connected with result code {rc} and '
                        f'flags {flags}')
            mqtt_client.subscribe(self.listen_topic, qos=constants.QOS_LEVEL)

        def on_message(mqtt_client, userdata, msg):
            # No longer processing messages if server is closing
            if self._is_closing:
                return
            msg_json = json.loads(msg.payload.decode(self.fsencoding))
            if msg_json['type'] == 'BEHAVIOR_INVOCATION':
                if self._behavior_tpe.max_threads_busy():
                    # TODO Find out from Extensibility on what is recommended.
                    self.send_too_many_requests_response(msg)
                else:
                    self._behavior_tpe.submit(
                        lambda: self.process_behavior_message(msg_json=msg_json
                                                              ))  # noqa: E501
            elif self._ctpe.max_threads_busy():
                self.send_too_many_requests_response(msg)
            else:
                self._ctpe.submit(lambda: self.process_mqtt_message(msg))

        def on_subscribe(mqtt_client, userdata, msg_id, given_qos):
            LOGGER.info(f'MQTT client subscribed with given_qos: {given_qos}')

        def on_disconnect(mqtt_client, userdata, rc):
            LOGGER.info(f'MQTT disconnect with reason: {rc}')

        self._mqtt_client = mqtt.Client(client_id=constants.MQTT_CLIENT_ID,
                                        transport=constants.TRANSPORT_WSS)
        self._mqtt_client.username_pw_set(username=self.client_username,
                                          password=self.token)
        cert_req = ssl.CERT_REQUIRED if self.verify_ssl else ssl.CERT_NONE
        self._mqtt_client.tls_set(cert_reqs=cert_req)
        self._mqtt_client.ws_set_options(path=constants.MQTT_BROKER_PATH)

        # Setup callbacks
        self._mqtt_client.on_connect = on_connect
        self._mqtt_client.on_message = on_message
        self._mqtt_client.on_disconnect = on_disconnect
        self._mqtt_client.on_subscribe = on_subscribe

        try:
            self._mqtt_client.connect(self.url,
                                      port=constants.MQTT_CONNECT_PORT)
        except Exception as e:
            LOGGER.error(f'MQTT client connection error: {e}')
            raise
        self._mqtt_client.loop_forever()
Exemple #7
0
 def exception_handler_wrapper(*args, **kwargs):
     try:
         result = func(*args, **kwargs)
     except HTTPError as error:
         response_dict = json.loads(error.response.text)
         error_message = response_dict.get('message')
         LOGGER.error(error_message)
         raise cse_exception.DefEntityServiceError(
             error_message=error_message,
             minor_error_code=MinorErrorCode.DEFAULT_ERROR_CODE)
     except Exception as error:
         LOGGER.error(error)
         raise error
     return result
Exemple #8
0
    def connect(self):
        def on_connect(mqtt_client, userdata, flags, rc):
            LOGGER.info(f'MQTT client connected with result code {rc} and '
                        f'flags {flags}')
            mqtt_client.subscribe(self.listen_topic, qos=constants.QOS_LEVEL)

        def on_message(mqtt_client, userdata, msg):
            # No longer processing messages if server is closing
            if self._is_closing:
                return
            if self._ctpe.max_threads_busy():
                self.send_too_many_requests_response(msg)
            else:
                self._ctpe.submit(lambda: self.process_mqtt_message(msg))

        def on_subscribe(mqtt_client, userdata, msg_id, given_qos):
            LOGGER.info(f'MQTT client subscribed with given_qos: {given_qos}')

        def on_disconnect(mqtt_client, userdata, rc):
            LOGGER.info(f'MQTT disconnect with reason: {rc}')

        self._mqtt_client = mqtt.Client(client_id=constants.MQTT_CLIENT_ID,
                                        transport=constants.TRANSPORT_WSS)
        self._mqtt_client.username_pw_set(username=self.client_username,
                                          password=self.token)
        cert_req = ssl.CERT_REQUIRED if self.verify_ssl else ssl.CERT_NONE
        self._mqtt_client.tls_set(cert_reqs=cert_req)
        self._mqtt_client.ws_set_options(path=constants.MQTT_BROKER_PATH)

        # Setup callbacks
        self._mqtt_client.on_connect = on_connect
        self._mqtt_client.on_message = on_message
        self._mqtt_client.on_disconnect = on_disconnect
        self._mqtt_client.on_subscribe = on_subscribe

        # Set the mqtt publisher
        self._mqtt_publisher = MQTTPublisher(mqtt_client=self._mqtt_client,
                                             respond_topic=self.respond_topic,
                                             fsencoding=self.fsencoding)

        try:
            self._mqtt_client.connect(self.url,
                                      port=constants.MQTT_CONNECT_PORT)
        except Exception as e:
            LOGGER.error(f'MQTT client connection error: {e}')
            raise
        self._mqtt_client.loop_forever()
    def _form_updated_entity(self, entity_id: str, changes: dict):
        entity = self.get_entity(entity_id)
        # get entity call updates _cloudapi_client headers to get etag
        etag = self._cloudapi_client.get_last_response_etag()

        # form updated RDE
        for attr_str, value in changes.items():
            curr_obj = entity
            attrs: list = attr_str.split('.')
            last_attr: str = attrs.pop()
            for attr in attrs:
                try:
                    curr_obj = getattr(curr_obj, attr)
                except AttributeError as err:
                    LOGGER.error(
                        f"missing attribute [{attr}] in [{attr_str}] when updating RDE: {err}"
                    )  # noqa: E501
                    raise
            setattr(curr_obj, last_attr, value)
        return entity, etag
Exemple #10
0
def get_response_fields(request_msg, fsencoding, is_mqtt):
    """Get the msg json and response fields request message."""
    msg_json, request_id = None, None
    try:
        # Parse the message
        if is_mqtt:
            payload_json = json.loads(request_msg.payload.decode(fsencoding))
            http_req_json = json.loads(
                base64.b64decode(payload_json['httpRequest']))
            request_id = payload_json["headers"]["requestId"]
            msg_json = http_req_json['message']

            # Use api access token as authorization token -- this may involve
            # overwriting the current authorization token
            msg_json['headers']['Authorization'] = \
                'Bearer ' + http_req_json['securityContext']['apiAccessToken']
        else:
            msg_json = json.loads(request_msg.decode(fsencoding))[0]
            request_id = msg_json['id']

        thread_local_data.set_thread_local_data(ThreadLocalData.REQUEST_ID,
                                                request_id)  # noqa: E501
        thread_local_data.set_thread_local_data(
            ThreadLocalData.USER_AGENT,
            msg_json['headers'].get('User-Agent'))  # noqa: E501
        result = request_dispatcher.process_request(msg_json)
        status_code = result['status_code']
        reply_body = result['body']

    except Exception as e:
        if isinstance(e, CseRequestError):
            status_code = e.status_code
        else:
            status_code = requests.codes.internal_server_error
        reply_body = {RESPONSE_MESSAGE_KEY: str(e)}

        tb = traceback.format_exc()
        LOGGER.error(tb)
    return msg_json, reply_body, status_code, request_id
Exemple #11
0
def _get_cluster_and_broker(request_data, op_ctx, **kwargs):
    cluster_name = request_data[RequestKey.CLUSTER_NAME]

    pks_ctx_list = create_pks_context_for_all_accounts_in_org(op_ctx)
    for pks_ctx in pks_ctx_list:
        debug_msg = f"Get cluster info for cluster '{cluster_name}' " \
            f"failed on host '{pks_ctx['host']}' with error: "
        pks_broker = PksBroker(pks_ctx, op_ctx)
        try:
            return pks_broker.get_cluster_info(
                data=request_data, **kwargs), pks_broker  # noqa: E501
        except (PksClusterNotFoundError, PksServerError) as err:
            # continue searching using other PksBrokers
            LOGGER.debug(f"{debug_msg}{err}")
        except PksDuplicateClusterError as err:
            # fail because multiple clusters with same name exist
            LOGGER.debug(f"{debug_msg}{err}")
            raise
        except Exception as err:
            LOGGER.error(f"Unknown error: {err}", exc_info=True)
            raise

    # raised if cluster was not found in PksBrokers
    raise ClusterNotFoundError(f"Cluster '{cluster_name}' not found.")