diff --git a/CHANGELOG.md b/CHANGELOG.md index 236f0e2055..aeda6dc9fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,8 @@ ENHANCEMENTS: * Update Terraform to use Azure AD authentication rather than storage account keys ([#4103](https://github.com/microsoft/AzureTRE/issues/4103)) BUG FIXES: -- Update KeyVault references in API to use the version so Terraform cascades the update ([#4112](https://github.com/microsoft/AzureTRE/pull/4112)) +* Update KeyVault references in API to use the version so Terraform cascades the update ([#4112](https://github.com/microsoft/AzureTRE/pull/4112)) +* Amend session ID to prevent parallel operations on a resource. ([#3807](https://github.com/microsoft/AzureTRE/pull/3807)) COMPONENTS: diff --git a/api_app/_version.py b/api_app/_version.py index 1a95d56216..8261536c68 100644 --- a/api_app/_version.py +++ b/api_app/_version.py @@ -1 +1 @@ -__version__ = "0.19.3" +__version__ = "0.19.4" diff --git a/api_app/service_bus/deployment_status_updater.py b/api_app/service_bus/deployment_status_updater.py index 4bac477754..b1a892152e 100644 --- a/api_app/service_bus/deployment_status_updater.py +++ b/api_app/service_bus/deployment_status_updater.py @@ -168,7 +168,7 @@ async def update_status_in_database(self, message: DeploymentStatusUpdateMessage # create + send the message logger.info(f"Sending next step in operation to deployment queue -> step_id: {next_step.templateStepId}, action: {next_step.resourceAction}") content = json.dumps(resource_to_send.get_resource_request_message_payload(operation_id=operation.id, step_id=next_step.id, action=next_step.resourceAction)) - await send_deployment_message(content=content, correlation_id=operation.id, session_id=resource_to_send.id, action=next_step.resourceAction) + await send_deployment_message(content=content, correlation_id=operation.id, resource=resource_to_send, action=next_step.resourceAction) except Exception as e: logger.exception("Unable to send update for resource in pipeline step") next_step.message = repr(e) diff --git a/api_app/service_bus/helpers.py b/api_app/service_bus/helpers.py index 77f7127999..e966ce54a3 100644 --- a/api_app/service_bus/helpers.py +++ b/api_app/service_bus/helpers.py @@ -34,7 +34,16 @@ async def _send_message(message: ServiceBusMessage, queue: str): await sender.send_messages(message) -async def send_deployment_message(content, correlation_id, session_id, action): +async def send_deployment_message(content, correlation_id, resource, action): + + # use session id to prevent likelihood of conflicts when sending multiple messages for the same resource + if resource.resourceType == ResourceType.WorkspaceService: + session_id = resource.workspaceId + elif resource.resourceType == ResourceType.UserResource: + session_id = resource.parentWorkspaceServiceId + else: + session_id = resource.id + resource_request_message = ServiceBusMessage(body=content, correlation_id=correlation_id, session_id=session_id) logger.info(f"Sending resource request message with correlation ID {resource_request_message.correlation_id}, action: {action}") await _send_message(resource_request_message, config.SERVICE_BUS_RESOURCE_REQUEST_QUEUE) @@ -42,7 +51,7 @@ async def send_deployment_message(content, correlation_id, session_id, action): async def update_resource_for_step(operation_step: OperationStep, resource_repo: ResourceRepository, resource_template_repo: ResourceTemplateRepository, resource_history_repo: ResourceHistoryRepository, root_resource: Resource, step_resource: Resource, resource_to_update_id: str, primary_action: str, user: User) -> Resource: # step_resource is the resource instance where the step was defined. e.g. 'add firewall rule' step defined in Guacamole template -> the step_resource is the Guacamole ws service. - # root_resource is theresource on which the user chose to update, i.e. the top most resource in cascaded action or the same resource in a non-cascaded action. + # root_resource is the resource on which the user chose to update, i.e. the top most resource in cascaded action or the same resource in a non-cascaded action. if step_resource is None: step_resource = await resource_repo.get_resource_by_id(operation_step.sourceTemplateResourceId) diff --git a/api_app/service_bus/resource_request_sender.py b/api_app/service_bus/resource_request_sender.py index e5fe83ba84..c89651e1fd 100644 --- a/api_app/service_bus/resource_request_sender.py +++ b/api_app/service_bus/resource_request_sender.py @@ -62,6 +62,6 @@ async def send_resource_request_message(resource: Resource, operations_repo: Ope # create + send the message content = json.dumps(resource_to_send.get_resource_request_message_payload(operation_id=operation.id, step_id=first_step.id, action=first_step.resourceAction)) - await send_deployment_message(content=content, correlation_id=operation.id, session_id=first_step.resourceId, action=first_step.resourceAction) + await send_deployment_message(content=content, correlation_id=operation.id, resource=resource_to_send, action=first_step.resourceAction) return operation diff --git a/api_app/tests_ma/test_api/test_routes/test_resource_helpers.py b/api_app/tests_ma/test_api/test_routes/test_resource_helpers.py index 31fb31e5f1..d216911e55 100644 --- a/api_app/tests_ma/test_api/test_routes/test_resource_helpers.py +++ b/api_app/tests_ma/test_api/test_routes/test_resource_helpers.py @@ -294,7 +294,7 @@ async def test_save_and_deploy_masks_secrets(self, send_deployment_message_mock, send_deployment_message_mock.assert_called_once_with( content=json.dumps(resource.get_resource_request_message_payload(operation_id=operation_id, step_id=step_id, action="install")), correlation_id=operation_id, - session_id=resource.id, + resource=resource, action="install") # Checking that the item saved had a secret redacted diff --git a/templates/workspace_services/databricks/porter.yaml b/templates/workspace_services/databricks/porter.yaml index 5c6ac9b030..231527e043 100644 --- a/templates/workspace_services/databricks/porter.yaml +++ b/templates/workspace_services/databricks/porter.yaml @@ -29,6 +29,7 @@ parameters: type: string - name: is_exposed_externally type: boolean + default: false - name: tfstate_resource_group_name type: string description: "Resource group containing the Terraform state storage account" @@ -100,6 +101,11 @@ outputs: applyTo: - install - upgrade + - name: is_exposed_externally + type: boolean + applyTo: + - install + - upgrade mixins: - terraform: @@ -133,6 +139,7 @@ install: - name: artifact_blob_storage_domains - name: workspace_address_spaces - name: databricks_address_prefixes + - name: is_exposed_externally upgrade: - terraform: @@ -162,6 +169,7 @@ upgrade: - name: artifact_blob_storage_domains - name: workspace_address_spaces - name: databricks_address_prefixes + - name: is_exposed_externally uninstall: - terraform: diff --git a/templates/workspace_services/databricks/terraform/outputs.tf b/templates/workspace_services/databricks/terraform/outputs.tf index 800dd1f743..f814be441f 100644 --- a/templates/workspace_services/databricks/terraform/outputs.tf +++ b/templates/workspace_services/databricks/terraform/outputs.tf @@ -49,3 +49,7 @@ data "dns_a_record_set" "event_hub_endpoint_addresses" { output "event_hub_endpoint_addresses" { value = setunion(flatten([for addr in data.dns_a_record_set.event_hub_endpoint_addresses : addr.addrs])) } + +output "is_exposed_externally" { + value = var.is_exposed_externally +}