Search in sources :

Example 6 with FlightState

use of bio.terra.stairway.FlightState in project terra-workspace-manager by DataBiosphere.

the class CreateGcpContextFlightTest 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(), CreateGcpContextFlight.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);
    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) Test(org.junit.jupiter.api.Test) BaseConnectedTest(bio.terra.workspace.common.BaseConnectedTest) DisabledIfEnvironmentVariable(org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable)

Example 7 with FlightState

use of bio.terra.stairway.FlightState in project terra-workspace-manager by DataBiosphere.

the class StairwayTestUtils method enumerateJobsDump.

public static void enumerateJobsDump(Alpha1Service alpha1Service, UUID workspaceUuid, AuthenticatedUserRequest userRequest) {
    EnumeratedJobs jobs = alpha1Service.enumerateJobs(workspaceUuid, userRequest, 1000, null, null, null, null, null);
    System.out.printf("Enumerated Jobs: total=%d, pageToken=%s%n", jobs.getTotalResults(), jobs.getPageToken());
    for (EnumeratedJob job : jobs.getResults()) {
        FlightState flightState = job.getFlightState();
        System.out.printf("  Job %s %s%n", flightState.getFlightId(), flightState.getFlightStatus());
        System.out.printf("    description: %s%n", job.getJobDescription());
        System.out.printf("    submitted  : %s%n", flightState.getSubmitted());
        System.out.printf("    completed  : %s%n", flightState.getCompleted().map(Instant::toString).orElse("<incomplete>"));
        if (flightState.getException().isPresent()) {
            System.out.printf("   error       : %s%n", flightState.getException().get().getMessage());
        }
        System.out.printf("    operation : %s%n", job.getOperationType());
        if (job.getResource().isPresent()) {
            WsmResource resource = job.getResource().get();
            System.out.println("    resource:");
            System.out.printf("      name: %s%n", resource.getName());
            System.out.printf("      id  : %s%n", resource.getResourceId());
            System.out.printf("      desc: %s%n", resource.getDescription());
            System.out.printf("      stew: %s%n", resource.getStewardshipType());
            System.out.printf("      type: %s%n", resource.getResourceType());
        }
    }
}
Also used : FlightState(bio.terra.stairway.FlightState) WsmResource(bio.terra.workspace.service.resource.model.WsmResource) Instant(java.time.Instant) EnumeratedJobs(bio.terra.workspace.service.workspace.model.EnumeratedJobs) EnumeratedJob(bio.terra.workspace.service.workspace.model.EnumeratedJob)

Example 8 with FlightState

use of bio.terra.stairway.FlightState in project terra-workspace-manager by DataBiosphere.

the class ControlledResourceService method waitForResourceOrJob.

/**
 * For async resource creation, we do not want to return to the caller until the resource row is
 * in the database and, thus, visible to enumeration. This method waits for either the row to show
 * up (the expected success case) or the job to complete (the expected error case). If one of
 * those doesn't happen in the retry window, we throw SERVICE_UNAVAILABLE. The theory is for it
 * not to complete, either WSM is so busy that it cannot schedule the flight or something bad has
 * happened. Either way, SERVICE_UNAVAILABLE seems like a reasonable response.
 *
 * <p>There is no race condition between the two checks. For either termination test, we will make
 * the async return to the client. That path returns the current job state. If the job is
 * complete, the client calls the result endpoint and gets the full result.
 *
 * @param workspaceUuid workspace of the resource create
 * @param resourceId id of resource being created
 * @param jobId id of the create flight.
 */
private void waitForResourceOrJob(UUID workspaceUuid, UUID resourceId, String jobId) {
    Instant exitTime = Instant.now().plus(RESOURCE_ROW_MAX_WAIT_TIME);
    try {
        while (Instant.now().isBefore(exitTime)) {
            if (resourceDao.resourceExists(workspaceUuid, resourceId)) {
                return;
            }
            FlightState flightState = jobService.getStairway().getFlightState(jobId);
            if (flightState.getCompleted().isPresent()) {
                return;
            }
            TimeUnit.SECONDS.sleep(RESOURCE_ROW_WAIT_SECONDS);
        }
    } catch (InterruptedException e) {
    // fall through to throw
    }
    throw new ServiceUnavailableException("Failed to make prompt progress on resource");
}
Also used : FlightState(bio.terra.stairway.FlightState) Instant(java.time.Instant) ServiceUnavailableException(bio.terra.common.exception.ServiceUnavailableException)

Example 9 with FlightState

use of bio.terra.stairway.FlightState in project terra-workspace-manager by DataBiosphere.

the class AwaitCloneAllResourcesFlightStep method doStep.

@Override
public StepResult doStep(FlightContext context) throws InterruptedException, RetryException {
    validateRequiredEntries(context.getInputParameters(), ControlledResourceKeys.SOURCE_WORKSPACE_ID, JobMapKeys.REQUEST.getKeyName());
    validateRequiredEntries(context.getWorkingMap(), ControlledResourceKeys.CLONE_ALL_RESOURCES_FLIGHT_ID);
    final var cloneAllResourcesFlightId = context.getWorkingMap().get(ControlledResourceKeys.CLONE_ALL_RESOURCES_FLIGHT_ID, String.class);
    final var destinationWorkspace = context.getInputParameters().get(JobMapKeys.REQUEST.getKeyName(), Workspace.class);
    try {
        // noinspection deprecation
        final FlightState subflightState = context.getStairway().waitForFlight(cloneAllResourcesFlightId, FLIGHT_POLL_SECONDS, FLIGHT_POLL_CYCLES);
        if (FlightStatus.SUCCESS != subflightState.getFlightStatus()) {
            // no point in retrying the await step
            return new StepResult(StepStatus.STEP_RESULT_FAILURE_FATAL, subflightState.getException().orElseGet(() -> new RuntimeException(String.format("Subflight had unexpected status %s. No exception for subflight found.", subflightState.getFlightStatus()))));
        }
        final FlightMap subflightResultMap = FlightUtils.getResultMapRequired(subflightState);
        // Build the response object from the resource ID to details map. The map won't have been
        // instantiated if there are no resources in the workspace, so just use an empty map in that
        // case.
        final var resourceIdToDetails = Optional.ofNullable(subflightResultMap.get(ControlledResourceKeys.RESOURCE_ID_TO_CLONE_RESULT, new TypeReference<Map<UUID, WsmResourceCloneDetails>>() {
        })).orElse(Collections.emptyMap());
        final var apiClonedWorkspace = new ApiClonedWorkspace();
        apiClonedWorkspace.setDestinationWorkspaceId(destinationWorkspace.getWorkspaceId());
        final var sourceWorkspaceId = context.getInputParameters().get(ControlledResourceKeys.SOURCE_WORKSPACE_ID, UUID.class);
        apiClonedWorkspace.setSourceWorkspaceId(sourceWorkspaceId);
        final List<ApiResourceCloneDetails> resources = resourceIdToDetails.values().stream().map(WsmResourceCloneDetails::toApiModel).collect(Collectors.toList());
        apiClonedWorkspace.setResources(resources);
        // Set overall response for workspace clone flights
        FlightUtils.setResponse(context, apiClonedWorkspace, HttpStatus.OK);
    } catch (DatabaseOperationException | FlightWaitTimedOutException e) {
        // Retry for database issues or expired wait loop
        return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
    }
    return StepResult.getStepResultSuccess();
}
Also used : ApiResourceCloneDetails(bio.terra.workspace.generated.model.ApiResourceCloneDetails) FlightWaitTimedOutException(bio.terra.stairway.exception.FlightWaitTimedOutException) FlightState(bio.terra.stairway.FlightState) ApiClonedWorkspace(bio.terra.workspace.generated.model.ApiClonedWorkspace) DatabaseOperationException(bio.terra.stairway.exception.DatabaseOperationException) FlightMap(bio.terra.stairway.FlightMap) StepResult(bio.terra.stairway.StepResult) Map(java.util.Map) FlightMap(bio.terra.stairway.FlightMap)

Example 10 with FlightState

use of bio.terra.stairway.FlightState in project terra-workspace-manager by DataBiosphere.

the class AwaitCloneGcsBucketResourceFlightStep method doStep.

@Override
public StepResult doStep(FlightContext context) throws InterruptedException, RetryException {
    // wait for the flight
    try {
        final FlightState subflightState = context.getStairway().waitForFlight(subflightId, FLIGHT_POLL_SECONDS, FLIGHT_POLL_CYCLES);
        final FlightStatus subflightStatus = subflightState.getFlightStatus();
        final WsmCloneResourceResult cloneResult = WorkspaceCloneUtils.flightStatusToCloneResult(subflightStatus, resource);
        final var cloneDetails = new WsmResourceCloneDetails();
        cloneDetails.setResult(cloneResult);
        final FlightMap resultMap = FlightUtils.getResultMapRequired(subflightState);
        final var clonedBucket = resultMap.get(JobMapKeys.RESPONSE.getKeyName(), ApiClonedControlledGcpGcsBucket.class);
        cloneDetails.setStewardshipType(StewardshipType.CONTROLLED);
        cloneDetails.setResourceType(WsmResourceType.CONTROLLED_GCP_GCS_BUCKET);
        cloneDetails.setCloningInstructions(resource.getCloningInstructions());
        cloneDetails.setSourceResourceId(resource.getResourceId());
        cloneDetails.setDestinationResourceId(Optional.ofNullable(clonedBucket).map(ApiClonedControlledGcpGcsBucket::getBucket).map(ApiCreatedControlledGcpGcsBucket::getResourceId).orElse(null));
        cloneDetails.setErrorMessage(FlightUtils.getFlightErrorMessage(subflightState));
        cloneDetails.setName(resource.getName());
        cloneDetails.setDescription(resource.getDescription());
        // add to the map
        final var resourceIdToResult = Optional.ofNullable(context.getWorkingMap().get(ControlledResourceKeys.RESOURCE_ID_TO_CLONE_RESULT, new TypeReference<Map<UUID, WsmResourceCloneDetails>>() {
        })).orElseGet(HashMap::new);
        resourceIdToResult.put(resource.getResourceId(), cloneDetails);
        context.getWorkingMap().put(ControlledResourceKeys.RESOURCE_ID_TO_CLONE_RESULT, resourceIdToResult);
    } catch (DatabaseOperationException | FlightWaitTimedOutException e) {
        // Retry for database issues or expired wait loop
        return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
    }
    validateRequiredEntries(context.getWorkingMap(), ControlledResourceKeys.RESOURCE_ID_TO_CLONE_RESULT);
    return StepResult.getStepResultSuccess();
}
Also used : WsmResourceCloneDetails(bio.terra.workspace.service.workspace.model.WsmResourceCloneDetails) WsmCloneResourceResult(bio.terra.workspace.service.workspace.model.WsmCloneResourceResult) HashMap(java.util.HashMap) FlightWaitTimedOutException(bio.terra.stairway.exception.FlightWaitTimedOutException) ApiCreatedControlledGcpGcsBucket(bio.terra.workspace.generated.model.ApiCreatedControlledGcpGcsBucket) FlightState(bio.terra.stairway.FlightState) DatabaseOperationException(bio.terra.stairway.exception.DatabaseOperationException) FlightStatus(bio.terra.stairway.FlightStatus) FlightMap(bio.terra.stairway.FlightMap) StepResult(bio.terra.stairway.StepResult) HashMap(java.util.HashMap) Map(java.util.Map) FlightMap(bio.terra.stairway.FlightMap)

Aggregations

FlightState (bio.terra.stairway.FlightState)52 AuthenticatedUserRequest (bio.terra.workspace.service.iam.AuthenticatedUserRequest)21 UUID (java.util.UUID)21 Test (org.junit.jupiter.api.Test)21 FlightMap (bio.terra.stairway.FlightMap)20 BaseConnectedTest (bio.terra.workspace.common.BaseConnectedTest)17 DisabledIfEnvironmentVariable (org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable)15 FlightDebugInfo (bio.terra.stairway.FlightDebugInfo)11 DatabaseOperationException (bio.terra.stairway.exception.DatabaseOperationException)10 StepStatus (bio.terra.stairway.StepStatus)7 StepResult (bio.terra.stairway.StepResult)6 FlightWaitTimedOutException (bio.terra.stairway.exception.FlightWaitTimedOutException)6 StairwayException (bio.terra.stairway.exception.StairwayException)6 InternalStairwayException (bio.terra.workspace.service.job.exception.InternalStairwayException)6 HashMap (java.util.HashMap)6 BaseAzureTest (bio.terra.workspace.common.BaseAzureTest)5 WsmResource (bio.terra.workspace.service.resource.model.WsmResource)5 Project (com.google.api.services.cloudresourcemanager.v3.model.Project)5 FlightNotFoundException (bio.terra.stairway.exception.FlightNotFoundException)4 ControlledAzureDiskResource (bio.terra.workspace.service.resource.controlled.cloud.azure.disk.ControlledAzureDiskResource)4