Skip to content

Commit

Permalink
Extract an interface for landing zone service operations so we can be…
Browse files Browse the repository at this point in the history
…gin to migrate over to the de-amalgamated LZS HTTP service
  • Loading branch information
aherbst-broad committed Apr 16, 2024
1 parent ad2bfc8 commit 191cf42
Show file tree
Hide file tree
Showing 6 changed files with 429 additions and 185 deletions.
3 changes: 2 additions & 1 deletion service/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ dependencies {
implementation group: 'bio.terra', name: 'terra-cloud-resource-lib', version: "1.2.30-SNAPSHOT"

// Terra Landing Zone Service
implementation ('bio.terra:terra-landing-zone-service:0.0.317-SNAPSHOT')
implementation ('bio.terra:terra-landing-zone-service:0.0.319-SNAPSHOT')
implementation ('bio.terra:landing-zone-service-client:0.0.319-SNAPSHOT')

// Storage transfer service
implementation group: 'com.google.apis', name: 'google-api-services-storagetransfer', version: 'v1-rev20230831-2.0.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Amalgam Package

_NOTE_: This is a deprecated pattern and should not be used going forward.

Amalgam (noun) _a mixture or blend._

The WSM service app is configured to contain other Terra components. There are two reasons why we want to do this:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package bio.terra.workspace.amalgam.landingzone.azure;

import bio.terra.common.exception.ConflictException;
import bio.terra.common.iam.BearerToken;
import bio.terra.landingzone.library.landingzones.deployment.LandingZonePurpose;
import bio.terra.landingzone.service.landingzone.azure.LandingZoneService;
import bio.terra.landingzone.service.landingzone.azure.model.LandingZone;
import bio.terra.landingzone.service.landingzone.azure.model.LandingZoneRequest;
import bio.terra.workspace.common.utils.MapperUtils;
import bio.terra.workspace.generated.model.ApiAzureLandingZone;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneDefinition;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneDefinitionList;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneList;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneParameter;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneResourcesList;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneResourcesPurposeGroup;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneResult;
import bio.terra.workspace.generated.model.ApiCreateLandingZoneResult;
import bio.terra.workspace.generated.model.ApiDeleteAzureLandingZoneJobResult;
import bio.terra.workspace.generated.model.ApiDeleteAzureLandingZoneResult;
import bio.terra.workspace.generated.model.ApiResourceQuota;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* This is the "amalgamated" implementation of our landing zone service layer. It makes calls
* directly to the landing zone library rather than via an HTTP API. NOTE: This is a legacy class
* intended to ease the transition to the newer HTTP LZS service.
*/
@Deprecated
@Component
public class AmalgamatedLandingZoneService implements WorkspaceLandingZoneService {

private final LandingApiClientTypeAdapter typeAdapter;
private final LandingZoneService landingZoneService;

@Autowired
public AmalgamatedLandingZoneService(LandingZoneService landingZoneService) {
this.landingZoneService = landingZoneService;
this.typeAdapter = new LandingApiClientTypeAdapter();
}

@Override
public ApiCreateLandingZoneResult startLandingZoneCreationJob(
BearerToken bearerToken,
String jobId,
UUID landingZoneId,
String definition,
String version,
List<ApiAzureLandingZoneParameter> parameters,
UUID billingProfileId,
String asyncResultEndpoint) {

LandingZoneRequest landingZoneRequest =
LandingZoneRequest.builder()
.landingZoneId(landingZoneId)
.definition(definition)
.version(version)
.parameters(MapperUtils.LandingZoneMapper.landingZoneParametersFrom(parameters))
.billingProfileId(billingProfileId)
.build();
var result =
landingZoneService.startLandingZoneCreationJob(
bearerToken, jobId, landingZoneRequest, asyncResultEndpoint);

return typeAdapter.toApiCreateLandingZoneResult(result);
}

@Override
public ApiDeleteAzureLandingZoneResult startLandingZoneDeletionJob(
BearerToken bearerToken, String jobId, UUID landingZoneId, String resultEndpoint) {
var result =
landingZoneService.startLandingZoneDeletionJob(
bearerToken, jobId, landingZoneId, resultEndpoint);
return typeAdapter.toApiDeleteAzureLandingZoneResult(result);
}

@Override
public ApiDeleteAzureLandingZoneJobResult getDeleteLandingZoneResult(
BearerToken bearerToken, UUID landingZoneId, String jobId) {
var response = landingZoneService.getAsyncDeletionJobResult(bearerToken, landingZoneId, jobId);
return typeAdapter.toApiDeleteAzureLandingZoneJobResult(response);
}

@Override
public ApiAzureLandingZoneResult getAsyncJobResult(BearerToken bearerToken, String jobId) {
var response = landingZoneService.getAsyncJobResult(bearerToken, jobId);
return typeAdapter.toApiAzureLandingZoneResult(response);
}

@Override
public ApiAzureLandingZone getAzureLandingZone(BearerToken bearerToken, UUID landingZoneId) {
LandingZone landingZoneRecord = landingZoneService.getLandingZone(bearerToken, landingZoneId);
return typeAdapter.toApiAzureLandingZone(landingZoneRecord);
}

@Override
public ApiAzureLandingZoneList listLandingZonesByBillingProfile(
BearerToken bearerToken, UUID billingProfileId) {
ApiAzureLandingZoneList result = new ApiAzureLandingZoneList();
List<LandingZone> landingZones =
landingZoneService.getLandingZonesByBillingProfile(bearerToken, billingProfileId);
if (landingZones.size() > 0) {
// The enforced logic is 1:1 relation between Billing Profile and a Landing Zone.
// The landing zone service returns one record in the list if landing zone exists
// for a given billing profile.
if (landingZones.size() == 1) {
result.addLandingzonesItem(typeAdapter.toApiAzureLandingZone(landingZones.get(0)));
} else {
throw new ConflictException(
String.format(
"There are more than one landing zone found for the given billing profile: '%s'. Please"
+ " check the landing zone deployment is correct.",
billingProfileId));
}
}
return result;
}

@Override
public ApiAzureLandingZoneList listLandingZones(BearerToken bearerToken) {
List<LandingZone> landingZones = landingZoneService.listLandingZones(bearerToken);
return new ApiAzureLandingZoneList()
.landingzones(
landingZones.stream()
.map(typeAdapter::toApiAzureLandingZone)
.collect(Collectors.toList()));
}

@Override
public String getLandingZoneRegion(BearerToken bearerToken, UUID landingZoneId) {
return landingZoneService.getLandingZoneRegion(bearerToken, landingZoneId);
}

@Override
public ApiAzureLandingZoneDefinitionList listLandingZoneDefinitions(BearerToken bearerToken) {
var templates = landingZoneService.listLandingZoneDefinitions(bearerToken);
return new ApiAzureLandingZoneDefinitionList()
.landingzones(
templates.stream()
.map(
t ->
new ApiAzureLandingZoneDefinition()
.definition(t.definition())
.name(t.name())
.description(t.description())
.version(t.version()))
.collect(Collectors.toList()));
}

@Override
public ApiAzureLandingZoneResourcesList listResourcesWithPurposes(
BearerToken bearerToken, UUID landingZoneId) {
var result = new ApiAzureLandingZoneResourcesList().id(landingZoneId);
landingZoneService
.listResourcesWithPurposes(bearerToken, landingZoneId)
.deployedResources()
.forEach(
(p, dp) ->
result.addResourcesItem(
new ApiAzureLandingZoneResourcesPurposeGroup()
.purpose(p.toString())
.deployedResources(
dp.stream()
.map(r -> typeAdapter.toApiAzureLandingZoneDeployedResource(r, p))
.toList())));

return result;
}

@Override
public ApiAzureLandingZoneResourcesList listResourcesMatchingPurpose(
BearerToken bearerToken, UUID landingZoneId, LandingZonePurpose resourcePurpose) {
var result = new ApiAzureLandingZoneResourcesList().id(landingZoneId);
var deployedResources =
landingZoneService
.listResourcesByPurpose(bearerToken, landingZoneId, resourcePurpose)
.stream()
.map(r -> typeAdapter.toApiAzureLandingZoneDeployedResource(r, resourcePurpose))
.toList();
result.addResourcesItem(
new ApiAzureLandingZoneResourcesPurposeGroup()
.purpose(resourcePurpose.toString())
.deployedResources(deployedResources));
return result;
}

@Override
public ApiResourceQuota getResourceQuota(
BearerToken bearerToken, UUID landingZoneId, String resourceId) {
var response = landingZoneService.getResourceQuota(bearerToken, landingZoneId, resourceId);
return typeAdapter.toApiResourceQuota(landingZoneId, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package bio.terra.workspace.amalgam.landingzone.azure;

import bio.terra.landingzone.job.LandingZoneJobService;
import bio.terra.landingzone.job.model.JobReport;
import bio.terra.landingzone.library.landingzones.deployment.LandingZonePurpose;
import bio.terra.landingzone.library.landingzones.deployment.ResourcePurpose;
import bio.terra.landingzone.library.landingzones.deployment.SubnetResourcePurpose;
import bio.terra.landingzone.library.landingzones.management.quotas.ResourceQuota;
import bio.terra.landingzone.service.landingzone.azure.model.DeletedLandingZone;
import bio.terra.landingzone.service.landingzone.azure.model.DeployedLandingZone;
import bio.terra.landingzone.service.landingzone.azure.model.LandingZone;
import bio.terra.landingzone.service.landingzone.azure.model.LandingZoneResource;
import bio.terra.landingzone.service.landingzone.azure.model.StartLandingZoneCreation;
import bio.terra.landingzone.service.landingzone.azure.model.StartLandingZoneDeletion;
import bio.terra.workspace.common.utils.MapperUtils;
import bio.terra.workspace.generated.model.ApiAzureLandingZone;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneDeployedResource;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneDetails;
import bio.terra.workspace.generated.model.ApiAzureLandingZoneResult;
import bio.terra.workspace.generated.model.ApiCreateLandingZoneResult;
import bio.terra.workspace.generated.model.ApiDeleteAzureLandingZoneJobResult;
import bio.terra.workspace.generated.model.ApiDeleteAzureLandingZoneResult;
import bio.terra.workspace.generated.model.ApiResourceQuota;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
* Utilities for transforming from internal landing zone library types to externally facing API
* types.
*/
public class LandingApiClientTypeAdapter {

public ApiCreateLandingZoneResult toApiCreateLandingZoneResult(
LandingZoneJobService.AsyncJobResult<StartLandingZoneCreation> jobResult) {

return new ApiCreateLandingZoneResult()
.jobReport(MapperUtils.JobReportMapper.from(jobResult.getJobReport()))
.errorReport(MapperUtils.ErrorReportMapper.from(jobResult.getApiErrorReport()))
.landingZoneId(jobResult.getResult().landingZoneId())
.definition(jobResult.getResult().definition())
.version(jobResult.getResult().version());
}

public ApiAzureLandingZone toApiAzureLandingZone(LandingZone landingZone) {
return new ApiAzureLandingZone()
.billingProfileId(landingZone.billingProfileId())
.landingZoneId(landingZone.landingZoneId())
.definition(landingZone.definition())
.version(landingZone.version())
.region(landingZone.region())
.createdDate(landingZone.createdDate());
}

public ApiDeleteAzureLandingZoneResult toApiDeleteAzureLandingZoneResult(
LandingZoneJobService.AsyncJobResult<StartLandingZoneDeletion> jobResult) {
return new ApiDeleteAzureLandingZoneResult()
.jobReport(MapperUtils.JobReportMapper.from(jobResult.getJobReport()))
.errorReport(MapperUtils.ErrorReportMapper.from(jobResult.getApiErrorReport()))
.landingZoneId(jobResult.getResult().landingZoneId());
}

public ApiAzureLandingZoneDeployedResource toApiAzureLandingZoneDeployedResource(
LandingZoneResource resource, LandingZonePurpose purpose) {
if (purpose.getClass().equals(ResourcePurpose.class)) {
return new ApiAzureLandingZoneDeployedResource()
.resourceId(resource.resourceId())
.resourceType(resource.resourceType())
.tags(resource.tags())
.region(resource.region());
}
if (purpose.getClass().equals(SubnetResourcePurpose.class)) {
return new ApiAzureLandingZoneDeployedResource()
.resourceParentId(resource.resourceParentId().orElse(null)) // Only available for subnets
.resourceName(resource.resourceName().orElse(null)) // Only available for subnets
.resourceType(resource.resourceType())
.resourceId(resource.resourceId())
.tags(resource.tags())
.region(resource.region());
}
throw new LandingZoneUnsupportedPurposeException(
String.format(
"Support for purpose type %s is not implemented.", purpose.getClass().getSimpleName()));
}

public ApiDeleteAzureLandingZoneJobResult toApiDeleteAzureLandingZoneJobResult(
LandingZoneJobService.AsyncJobResult<DeletedLandingZone> jobResult) {
var apiJobResult =
new ApiDeleteAzureLandingZoneJobResult()
.jobReport(MapperUtils.JobReportMapper.from(jobResult.getJobReport()))
.errorReport(MapperUtils.ErrorReportMapper.from(jobResult.getApiErrorReport()));

if (jobResult.getJobReport().getStatus().equals(JobReport.StatusEnum.SUCCEEDED)) {
apiJobResult.landingZoneId(jobResult.getResult().landingZoneId());
apiJobResult.resources(jobResult.getResult().deleteResources());
}
return apiJobResult;
}

public ApiResourceQuota toApiResourceQuota(UUID landingZoneId, ResourceQuota resourceQuota) {
return new ApiResourceQuota()
.landingZoneId(landingZoneId)
.azureResourceId(resourceQuota.resourceId())
.resourceType(resourceQuota.resourceType())
.quotaValues(resourceQuota.quota());
}

public ApiAzureLandingZoneResult toApiAzureLandingZoneResult(
LandingZoneJobService.AsyncJobResult<DeployedLandingZone> jobResult) {
ApiAzureLandingZoneDetails azureLandingZone = null;
if (jobResult.getJobReport().getStatus().equals(JobReport.StatusEnum.SUCCEEDED)) {
azureLandingZone =
Optional.ofNullable(jobResult.getResult())
.map(
lz ->
new ApiAzureLandingZoneDetails()
.id(lz.id())
.resources(
lz.deployedResources().stream()
.map(
resource ->
new ApiAzureLandingZoneDeployedResource()
.region(resource.region())
.resourceType(resource.resourceType())
.resourceId(resource.resourceId()))
.collect(Collectors.toList())))
.orElse(null);
}

return new ApiAzureLandingZoneResult()
.jobReport(MapperUtils.JobReportMapper.from(jobResult.getJobReport()))
.errorReport(MapperUtils.ErrorReportMapper.from(jobResult.getApiErrorReport()))
.landingZone(azureLandingZone);
}
}
Loading

0 comments on commit 191cf42

Please sign in to comment.