Ejemplo n.º 1
0
def try_upgrade(resource_repo: ResourceRepository, resource_template_repo: ResourceTemplateRepository, properties: dict, user: User, resource_to_update_id: str) -> Resource:
    resource_to_update = resource_repo.get_resource_by_id(resource_to_update_id)

    # get the template for the resource to upgrade
    parent_service_name = ""
    if resource_to_update.resourceType == ResourceType.UserResource:
        parent_service_name = resource_to_update["parentWorkspaceServiceId"]

    resource_template_to_send = resource_template_repo.get_current_template(resource_to_update.templateName, resource_to_update.resourceType, parent_service_name)

    # create the patch
    patch = ResourcePatch(
        properties=properties
    )

    # validate and submit the patch
    resource_to_send, _ = resource_repo.patch_resource(
        resource=resource_to_update,
        resource_patch=patch,
        resource_template=resource_template_to_send,
        etag=resource_to_update.etag,
        resource_template_repo=resource_template_repo,
        user=user)

    return resource_to_send
Ejemplo n.º 2
0
def get_current_template_by_name(template_name: str,
                                 template_repo: ResourceTemplateRepository,
                                 resource_type: ResourceType,
                                 parent_service_template_name: str = "",
                                 is_update: bool = False) -> dict:
    try:
        template = template_repo.get_current_template(
            template_name, resource_type, parent_service_template_name)
        return template_repo.enrich_template(template, is_update=is_update)
    except EntityDoesNotExist:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
                            detail=strings.TEMPLATE_DOES_NOT_EXIST)
    except DuplicateEntity:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                            detail=strings.NO_UNIQUE_CURRENT_FOR_TEMPLATE)
    except Exception as e:
        logging.debug(e)
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                            detail=strings.STATE_STORE_ENDPOINT_NOT_RESPONDING)
Ejemplo n.º 3
0
 def patch_workspace(self, workspace: Workspace,
                     workspace_patch: ResourcePatch, etag: str,
                     resource_template_repo: ResourceTemplateRepository,
                     user: User) -> Tuple[Workspace, ResourceTemplate]:
     # get the workspace template
     workspace_template = resource_template_repo.get_template_by_name_and_version(
         workspace.templateName, workspace.templateVersion,
         ResourceType.Workspace)
     return self.patch_resource(workspace, workspace_patch,
                                workspace_template, etag,
                                resource_template_repo, user)
Ejemplo n.º 4
0
 def patch_shared_service(
         self, shared_service: SharedService,
         shared_service_patch: ResourcePatch, etag: str,
         resource_template_repo: ResourceTemplateRepository,
         user: User) -> Tuple[SharedService, ResourceTemplate]:
     # get shared service template
     shared_service_template = resource_template_repo.get_template_by_name_and_version(
         shared_service.templateName, shared_service.templateVersion,
         ResourceType.SharedService)
     return self.patch_resource(shared_service, shared_service_patch,
                                shared_service_template, etag,
                                resource_template_repo, user)
Ejemplo n.º 5
0
    def validate_patch(self, resource_patch: ResourcePatch, resource_template_repo: ResourceTemplateRepository, resource_template: ResourceTemplate):
        # get the enriched (combined) template
        enriched_template = resource_template_repo.enrich_template(resource_template, is_update=True)

        # validate the PATCH data against a cut down version of the full template.
        update_template = copy.deepcopy(enriched_template)
        update_template["required"] = []
        update_template["properties"] = {}
        for prop_name, prop in enriched_template["properties"].items():
            if("updateable" in prop.keys() and prop["updateable"] is True):
                update_template["properties"][prop_name] = prop

        self._validate_resource_parameters(resource_patch.dict(), update_template)
Ejemplo n.º 6
0
def update_resource_for_step(operation_step: OperationStep, resource_repo: ResourceRepository, resource_template_repo: ResourceTemplateRepository, primary_resource_id: str, resource_to_update_id: str, primary_action: str, user: User) -> Resource:
    # create properties dict - for now we create a basic, string only dict to use as a patch
    # get primary resource to use in substitutions
    primary_resource = resource_repo.get_resource_by_id(primary_resource_id)

    # if this is main, just leave it alone and return it
    if operation_step.stepId == "main":
        return primary_resource

    # get the template for the primary resource, to get all the step details for substitutions
    primary_parent_service_name = ""
    if primary_resource.resourceType == ResourceType.UserResource:
        primary_parent_workspace_service = resource_repo.get_resource_by_id(primary_resource.parentWorkspaceServiceId)
        primary_parent_service_name = primary_parent_workspace_service.templateName
    primary_template = resource_template_repo.get_current_template(primary_resource.templateName, primary_resource.resourceType, primary_parent_service_name)

    # get the template step
    template_step = None
    for step in primary_template.pipeline.dict()[primary_action]:
        if step["stepId"] == operation_step.stepId:
            template_step = parse_obj_as(PipelineStep, step)
            break

    if template_step is None:
        raise f"Cannot find step with id of {operation_step.stepId} in template {primary_resource.templateName} for action {primary_action}"

    # TODO: actual substitution logic #1679
    properties = {}
    for prop in template_step.properties:
        properties[prop.name] = prop.value

    if template_step.resourceAction == "upgrade":
        resource_to_send = try_upgrade_with_retries(
            num_retries=3,
            attempt_count=0,
            resource_repo=resource_repo,
            resource_template_repo=resource_template_repo,
            properties=properties,
            user=user,
            resource_to_update_id=resource_to_update_id
        )

        return resource_to_send

    else:
        raise Exception("Only upgrade is currently supported for pipeline steps")
Ejemplo n.º 7
0
async def send_custom_action_message(
        resource: Resource,
        resource_repo: ResourceRepository,
        custom_action: str,
        resource_type: ResourceType,
        operations_repo: OperationRepository,
        resource_template_repo: ResourceTemplateRepository,
        user: User,
        parent_service_name: str = None) -> Operation:

    # Validate that the custom_action specified is present in the resource template
    resource_template = resource_template_repo.get_template_by_name_and_version(
        resource.templateName,
        resource.templateVersion,
        resource_type,
        parent_service_name=parent_service_name)
    if not resource_template.customActions:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail=strings.CUSTOM_ACTIONS_DO_NOT_EXIST)
    elif not any(action.name == custom_action
                 for action in resource_template.customActions):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail=strings.CUSTOM_ACTION_NOT_DEFINED)

    try:
        operation = await send_resource_request_message(
            resource=resource,
            operations_repo=operations_repo,
            resource_repo=resource_repo,
            user=user,
            resource_template=resource_template,
            resource_template_repo=resource_template_repo,
            action=custom_action)
        return operation
    except Exception as e:
        logging.error(
            f"Failed to send {resource_type} resource custom action message: {e}"
        )
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                            detail=strings.SERVICE_BUS_GENERAL_ERROR_MESSAGE)
Ejemplo n.º 8
0
async def receive_message_and_update_deployment(app) -> None:
    """
    Receives messages from the deployment status update queue and updates the status for
    the associated resource in the state store.
    Args:
        app ([FastAPI]): Handle to the currently running app
    """
    receive_message_gen = receive_message()

    try:
        async for message in receive_message_gen:
            operations_repo = OperationRepository(get_db_client(app))
            resource_repo = ResourceRepository(get_db_client(app))
            resource_template_repo = ResourceTemplateRepository(
                get_db_client(app))
            result = await update_status_in_database(resource_repo,
                                                     operations_repo,
                                                     resource_template_repo,
                                                     message)
            await receive_message_gen.asend(result)
    except StopAsyncIteration:  # the async generator when finished signals end with this exception.
        pass
def resource_template_repo():
    with patch('azure.cosmos.CosmosClient') as cosmos_client_mock:
        yield ResourceTemplateRepository(cosmos_client_mock)
Ejemplo n.º 10
0
 def _get_enriched_template(self, template_name: str, resource_type: ResourceType, parent_template_name: str = "") -> dict:
     template_repo = ResourceTemplateRepository(self._client)
     template = template_repo.get_current_template(template_name, resource_type, parent_template_name)
     return template_repo.enrich_template(template)
Ejemplo n.º 11
0
 def patch_user_resource(self, user_resource: UserResource, user_resource_patch: ResourcePatch, etag: str, resource_template_repo: ResourceTemplateRepository, parent_template_name: str, user: User) -> Tuple[UserResource, ResourceTemplate]:
     # get user resource template
     user_resource_template = resource_template_repo.get_template_by_name_and_version(user_resource.templateName, user_resource.templateVersion, ResourceType.UserResource, parent_service_name=parent_template_name)
     return self.patch_resource(user_resource, user_resource_patch, user_resource_template, etag, resource_template_repo, user)