def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState ensure_tracking_table_exists(session) if not model.ExecutionId: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.ExecutionId) try: ddbclient = session.client('dynamodb') item = ddbclient.get_item( TableName=TRACKING_TABLE_NAME, Key={'executionId': { 'S': model.ExecutionId }}) if 'Item' not in item: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.ExecutionId) except ddbclient.exceptions.ResourceNotFoundException: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.ExecutionId) except Exception as e: if not isinstance(e, exceptions.NotFound): raise exceptions.InternalFailure(f"{e}") raise e return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def execute_read_event_type_handler_work(session, model, progress): afd_client = client_helpers.get_afd_client(session) # read requests only include primary identifier (Arn). Extract Name from Arn if not model.Name: model.Name = model.Arn.split("/")[-1] # For contract_delete_read, we need to fail if the resource DNE # get_event_types will throw RNF Exception if event_type DNE ( get_event_types_works, get_event_types_response, ) = validation_helpers.check_if_get_event_types_succeeds( afd_client, model.Name) if not get_event_types_works: raise exceptions.NotFound("event_type", model.Name) try: event_types = get_event_types_response.get("eventTypes", []) if event_types: referenced_resources = model_helpers.get_referenced_resources( model) model = model_helpers.get_model_for_event_type( afd_client, event_types[0], referenced_resources) else: raise exceptions.NotFound("event_type", model.Name) progress.resourceModel = model progress.status = OperationStatus.SUCCESS except RuntimeError as e: raise exceptions.InternalFailure(f"Error occurred: {e}") LOG.info(f"Returning Progress with status: {progress.status}") return progress
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=None, ) try: client = session.client("transcribe") client.get_vocabulary( VocabularyName=model.VocabularyName ) client.delete_vocabulary( VocabularyName=model.VocabularyName ) progress.status = OperationStatus.SUCCESS except client.exceptions.NotFoundException as e: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) except Exception as e: if "t be found" in str(e): raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) raise exceptions.InternalFailure(f"{e}") return progress
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState config = request.typeConfiguration model.Notes = None try: req = requests.get(url='https://{}/v2/orders/{}'.format( ("api.alpaca.markets" if config.Credentials.Environment == "LIVE" else "paper-api.alpaca.markets"), model.Id), headers={ 'APCA-API-KEY-ID': config.Credentials.ApiKey, 'APCA-API-SECRET-KEY': config.Credentials.SecretKey }) if req.status_code == 404: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.Id) order = json.loads(req.text) if 'code' in order and order['code'] in [40410000, 40010001]: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.Id) if 'id' not in order: raise exceptions.InternalFailure(f"Internal failure") if order['canceled_at'] is not None: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.Id) model.Symbol = order['symbol'] model.Quantity = float(order['qty']) model.FilledQuantity = str(order['filled_qty']) if order['filled_avg_price'] == None: model.FilledValue = "0" model.CurrentValue = "0" else: model.FilledValue = str( float(order['filled_qty']) * float(order['filled_avg_price'])) req = requests.get( url='https://data.alpaca.markets/v2/stocks/{}/trades/latest'. format(order['symbol']), headers={ 'APCA-API-KEY-ID': config.Credentials.ApiKey, 'APCA-API-SECRET-KEY': config.Credentials.SecretKey }) trade = json.loads(req.text) model.CurrentValue = str( float(order['filled_qty']) * float(trade['trade']['p'])) model.FilledAt = order['filled_at'] except Exception as e: if not isinstance(e, exceptions.NotFound): raise exceptions.InternalFailure(f"{e}") raise e return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def validate_dependencies_for_detector_update( afd_client, model: models.ResourceModel, previous_model: models.ResourceModel): # TODO: revisit this validation when/if we support in-place teardown # For now, throw bad request for unsupported event type update, and validate external models + model versions # (Other updates that would require teardown will throw exception and trigger rollback) if model.EventType.Name != previous_model.EventType.Name: raise exceptions.InvalidRequest( f"Error: EventType.Name update is not allowed") if model.EventType.Inline != previous_model.EventType.Inline: raise exceptions.InvalidRequest( f"Error: EventType.Inline update is not allowed") if not model.EventType.Inline: event_type_name = util.extract_name_from_arn(model.EventType.Arn) ( get_event_types_succeeded, _, ) = validation_helpers.check_if_get_event_types_succeeds( afd_client, event_type_name) if not get_event_types_succeeded: raise exceptions.NotFound("detector.EventType", event_type_name) validation_helpers.validate_external_models_for_detector_model( afd_client, model) validation_helpers.validate_model_versions_for_detector_model( afd_client, model)
def get(self, desired: ResourceModel): try: account = self.organizations.describe_account(AccountId=desired.Id) except self.organizations.exceptions.AccountNotFoundException: raise exceptions.NotFound(OrganizationsAccountProvisioner.TYPE, desired.Id) parents = self.organizations.list_parents(ChildId=desired.Id) delegatedAdministratorServices = self.listDelegatedAdministratorServices( desired.Id) return ResourceModel._deserialize({ "Arn": account["Account"]["Arn"], "DelegatedAdministratorServices": delegatedAdministratorServices, "Email": account["Account"]["Email"], "Id": account["Account"]["Id"], "Name": account["Account"]["Name"], "ParentId": parents["Parents"][0]["Id"], "Status": account["Account"]["Status"] })
def execute_delete_event_type_handler_work(session, model, progress): afd_client = client_helpers.get_afd_client(session) # For contract_delete_delete, we need to fail if the resource DNE # get_event_types will throw RNF Exception if event_type DNE get_event_type_works, _ = validation_helpers.check_if_get_event_types_succeeds( afd_client, model.Name) if not get_event_type_works: raise exceptions.NotFound("event_type", model.Name) # Check for existing events, we'll need a DDB get call, since we do not have a plural `GetEvents` API # TODO: this, after event ingestion is released try: LOG.debug("deleting event type") api_helpers.call_delete_event_type(afd_client, model.Name) LOG.debug( "deleting inline dependencies (entity types, labels, event variables)" ) delete_worker_helpers.delete_inline_dependencies(afd_client, model) progress.resourceModel = None progress.status = OperationStatus.SUCCESS except RuntimeError as e: raise exceptions.InternalFailure(f"Error occurred: {e}") LOG.info(f"Returning Progress with status: {progress.status}") return progress
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, _c: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, ) if not proxy_needed(model.ClusterName, session): create_kubeconfig(model.ClusterName) _p, manifest_file, _d = handler_init( model, session, request.logicalResourceIdentifier, request.clientRequestToken ) if not get_model(model, session): raise exceptions.NotFound(TYPE_NAME, model.Uid) try: run_command( "kubectl delete -f %s -n %s" % (manifest_file, model.Namespace), model.ClusterName, session, ) except Exception as e: if "Error from server (NotFound)" not in str(e): raise return progress
def _validate_referenced_entity_type_for_event_type_update( afd_client, entity_type): entity_type_name = util.extract_name_from_arn(entity_type.Arn) get_entity_types_worked, _ = validation_helpers.check_if_get_entity_types_succeeds( afd_client, entity_type_name) if not get_entity_types_worked: raise exceptions.NotFound("entity_type", entity_type.Arn)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], # pylint: disable=unused-argument ) -> ProgressEvent: """This function is triggered by the CloudFormation READ event and will retrieve the StepConcurrency level of the cluster. Attributes: session (Optional[SessionProxy]): The session proxy for connecting to the needed AWS API client cluster_id (str): The unique ID of the cluster to get details from callback_context (MutableMapping[str, Any]): Use to store any state between re-invocation via IN_PROGRESS Returns: ProgressEvent: An event with the status of the action """ model = request.desiredResourceState if model.UID != get_uid(session, model.ClusterId): raise exceptions.NotFound(TYPE_NAME, model.ClusterId) try: model.StepConcurrencyLevel = get_concurrency_level( session, model.ClusterId) except Exception as unexpected_exception: LOG.error(str(unexpected_exception)) raise exceptions.InternalFailure( f"Failed Read: {str(unexpected_exception)}") return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info(request) if not session: raise exceptions.InternalFailure(f"boto3 session unavailable") if not request.desiredResourceState: raise exceptions.InternalFailure("Desired resource state unavailable") model = request.desiredResourceState organizations: Organizations.Client = session.client('organizations') try: scp = organizations.describe_policy(PolicyId=model.Id)["Policy"] except organizations.exceptions.PolicyNotFoundException: raise exceptions.NotFound(OrganizationsServiceControlPolicyProvisioner.TYPE, model.Id) model = ResourceModel._deserialize({ "Arn": scp["PolicySummary"]["Arn"], "Description": scp["PolicySummary"]["Description"], "Content": scp["Content"], "Id": scp["PolicySummary"]["Id"], "Name": scp["PolicySummary"]["Name"] }) return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def validate_model_versions_for_detector_model(afd_client, model: models.ResourceModel): if model.AssociatedModels is None: return for item in model.AssociatedModels: if util.is_external_model_arn(item.Arn): continue model_id, model_type, model_version_number = util.get_model_version_details_from_arn(item.Arn) get_model_version_worked, response = check_if_get_model_version_succeeds( frauddetector_client=afd_client, model_id=model_id, model_type=model_type, model_version_number=model_version_number, ) if not get_model_version_worked: raise exceptions.NotFound("ModelVersion", item.Arn) if response["status"] != "ACTIVE": raise exceptions.InvalidRequest( "Specified model must be in status:ACTIVE, ModelVersion arn='{}'".format(item.Arn) )
def execute_update_event_type_handler_work(session, model, progress, request): afd_client = client_helpers.get_afd_client(session) previous_resource_state: ResourceModel = request.previousResourceState # For contract_update_non_existent_resource, we need to fail if the resource DNE # get_event_types will throw RNF Exception if event_type DNE get_event_type_works, _ = validation_helpers.check_if_get_event_types_succeeds( afd_client, model.Name) if not get_event_type_works: raise exceptions.NotFound("event_type", model.Name) # # For contract_update_create_only_property, we need to fail if trying to set Name to something different previous_name = previous_resource_state.Name if model.Name != previous_name: raise exceptions.NotUpdatable( f"Error occurred: cannot update create-only property 'Name'") LOG.debug(f"updating tags for model ...") # since put_event_type does not update tags, update tags separately common_helpers.update_tags(afd_client, afd_resource_arn=model.Arn, new_tags=model.Tags) # Validate existence of referenced resources, validate and update inline resources # TODO: also check for when teardown is required, compare against AllowTeardown parameter, etc. LOG.debug(f"validating dependencies for update ...") update_worker_helpers.validate_dependencies_for_update( afd_client, model, previous_resource_state) # after satisfying contract call put event_type return common_helpers.put_event_type_and_return_progress( afd_client, model, progress)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, _c: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) if not proxy_needed(model.ClusterName, session): create_kubeconfig(model.ClusterName) if not get_model(model, session): raise exceptions.NotFound(TYPE_NAME, model.Uid) token, cluster_name, namespace, kind = decode_id(model.CfnId) _p, manifest_file, _d = handler_init( model, session, request.logicalResourceIdentifier, token ) outp = run_command( "kubectl apply -o json -f %s -n %s" % (manifest_file, model.Namespace), model.ClusterName, session, ) build_model(json.loads(outp), model) progress.status = OperationStatus.SUCCESS return progress
def get_ssm_parameter(name, session): try: ssm = session.client('ssm') response = ssm.get_parameter(Name=name) return response['Parameter']['Value'] except ClientError: raise exceptions.NotFound(TYPE_NAME, name)
def execute_read_variable_handler_work(session, model, progress): afd_client = client_helpers.get_afd_client(session) # read requests only include primary identifier (Arn). Extract Name from Arn model.Name = model.Arn.split("/")[-1] # For contract_delete_read, we need to fail if the resource DNE # get variables will throw RNF Exception if variable DNE ( get_variables_works, get_variables_response, ) = validation_helpers.check_if_get_variables_succeeds( afd_client, model.Name) if not get_variables_works: raise exceptions.NotFound("variable", model.Name) try: variables = get_variables_response.get("variables", []) if variables: model = model_helpers.get_model_for_variable( afd_client, variables[0]) progress.resourceModel = model progress.status = OperationStatus.SUCCESS except RuntimeError as e: raise exceptions.InternalFailure(f"Error occurred: {e}") return progress
def execute_update_variable_handler_work(session, model, progress, request): afd_client = client_helpers.get_afd_client(session) previous_resource_state: ResourceModel = request.previousResourceState # For contract_update_non_existent_resource, we need to fail if the resource DNE # get variables will throw RNF Exception if variable DNE ( get_variables_works, get_variables_response, ) = validation_helpers.check_if_get_variables_succeeds( afd_client, model.Name) if not get_variables_works: raise exceptions.NotFound("variable", model.Name) # # For contract_update_create_only_property, we need to fail if trying to set Name to something different previous_name = previous_resource_state.Name if model.Name != previous_name: raise exceptions.NotUpdatable( f"Error occurred: cannot update create-only property 'Name'") if model.Tags is None: # API does not handle 'None' property gracefully del model.Tags common_helpers.update_tags(afd_client, afd_resource_arn=model.Arn) else: # since update_variable does not update tags, update tags separately common_helpers.update_tags(afd_client, afd_resource_arn=model.Arn, new_tags=model.Tags) # after satisfying contract call update variable return common_helpers.update_variable_and_return_progress( afd_client, model, progress)
def _validate_referenced_event_type(afd_client, event_type_model: models.EventType): # check if event type exists, that's all. event_type_name = util.extract_name_from_arn(event_type_model.Arn) get_event_types_worked, _ = validation_helpers.check_if_get_event_types_succeeds( afd_client, event_type_name) if not get_event_types_worked: raise exceptions.NotFound("non-inline event_type", event_type_name)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState model.Phrases = None model.VocabularyFileUri = None try: client = session.client("transcribe") resp = client.get_vocabulary( VocabularyName=model.VocabularyName ) if resp['VocabularyState'] == "PENDING": return ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, callbackContext={ "pending": True } ) elif resp['VocabularyState'] == "FAILED": return ProgressEvent( status=OperationStatus.FAILED, message=resp['FailureReason'], resourceModel=model, ) else: model.LanguageCode = resp['LanguageCode'] except client.exceptions.NotFoundException as e: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) except Exception as e: if "t be found" in str(e): raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) raise exceptions.InternalFailure(f"{e}") return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def _validate_outcomes_for_rule(afd_client, rule_model: models.Rule): for outcome_model in rule_model.Outcomes: if outcome_model.Inline: _create_inline_outcome(afd_client, outcome_model) else: outcome_name = util.extract_name_from_arn(outcome_model.Arn) get_outcomes_worked, _ = validation_helpers.check_if_get_outcomes_succeeds( frauddetector_client=afd_client, outcome_name=outcome_name) if not get_outcomes_worked: raise exceptions.NotFound("non-inline outcome", outcome_name)
def delete(self, desired: ResourceModel): try: self.organizations.delete_policy(PolicyId=desired.Id) except self.organizations.exceptions.PolicyNotFoundException: raise exceptions.NotFound( OrganizationsServiceControlPolicyProvisioner.TYPE, desired.Id) except self.organizations.exceptions.PolicyInUseException: raise exceptions.ResourceConflict( f"Policy {desired.Id} cannot be deleted as it is currently in use" )
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], # pylint: disable=unused-argument ) -> ProgressEvent: """This function is triggered by the CloudFormation UPDATE event and will update the StepConcurrency level to the new provided value within the up to the max of 256. It will also add a tag to the cluster in order to keep track of the resource. Attributes: session (Optional[SessionProxy]): The session proxy for connecting to the needed AWS API client cluster_id (str): The unique ID of the cluster to get details from callback_context (MutableMapping[str, Any]): Use to store any state between re-invocation via IN_PROGRESS Returns: ProgressEvent: An event with the status of the action """ model = request.desiredResourceState previous_model = request.previousResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) LOG.info("UPDATE HANDLER") LOG.info("MODEL") LOG.info(model) LOG.info("PREVIOUS") LOG.info(previous_model) model.StepConcurrencyLevel = int(model.StepConcurrencyLevel) if model.UID != previous_model.UID: raise exceptions.InvalidRequest("Cannot update the UID") if model.StepConcurrencyLevel < 1 or model.StepConcurrencyLevel > 256: raise exceptions.InvalidRequest( f"Step Concurency Level must be between 1 and 256, \ {model.StepConcurrencyLevel} was given.") if model.UID != get_uid(session, model.ClusterId): raise exceptions.NotFound(TYPE_NAME, model.ClusterId) try: client = session.client('emr') LOG.info("Updating concurrency to %s for cluster %s", model.StepConcurrencyLevel, model.ClusterId) response = client.modify_cluster( ClusterId=model.ClusterId, StepConcurrencyLevel=model.StepConcurrencyLevel) LOG.info("RESPONSE: %s", response) progress.status = OperationStatus.SUCCESS except Exception as unexpected_exception: LOG.error(str(unexpected_exception)) raise exceptions.InternalFailure( f"Failed Update: {str(unexpected_exception)}") return progress
def validate_detector_exists_and_return_detector_resource_model( afd_client, model: models.ResourceModel) -> models.ResourceModel: # For contract_delete_read, we need to fail if the resource DNE ( get_detectors_works, get_detectors_response, ) = validation_helpers.check_if_get_detectors_succeeds( afd_client, model.DetectorId) if not get_detectors_works: raise exceptions.NotFound("detector", model.DetectorId) try: detectors = get_detectors_response.get("detectors", []) if not detectors: raise exceptions.NotFound("detector", model.DetectorId) return model_helpers.get_model_for_detector(afd_client, detectors[0], model) except RuntimeError as e: raise exceptions.InternalFailure(f"Error occurred: {e}")
def delete(self, desired: ResourceModel): try: self.organizations.delete_organizational_unit( OrganizationalUnitId=desired.Id) except self.organizations.exceptions.OrganizationalUnitNotFoundException: raise exceptions.NotFound(self.TYPE, desired.Id) except self.organizations.exceptions.OrganizationalUnitNotEmptyException: raise exceptions.ResourceConflict( f"Organizational Unit {desired.Id} cannot be deleted as it is not empty" )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, _callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState if not proxy_needed(model.ClusterName, session): create_kubeconfig(model.ClusterName) if not get_model(model, session): raise exceptions.NotFound(TYPE_NAME, model.Uid) return ProgressEvent(status=OperationStatus.SUCCESS, resourceModel=model,)
def validate_external_models_for_detector_model(afd_client, model: models.ResourceModel): LOG.info("validating external models for detector") existing_external_model_response = api_helpers.call_get_external_models(afd_client) existing_external_models = existing_external_model_response.get("externalModels", []) existing_external_model_arns = { external_model.get("arn", "not/found") for external_model in existing_external_models } for requested_external_model_arn in model_helpers.get_external_model_arns_from_model(model): if requested_external_model_arn not in existing_external_model_arns: LOG.warning(f"validation failed for external model: {requested_external_model_arn}") raise exceptions.NotFound("associatedModel", requested_external_model_arn)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) if not model.UID: raise exceptions.NotFound(TYPE_NAME, 'UID') state = get_ssm_parameter(model.UID + '-State', session) if state == 'DELETED': raise exceptions.NotFound(TYPE_NAME, 'UID') model.CIDRs = ','.join(set_cidr_list(model)) write_ssm_parameters(model.UID + '-CidrList', model.CIDRs, 'StringList', session) write_ssm_parameters(model.UID + '-State', 'UPDATED', 'String', session) progress.status = OperationStatus.SUCCESS return progress
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], # pylint: disable=unused-argument ) -> ProgressEvent: """This function is triggered by the CloudFormation DELETE event and will set the StepConcurrency level to the default of 1. It will also remove a tag on the cluster in order to keep track of the resource. Attributes: session (Optional[SessionProxy]): The session proxy for connecting to the needed AWS API client cluster_id (str): The unique ID of the cluster to get details from callback_context (MutableMapping[str, Any]): Use to store any state between re-invocation via IN_PROGRESS Returns: ProgressEvent: An event with the status of the action """ model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) LOG.info("DELETE HANDLER") if get_uid(session, model.ClusterId) != model.UID: raise exceptions.NotFound(TYPE_NAME, model.ClusterId) try: client = session.client('emr') LOG.info("Setting concurrency to default for cluster %s", model.ClusterId) response = client.modify_cluster(ClusterId=model.ClusterId, StepConcurrencyLevel=1) LOG.info("RESPONSE:") LOG.info("RESPONSE:") LOG.info(response) progress.resourceModel = None LOG.info("Removing Tags") tags_response = client.remove_tags(ResourceId=model.ClusterId, TagKeys=["StepConcurrencyUID"]) LOG.info("TAG REMOVAL RESPONSE") LOG.info(tags_response) LOG.info("TAG REMOVAL RESPONSE: %s", tags_response) progress.status = OperationStatus.SUCCESS except Exception as unexpected_exception: LOG.error(str(unexpected_exception)) raise exceptions.InternalFailure( f"Failed Delete: {str(unexpected_exception)}") return progress
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: # Read should not return writeOnlyProperties, and do a full read of the resource # See https://github.com/aws-cloudformation/cloudformation-cli/issues/370 key_name = request.desiredResourceState.KeyName ec2 = session.client("ec2") # type: botostubs.EC2 try: keypairs = ec2.describe_key_pairs(KeyNames=[key_name])["KeyPairs"] except ClientError as e: if e.response.get("Error", {}).get("Code") == "InvalidKeyPair.NotFound": raise exceptions.NotFound(TYPE_NAME, key_name) else: # raise the original exception raise if not len(keypairs) == 1: raise exceptions.NotFound(TYPE_NAME, key_name) return ProgressEvent(status=OperationStatus.SUCCESS, resourceModel=_create_model(keypairs[0]))
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) if callback_context.get('pending'): return read_handler(session, request, callback_context) try: client = session.client("transcribe") if model.Phrases is not None: client.update_vocabulary( VocabularyName=model.VocabularyName, LanguageCode=model.LanguageCode, Phrases=model.Phrases ) else: client.update_vocabulary( VocabularyName=model.VocabularyName, LanguageCode=model.LanguageCode, VocabularyFileUri=model.VocabularyFileUri ) except client.exceptions.NotFoundException as e: raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) except Exception as e: if "t be found" in str(e): raise exceptions.NotFound(type_name=TYPE_NAME, identifier=model.VocabularyName) raise exceptions.InternalFailure(f"{e}") return read_handler(session, request, callback_context)