Search in sources :

Example 1 with GcpCloudContext

use of bio.terra.workspace.service.workspace.model.GcpCloudContext in project terra-workspace-manager by DataBiosphere.

the class CreateGcpContextFlightV2Test method successCreatesProjectAndContext.

@Test
@DisabledIfEnvironmentVariable(named = "TEST_ENV", matches = BUFFER_SERVICE_DISABLED_ENVS_REG_EX)
void successCreatesProjectAndContext() throws Exception {
    UUID workspaceId = createWorkspace(spendUtils.defaultSpendId());
    AuthenticatedUserRequest userRequest = userAccessUtils.defaultUserAuthRequest();
    assertTrue(testUtils.getAuthorizedGcpCloudContext(workspaceId, userRequest).isEmpty());
    // Retry steps once to validate idempotency.
    Map<String, StepStatus> retrySteps = getStepNameToStepStatusMap();
    FlightDebugInfo debugInfo = FlightDebugInfo.newBuilder().doStepFailures(retrySteps).build();
    FlightState flightState = StairwayTestUtils.blockUntilFlightCompletes(jobService.getStairway(), CreateGcpContextFlightV2.class, createInputParameters(workspaceId, userRequest), STAIRWAY_FLIGHT_TIMEOUT, debugInfo);
    assertEquals(FlightStatus.SUCCESS, flightState.getFlightStatus());
    String projectId = flightState.getResultMap().get().get(WorkspaceFlightMapKeys.GCP_PROJECT_ID, String.class);
    assertTrue(testUtils.getAuthorizedGcpCloudContext(workspaceId, userRequest).isPresent());
    String contextProjectId = workspaceService.getAuthorizedRequiredGcpProject(workspaceId, userRequest);
    assertEquals(projectId, contextProjectId);
    // Verify that the policies were properly stored
    Optional<GcpCloudContext> optionalCloudContext = testUtils.getAuthorizedGcpCloudContext(workspaceId, userRequest);
    assertTrue(optionalCloudContext.isPresent(), "has cloud context");
    GcpCloudContext cloudContext = optionalCloudContext.get();
    assertTrue(cloudContext.getSamPolicyOwner().isPresent(), "has owner policy");
    assertTrue(cloudContext.getSamPolicyWriter().isPresent(), "has writer policy");
    assertTrue(cloudContext.getSamPolicyReader().isPresent(), "has reader policy");
    assertTrue(cloudContext.getSamPolicyApplication().isPresent(), "has application policy");
    Project project = crl.getCloudResourceManagerCow().projects().get(projectId).execute();
    assertEquals(projectId, project.getProjectId());
    assertEquals("billingAccounts/" + spendUtils.defaultBillingAccountId(), crl.getCloudBillingClientCow().getProjectBillingInfo("projects/" + projectId).getBillingAccountName());
    assertRolesExist(project);
    assertPolicyGroupsSynced(workspaceId, project);
}
Also used : FlightState(bio.terra.stairway.FlightState) Project(com.google.api.services.cloudresourcemanager.v3.model.Project) FlightDebugInfo(bio.terra.stairway.FlightDebugInfo) AuthenticatedUserRequest(bio.terra.workspace.service.iam.AuthenticatedUserRequest) StepStatus(bio.terra.stairway.StepStatus) UUID(java.util.UUID) GcpCloudContext(bio.terra.workspace.service.workspace.model.GcpCloudContext) Test(org.junit.jupiter.api.Test) BaseConnectedTest(bio.terra.workspace.common.BaseConnectedTest) DisabledIfEnvironmentVariable(org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable)

Example 2 with GcpCloudContext

use of bio.terra.workspace.service.workspace.model.GcpCloudContext in project terra-workspace-manager by DataBiosphere.

the class RemoveUserFromWorkspaceFlightTest method removeUserFromWorkspaceFlightDoUndo.

@Test
@DisabledIfEnvironmentVariable(named = "TEST_ENV", matches = BUFFER_SERVICE_DISABLED_ENVS_REG_EX)
void removeUserFromWorkspaceFlightDoUndo() throws Exception {
    // Create a workspace as the default test user
    Workspace request = Workspace.builder().workspaceId(UUID.randomUUID()).workspaceStage(WorkspaceStage.MC_WORKSPACE).spendProfileId(spendUtils.defaultSpendId()).build();
    UUID workspaceId = workspaceService.createWorkspace(request, userAccessUtils.defaultUserAuthRequest());
    // Add the secondary test user as a writer
    samService.grantWorkspaceRole(workspaceId, userAccessUtils.defaultUserAuthRequest(), WsmIamRole.WRITER, userAccessUtils.getSecondUserEmail());
    samService.dumpRoleBindings(SamResource.WORKSPACE, workspaceId.toString(), userAccessUtils.defaultUserAuthRequest().getRequiredToken());
    // Create a GCP context as default user
    String makeContextJobId = UUID.randomUUID().toString();
    workspaceService.createGcpCloudContext(workspaceId, makeContextJobId, userAccessUtils.defaultUserAuthRequest());
    jobService.waitForJob(makeContextJobId);
    AsyncJobResult<CloudContextHolder> createContextJobResult = jobService.retrieveAsyncJobResult(makeContextJobId, CloudContextHolder.class, userAccessUtils.defaultUserAuthRequest());
    assertEquals(StatusEnum.SUCCEEDED, createContextJobResult.getJobReport().getStatus());
    GcpCloudContext cloudContext = createContextJobResult.getResult().getGcpCloudContext();
    // Create a private dataset for secondary user
    String datasetId = RandomStringUtils.randomAlphabetic(8);
    ControlledBigQueryDatasetResource privateDataset = buildPrivateDataset(workspaceId, datasetId, cloudContext.getGcpProjectId());
    assertNotNull(privateDataset);
    // Validate with Sam that secondary user can read their private resource
    assertTrue(samService.isAuthorized(userAccessUtils.secondUserAuthRequest(), privateDataset.getCategory().getSamResourceName(), privateDataset.getResourceId().toString(), SamControlledResourceActions.WRITE_ACTION));
    // Run the "removeUser" flight to the very end, then undo it, retrying steps along the way.
    Map<String, StepStatus> retrySteps = new HashMap<>();
    retrySteps.put(RemoveUserFromSamStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(CheckUserStillInWorkspaceStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(ClaimUserPrivateResourcesStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(RemovePrivateResourceAccessStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(MarkPrivateResourcesAbandonedStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(RevokePetUsagePermissionStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    retrySteps.put(ReleasePrivateResourceCleanupClaimsStep.class.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY);
    FlightDebugInfo failingDebugInfo = FlightDebugInfo.newBuilder().undoStepFailures(retrySteps).lastStepFailure(true).build();
    FlightMap inputParameters = new FlightMap();
    inputParameters.put(WorkspaceFlightMapKeys.WORKSPACE_ID, workspaceId.toString());
    inputParameters.put(WorkspaceFlightMapKeys.USER_TO_REMOVE, userAccessUtils.getSecondUserEmail());
    inputParameters.put(WorkspaceFlightMapKeys.ROLE_TO_REMOVE, ControlledResourceIamRole.WRITER.name());
    // Auth info comes from default user, as they are the ones "making this request"
    inputParameters.put(JobMapKeys.AUTH_USER_INFO.getKeyName(), userAccessUtils.defaultUserAuthRequest());
    FlightState flightState = StairwayTestUtils.blockUntilFlightCompletes(jobService.getStairway(), RemoveUserFromWorkspaceFlight.class, inputParameters, STAIRWAY_FLIGHT_TIMEOUT, failingDebugInfo);
    assertEquals(FlightStatus.ERROR, flightState.getFlightStatus());
    // Validate that secondary user is still a workspace writer and can still read their private
    // resource.
    assertTrue(samService.isAuthorized(userAccessUtils.secondUserAuthRequest(), SamResource.WORKSPACE, workspaceId.toString(), SamWorkspaceAction.WRITE));
    assertTrue(samService.isAuthorized(userAccessUtils.secondUserAuthRequest(), privateDataset.getCategory().getSamResourceName(), privateDataset.getResourceId().toString(), SamControlledResourceActions.WRITE_ACTION));
    // Run the flight again, this time to success. Retry each do step once.
    FlightDebugInfo passingDebugInfo = FlightDebugInfo.newBuilder().doStepFailures(retrySteps).build();
    FlightState passingFlightState = StairwayTestUtils.blockUntilFlightCompletes(jobService.getStairway(), RemoveUserFromWorkspaceFlight.class, inputParameters, STAIRWAY_FLIGHT_TIMEOUT, passingDebugInfo);
    assertEquals(FlightStatus.SUCCESS, passingFlightState.getFlightStatus());
    // Verify the secondary user can no longer access the workspace or their private resource
    assertFalse(samService.isAuthorized(userAccessUtils.secondUserAuthRequest(), SamResource.WORKSPACE, workspaceId.toString(), SamWorkspaceAction.WRITE));
    assertFalse(samService.isAuthorized(userAccessUtils.secondUserAuthRequest(), privateDataset.getCategory().getSamResourceName(), privateDataset.getResourceId().toString(), SamControlledResourceActions.WRITE_ACTION));
    // Cleanup
    workspaceService.deleteWorkspace(workspaceId, userAccessUtils.defaultUserAuthRequest());
}
Also used : FlightDebugInfo(bio.terra.stairway.FlightDebugInfo) HashMap(java.util.HashMap) StepStatus(bio.terra.stairway.StepStatus) CloudContextHolder(bio.terra.workspace.service.workspace.model.CloudContextHolder) FlightState(bio.terra.stairway.FlightState) FlightMap(bio.terra.stairway.FlightMap) UUID(java.util.UUID) ControlledBigQueryDatasetResource(bio.terra.workspace.service.resource.controlled.cloud.gcp.bqdataset.ControlledBigQueryDatasetResource) GcpCloudContext(bio.terra.workspace.service.workspace.model.GcpCloudContext) Workspace(bio.terra.workspace.service.workspace.model.Workspace) BaseConnectedTest(bio.terra.workspace.common.BaseConnectedTest) Test(org.junit.jupiter.api.Test) DisabledIfEnvironmentVariable(org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable)

Example 3 with GcpCloudContext

use of bio.terra.workspace.service.workspace.model.GcpCloudContext in project terra-workspace-manager by DataBiosphere.

the class DeleteBigQueryDatasetStep method doStep.

@Override
public StepResult doStep(FlightContext flightContext) throws InterruptedException, RetryException {
    final GcpCloudContext gcpCloudContext = flightContext.getWorkingMap().get(ControlledResourceKeys.GCP_CLOUD_CONTEXT, GcpCloudContext.class);
    String projectId = gcpCloudContext.getGcpProjectId();
    BigQueryCow bqCow = crlService.createWsmSaBigQueryCow();
    try {
        // With deleteContents set to true, this will delete the dataset even if it still has tables.
        bqCow.datasets().delete(projectId, resource.getDatasetName()).setDeleteContents(true).execute();
    } catch (GoogleJsonResponseException e) {
        if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
            logger.info("BQ dataset {} in project {} already deleted", resource.getDatasetName(), projectId);
            return StepResult.getStepResultSuccess();
        }
        return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
    } catch (IOException e) {
        return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
    }
    return StepResult.getStepResultSuccess();
}
Also used : GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) IOException(java.io.IOException) StepResult(bio.terra.stairway.StepResult) BigQueryCow(bio.terra.cloudres.google.bigquery.BigQueryCow) GcpCloudContext(bio.terra.workspace.service.workspace.model.GcpCloudContext)

Example 4 with GcpCloudContext

use of bio.terra.workspace.service.workspace.model.GcpCloudContext in project terra-workspace-manager by DataBiosphere.

the class NotebookCloudSyncStep method doStep.

@Override
public StepResult doStep(FlightContext flightContext) throws InterruptedException, RetryException {
    FlightMap workingMap = flightContext.getWorkingMap();
    FlightUtils.validateRequiredEntries(workingMap, ControlledResourceKeys.GCP_CLOUD_CONTEXT);
    GcpCloudContext cloudContext = workingMap.get(ControlledResourceKeys.GCP_CLOUD_CONTEXT, GcpCloudContext.class);
    List<Binding> newBindings = createBindings(cloudContext, flightContext.getWorkingMap());
    AIPlatformNotebooksCow notebooks = crlService.getAIPlatformNotebooksCow();
    InstanceName instanceName = resource.toInstanceName(cloudContext.getGcpProjectId());
    try {
        Policy policy = notebooks.instances().getIamPolicy(instanceName).execute();
        // Duplicating bindings is harmless (e.g. on retry). GCP de-duplicates.
        Optional.ofNullable(policy.getBindings()).ifPresent(newBindings::addAll);
        policy.setBindings(newBindings);
        notebooks.instances().setIamPolicy(instanceName, new SetIamPolicyRequest().setPolicy(policy)).execute();
    } catch (IOException e) {
        return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
    }
    return StepResult.getStepResultSuccess();
}
Also used : Binding(com.google.api.services.notebooks.v1.model.Binding) InstanceName(bio.terra.cloudres.google.notebooks.InstanceName) Policy(com.google.api.services.notebooks.v1.model.Policy) AIPlatformNotebooksCow(bio.terra.cloudres.google.notebooks.AIPlatformNotebooksCow) SetIamPolicyRequest(com.google.api.services.notebooks.v1.model.SetIamPolicyRequest) FlightMap(bio.terra.stairway.FlightMap) IOException(java.io.IOException) StepResult(bio.terra.stairway.StepResult) GcpCloudContext(bio.terra.workspace.service.workspace.model.GcpCloudContext)

Example 5 with GcpCloudContext

use of bio.terra.workspace.service.workspace.model.GcpCloudContext in project terra-workspace-manager by DataBiosphere.

the class GetCloudContextStep method doStep.

@Override
public StepResult doStep(FlightContext flightContext) throws InterruptedException, RetryException {
    // Get the cloud context and store it in the working map
    switch(cloudPlatform) {
        case AZURE:
            AzureCloudContext azureCloudContext = azureCloudContextService.getRequiredAzureCloudContext(workspaceId);
            flightContext.getWorkingMap().put(ControlledResourceKeys.AZURE_CLOUD_CONTEXT, azureCloudContext);
            break;
        case GCP:
            GcpCloudContext gcpCloudContext = gcpCloudContextService.getRequiredGcpCloudContext(workspaceId, userRequest);
            flightContext.getWorkingMap().put(ControlledResourceKeys.GCP_CLOUD_CONTEXT, gcpCloudContext);
            break;
        case ANY:
        default:
            // There cannot be an ANY resource that is also a controlled resource.
            throw new InternalLogicException("Invalid cloud platform for controlled resource: " + cloudPlatform);
    }
    return StepResult.getStepResultSuccess();
}
Also used : InternalLogicException(bio.terra.workspace.common.exception.InternalLogicException) AzureCloudContext(bio.terra.workspace.service.workspace.model.AzureCloudContext) GcpCloudContext(bio.terra.workspace.service.workspace.model.GcpCloudContext)

Aggregations

GcpCloudContext (bio.terra.workspace.service.workspace.model.GcpCloudContext)21 StepResult (bio.terra.stairway.StepResult)9 IOException (java.io.IOException)7 FlightMap (bio.terra.stairway.FlightMap)5 Test (org.junit.jupiter.api.Test)5 AIPlatformNotebooksCow (bio.terra.cloudres.google.notebooks.AIPlatformNotebooksCow)4 InstanceName (bio.terra.cloudres.google.notebooks.InstanceName)4 GoogleJsonResponseException (com.google.api.client.googleapis.json.GoogleJsonResponseException)4 UUID (java.util.UUID)4 BaseUnitTest (bio.terra.workspace.common.BaseUnitTest)3 Workspace (bio.terra.workspace.service.workspace.model.Workspace)3 Operation (com.google.api.services.notebooks.v1.model.Operation)3 BigQueryCow (bio.terra.cloudres.google.bigquery.BigQueryCow)2 StorageCow (bio.terra.cloudres.google.storage.StorageCow)2 FlightDebugInfo (bio.terra.stairway.FlightDebugInfo)2 FlightState (bio.terra.stairway.FlightState)2 StepStatus (bio.terra.stairway.StepStatus)2 BaseConnectedTest (bio.terra.workspace.common.BaseConnectedTest)2 CloudContextHolder (bio.terra.workspace.service.workspace.model.CloudContextHolder)2 DisabledIfEnvironmentVariable (org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable)2