Search in sources :

Example 1 with AIPlatformNotebooks

use of com.google.api.services.notebooks.v1.AIPlatformNotebooks in project terra-workspace-manager by DataBiosphere.

the class PrivateControlledAiNotebookInstanceLifecycle method doUserJourney.

@Override
@SuppressFBWarnings(value = "DLS_DEAD_LOCAL_STORE")
protected void doUserJourney(TestUserSpecification testUser, WorkspaceApi workspaceApi) throws Exception {
    CloudContextMaker.createGcpCloudContext(getWorkspaceId(), workspaceApi);
    workspaceApi.grantRole(new GrantRoleRequestBody().memberEmail(resourceUser.userEmail), getWorkspaceId(), IamRole.WRITER);
    workspaceApi.grantRole(new GrantRoleRequestBody().memberEmail(otherWorkspaceUser.userEmail), getWorkspaceId(), IamRole.WRITER);
    ControlledGcpResourceApi resourceUserApi = ClientTestUtils.getControlledGcpResourceClient(resourceUser, server);
    CreatedControlledGcpAiNotebookInstanceResult creationResult = NotebookUtils.makeControlledNotebookUserPrivate(getWorkspaceId(), instanceId, /*location=*/
    null, resourceUserApi);
    UUID resourceId = creationResult.getAiNotebookInstance().getMetadata().getResourceId();
    GcpAiNotebookInstanceResource resource = resourceUserApi.getAiNotebookInstance(getWorkspaceId(), resourceId);
    assertEquals(instanceId, resource.getAttributes().getInstanceId(), "Notebook instance id is correct in GET response from WSM");
    assertEquals(instanceId, creationResult.getAiNotebookInstance().getAttributes().getInstanceId(), "Notebook instance id is correct in create response from WSM");
    assertEquals(resourceUser.userEmail, resource.getMetadata().getControlledResourceMetadata().getPrivateResourceUser().getUserName(), "User is the private user of the notebook");
    assertEquals("us-central1-a", resource.getAttributes().getLocation(), "The notebook uses the default location because location is not specified.");
    createAControlledAiNotebookInstanceWithoutSpecifiedInstanceId_validInstanceIdIsGenerated(resourceUserApi);
    createAControlledAiNotebookInstanceWithoutSpecifiedInstanceId_specifyLocation(resourceUserApi);
    String instanceName = String.format("projects/%s/locations/%s/instances/%s", resource.getAttributes().getProjectId(), resource.getAttributes().getLocation(), resource.getAttributes().getInstanceId());
    AIPlatformNotebooks userNotebooks = ClientTestUtils.getAIPlatformNotebooksClient(resourceUser);
    assertTrue(NotebookUtils.userHasProxyAccess(creationResult, resourceUser, resource.getAttributes().getProjectId()), "Private resource user has access to their notebook");
    assertFalse(NotebookUtils.userHasProxyAccess(creationResult, otherWorkspaceUser, resource.getAttributes().getProjectId()), "Other workspace user does not have access to a private notebook");
    // The user should be able to stop their notebook.
    userNotebooks.projects().locations().instances().stop(instanceName, new StopInstanceRequest());
    // The user should not be able to directly delete their notebook.
    GoogleJsonResponseException directDeleteForbidden = assertThrows(GoogleJsonResponseException.class, () -> userNotebooks.projects().locations().instances().delete(instanceName).execute());
    assertEquals(HttpStatus.SC_FORBIDDEN, directDeleteForbidden.getStatusCode(), "User may not delete notebook directly on GCP");
    // Any workspace user should be able to enumerate all created notebooks, even though they can't
    // read or write them.
    ResourceApi otherUserApi = ClientTestUtils.getResourceClient(otherWorkspaceUser, server);
    ResourceList notebookList = otherUserApi.enumerateResources(getWorkspaceId(), 0, 5, ResourceType.AI_NOTEBOOK, StewardshipType.CONTROLLED);
    assertEquals(3, notebookList.getResources().size());
    MultiResourcesUtils.assertResourceType(ResourceType.AI_NOTEBOOK, notebookList);
    // Delete the AI Notebook through WSM.
    DeleteControlledGcpAiNotebookInstanceResult deleteResult = resourceUserApi.deleteAiNotebookInstance(new DeleteControlledGcpAiNotebookInstanceRequest().jobControl(new JobControl().id(UUID.randomUUID().toString())), getWorkspaceId(), resourceId);
    String deleteJobId = deleteResult.getJobReport().getId();
    deleteResult = ClientTestUtils.pollWhileRunning(deleteResult, () -> resourceUserApi.getDeleteAiNotebookInstanceResult(getWorkspaceId(), deleteJobId), DeleteControlledGcpAiNotebookInstanceResult::getJobReport, Duration.ofSeconds(10));
    ClientTestUtils.assertJobSuccess("delete ai notebook", deleteResult.getJobReport(), deleteResult.getErrorReport());
    // Verify the notebook was deleted from WSM metadata.
    ApiException notebookIsMissing = assertThrows(ApiException.class, () -> resourceUserApi.getAiNotebookInstance(getWorkspaceId(), resourceId), "Notebook is deleted from WSM");
    assertEquals(HttpStatus.SC_NOT_FOUND, notebookIsMissing.getCode(), "Error from WSM is 404");
    // Verify the notebook was deleted from GCP.
    GoogleJsonResponseException notebookNotFound = assertThrows(GoogleJsonResponseException.class, () -> userNotebooks.projects().locations().instances().get(instanceName).execute(), "Notebook is deleted from GCP");
    // GCP may respond with either 403 or 404 depending on how quickly this is called after deleting
    // the notebook. Either response is valid in this case.
    assertThat("Error from GCP is 403 or 404", notebookNotFound.getStatusCode(), anyOf(equalTo(HttpStatus.SC_NOT_FOUND), equalTo(HttpStatus.SC_FORBIDDEN)));
}
Also used : GrantRoleRequestBody(bio.terra.workspace.model.GrantRoleRequestBody) CreatedControlledGcpAiNotebookInstanceResult(bio.terra.workspace.model.CreatedControlledGcpAiNotebookInstanceResult) DeleteControlledGcpAiNotebookInstanceRequest(bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceRequest) DeleteControlledGcpAiNotebookInstanceResult(bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceResult) JobControl(bio.terra.workspace.model.JobControl) AIPlatformNotebooks(com.google.api.services.notebooks.v1.AIPlatformNotebooks) GcpAiNotebookInstanceResource(bio.terra.workspace.model.GcpAiNotebookInstanceResource) StopInstanceRequest(com.google.api.services.notebooks.v1.model.StopInstanceRequest) GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) ControlledGcpResourceApi(bio.terra.workspace.api.ControlledGcpResourceApi) ResourceApi(bio.terra.workspace.api.ResourceApi) ResourceList(bio.terra.workspace.model.ResourceList) ControlledGcpResourceApi(bio.terra.workspace.api.ControlledGcpResourceApi) UUID(java.util.UUID) ApiException(bio.terra.workspace.client.ApiException) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Example 2 with AIPlatformNotebooks

use of com.google.api.services.notebooks.v1.AIPlatformNotebooks in project terra-workspace-manager by DataBiosphere.

the class NotebookUtils method userHasProxyAccess.

/**
 * Check whether the user has access to the Notebook through the proxy with a service account.
 *
 * <p>We can't directly test that we can go through the proxy to the Jupyter notebook without a
 * real Google user auth flow, so we check the necessary ingredients instead.
 */
public static boolean userHasProxyAccess(CreatedControlledGcpAiNotebookInstanceResult createdNotebook, TestUserSpecification user, String projectId) throws GeneralSecurityException, IOException {
    String instanceName = String.format("projects/%s/locations/%s/instances/%s", createdNotebook.getAiNotebookInstance().getAttributes().getProjectId(), createdNotebook.getAiNotebookInstance().getAttributes().getLocation(), createdNotebook.getAiNotebookInstance().getAttributes().getInstanceId());
    AIPlatformNotebooks userNotebooks = ClientTestUtils.getAIPlatformNotebooksClient(user);
    Instance instance;
    try {
        instance = userNotebooks.projects().locations().instances().get(instanceName).execute();
    } catch (GoogleJsonResponseException googleException) {
        // If we get a 403 or 404 when fetching the instance, the user does not have access.
        if (googleException.getStatusCode() == HttpStatus.SC_FORBIDDEN || googleException.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
            return false;
        } else {
            // If a different status code is thrown instead, rethrow here as that's an unexpected error.
            throw googleException;
        }
    }
    // Test that the user has access to the notebook with a service account through proxy mode.
    // git secrets gets a false positive if 'service_account' is double quoted.
    assertThat("Notebook has correct proxy mode access", instance.getMetadata(), Matchers.hasEntry("proxy-mode", "service_" + "account"));
    // The user needs to have the actAs permission on the service account.
    String actAsPermission = "iam.serviceAccounts.actAs";
    String serviceAccountName = String.format("projects/%s/serviceAccounts/%s", projectId, instance.getServiceAccount());
    List<String> maybePermissionsList = ClientTestUtils.getGcpIamClient(user).projects().serviceAccounts().testIamPermissions(serviceAccountName, new TestIamPermissionsRequest().setPermissions(List.of(actAsPermission))).execute().getPermissions();
    // GCP returns null rather than an empty list when a user does not have any permissions
    return Optional.ofNullable(maybePermissionsList).map(list -> list.contains(actAsPermission)).orElse(false);
}
Also used : AccessScope(bio.terra.workspace.model.AccessScope) CloningInstructionsEnum(bio.terra.workspace.model.CloningInstructionsEnum) ControlledGcpResourceApi(bio.terra.workspace.api.ControlledGcpResourceApi) Instance(com.google.api.services.notebooks.v1.model.Instance) JobControl(bio.terra.workspace.model.JobControl) ManagedBy(bio.terra.workspace.model.ManagedBy) CreateControlledGcpAiNotebookInstanceRequestBody(bio.terra.workspace.model.CreateControlledGcpAiNotebookInstanceRequestBody) HttpStatus(org.apache.http.HttpStatus) GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) GeneralSecurityException(java.security.GeneralSecurityException) Duration(java.time.Duration) DeleteControlledGcpAiNotebookInstanceResult(bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceResult) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) GcpAiNotebookInstanceVmImage(bio.terra.workspace.model.GcpAiNotebookInstanceVmImage) Nullable(javax.annotation.Nullable) DeleteControlledGcpAiNotebookInstanceRequest(bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceRequest) AIPlatformNotebooks(com.google.api.services.notebooks.v1.AIPlatformNotebooks) ControlledResourceCommonFields(bio.terra.workspace.model.ControlledResourceCommonFields) ApiException(bio.terra.workspace.client.ApiException) Matchers(org.hamcrest.Matchers) IOException(java.io.IOException) UUID(java.util.UUID) CreatedControlledGcpAiNotebookInstanceResult(bio.terra.workspace.model.CreatedControlledGcpAiNotebookInstanceResult) GcpAiNotebookInstanceCreationParameters(bio.terra.workspace.model.GcpAiNotebookInstanceCreationParameters) List(java.util.List) TestUserSpecification(bio.terra.testrunner.runner.config.TestUserSpecification) Optional(java.util.Optional) RandomStringUtils(org.apache.commons.lang3.RandomStringUtils) TestIamPermissionsRequest(com.google.api.services.iam.v1.model.TestIamPermissionsRequest) GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) Instance(com.google.api.services.notebooks.v1.model.Instance) TestIamPermissionsRequest(com.google.api.services.iam.v1.model.TestIamPermissionsRequest) AIPlatformNotebooks(com.google.api.services.notebooks.v1.AIPlatformNotebooks)

Aggregations

ControlledGcpResourceApi (bio.terra.workspace.api.ControlledGcpResourceApi)2 ApiException (bio.terra.workspace.client.ApiException)2 CreatedControlledGcpAiNotebookInstanceResult (bio.terra.workspace.model.CreatedControlledGcpAiNotebookInstanceResult)2 DeleteControlledGcpAiNotebookInstanceRequest (bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceRequest)2 DeleteControlledGcpAiNotebookInstanceResult (bio.terra.workspace.model.DeleteControlledGcpAiNotebookInstanceResult)2 JobControl (bio.terra.workspace.model.JobControl)2 GoogleJsonResponseException (com.google.api.client.googleapis.json.GoogleJsonResponseException)2 AIPlatformNotebooks (com.google.api.services.notebooks.v1.AIPlatformNotebooks)2 UUID (java.util.UUID)2 TestUserSpecification (bio.terra.testrunner.runner.config.TestUserSpecification)1 ResourceApi (bio.terra.workspace.api.ResourceApi)1 AccessScope (bio.terra.workspace.model.AccessScope)1 CloningInstructionsEnum (bio.terra.workspace.model.CloningInstructionsEnum)1 ControlledResourceCommonFields (bio.terra.workspace.model.ControlledResourceCommonFields)1 CreateControlledGcpAiNotebookInstanceRequestBody (bio.terra.workspace.model.CreateControlledGcpAiNotebookInstanceRequestBody)1 GcpAiNotebookInstanceCreationParameters (bio.terra.workspace.model.GcpAiNotebookInstanceCreationParameters)1 GcpAiNotebookInstanceResource (bio.terra.workspace.model.GcpAiNotebookInstanceResource)1 GcpAiNotebookInstanceVmImage (bio.terra.workspace.model.GcpAiNotebookInstanceVmImage)1 GrantRoleRequestBody (bio.terra.workspace.model.GrantRoleRequestBody)1 ManagedBy (bio.terra.workspace.model.ManagedBy)1