From 30300815f2faeef5780877dd74e2f8381b4a8caa Mon Sep 17 00:00:00 2001 From: BenWhitehead Date: Wed, 12 Jun 2024 21:22:02 -0400 Subject: [PATCH] docs: add Hierarchical Namespace Bucket and Folders samples (#2583) New samples * `storage_create_bucket_hierarchical_namespace` * `storage_control_create_folder` * `storage_control_delete_folder` * `storage_control_get_folder` * `storage_control_list_folders` * `storage_control_rename_folder` Fixes #2569 --- .../storage/control/v2/CreateFolder.java | 50 ++++++ .../v2/CreateHierarchicalNamespaceBucket.java | 54 ++++++ .../storage/control/v2/DeleteFolder.java | 48 ++++++ .../example/storage/control/v2/GetFolder.java | 50 ++++++ .../storage/control/v2/ListFolders.java | 48 ++++++ .../storage/control/v2/RenameFolder.java | 66 ++++++++ .../storage/control/v2/FoldersTest.java | 158 ++++++++++++++++++ .../example/storage/control/v2/HNSTest.java | 42 +++++ 8 files changed, 516 insertions(+) create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/CreateFolder.java create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/CreateHierarchicalNamespaceBucket.java create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/DeleteFolder.java create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/GetFolder.java create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/ListFolders.java create mode 100644 samples/snippets/src/main/java/com/example/storage/control/v2/RenameFolder.java create mode 100644 samples/snippets/src/test/java/com/example/storage/control/v2/FoldersTest.java create mode 100644 samples/snippets/src/test/java/com/example/storage/control/v2/HNSTest.java diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/CreateFolder.java b/samples/snippets/src/main/java/com/example/storage/control/v2/CreateFolder.java new file mode 100644 index 000000000..6bfc66092 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/CreateFolder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_control_create_folder] +import com.google.storage.control.v2.BucketName; +import com.google.storage.control.v2.CreateFolderRequest; +import com.google.storage.control.v2.Folder; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; + +public final class CreateFolder { + + public static void createFolder(String bucketName, String folderName) throws IOException { + // The name of the bucket + // String bucketName = "your-unique-bucket-name"; + + // The name of the folder within the bucket + // String folderName = "your-unique-folder-name"; + + try (StorageControlClient storageControl = StorageControlClient.create()) { + + CreateFolderRequest request = + CreateFolderRequest.newBuilder() + // Set project to "_" to signify globally scoped bucket + .setParent(BucketName.format("_", bucketName)) + .setFolderId(folderName) + .build(); + + Folder newFolder = storageControl.createFolder(request); + + System.out.printf("Created folder: %s%n", newFolder.getName()); + } + } +} +// [END storage_control_create_folder] diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/CreateHierarchicalNamespaceBucket.java b/samples/snippets/src/main/java/com/example/storage/control/v2/CreateHierarchicalNamespaceBucket.java new file mode 100644 index 000000000..f6d0868c2 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/CreateHierarchicalNamespaceBucket.java @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_create_bucket_hierarchical_namespace] +import com.google.cloud.storage.Bucket; +import com.google.cloud.storage.BucketInfo; +import com.google.cloud.storage.BucketInfo.HierarchicalNamespace; +import com.google.cloud.storage.BucketInfo.IamConfiguration; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageOptions; + +public final class CreateHierarchicalNamespaceBucket { + + public static void createHierarchicalNamespaceBucket(String projectId, String bucketName) + throws Exception { + // The ID of your GCP project + // String projectId = "your-project-id"; + + // The ID to give your GCS bucket + // String bucketName = "your-unique-bucket-name"; + StorageOptions storageOptions = StorageOptions.newBuilder().setProjectId(projectId).build(); + try (Storage storage = storageOptions.getService()) { + + BucketInfo bucketInfo = + BucketInfo.newBuilder(bucketName) + .setIamConfiguration( + // Hierarchical namespace buckets must use uniform bucket-level access. + IamConfiguration.newBuilder().setIsUniformBucketLevelAccessEnabled(true).build()) + .setHierarchicalNamespace(HierarchicalNamespace.newBuilder().setEnabled(true).build()) + .build(); + + Bucket bucket = storage.create(bucketInfo); + + System.out.printf( + "Created bucket %s with Hierarchical Namespace enabled.%n", bucket.getName()); + } + } +} +// [END storage_create_bucket_hierarchical_namespace] diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/DeleteFolder.java b/samples/snippets/src/main/java/com/example/storage/control/v2/DeleteFolder.java new file mode 100644 index 000000000..187a682f1 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/DeleteFolder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_control_delete_folder] + +import com.google.storage.control.v2.DeleteFolderRequest; +import com.google.storage.control.v2.FolderName; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; + +public final class DeleteFolder { + + public static void deleteFolder(String bucketName, String folderName) throws IOException { + // The name of the bucket + // String bucketName = "your-unique-bucket-name"; + + // The name of the folder within the bucket + // String folderName = "your-unique-folder-name"; + + try (StorageControlClient storageControl = StorageControlClient.create()) { + + // Set project to "_" to signify globally scoped bucket + String folderResourceName = FolderName.format("_", bucketName, folderName); + DeleteFolderRequest request = + DeleteFolderRequest.newBuilder().setName(folderResourceName).build(); + + storageControl.deleteFolder(request); + + System.out.printf("Deleted folder: %s%n", folderResourceName); + } + } +} +// [END storage_control_delete_folder] diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/GetFolder.java b/samples/snippets/src/main/java/com/example/storage/control/v2/GetFolder.java new file mode 100644 index 000000000..454ed7b3e --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/GetFolder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_control_get_folder] + +import com.google.storage.control.v2.Folder; +import com.google.storage.control.v2.FolderName; +import com.google.storage.control.v2.GetFolderRequest; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; + +public final class GetFolder { + + public static void getFolder(String bucketName, String folderName) throws IOException { + // The name of the bucket + // String bucketName = "your-unique-bucket-name"; + + // The name of the folder within the bucket + // String folderName = "your-unique-folder-name"; + + try (StorageControlClient storageControl = StorageControlClient.create()) { + + GetFolderRequest request = + GetFolderRequest.newBuilder() + // Set project to "_" to signify globally scoped bucket + .setName(FolderName.format("_", bucketName, folderName)) + .build(); + + Folder newFolder = storageControl.getFolder(request); + + System.out.printf("Got folder: %s%n", newFolder.getName()); + } + } +} +// [END storage_control_get_folder] diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/ListFolders.java b/samples/snippets/src/main/java/com/example/storage/control/v2/ListFolders.java new file mode 100644 index 000000000..2778213e7 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/ListFolders.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_control_list_folders] + +import com.google.storage.control.v2.BucketName; +import com.google.storage.control.v2.Folder; +import com.google.storage.control.v2.ListFoldersRequest; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; + +public final class ListFolders { + + public static void listFolders(String bucketName) throws IOException { + // The name of the bucket + // String bucketName = "your-unique-bucket-name"; + + try (StorageControlClient storageControl = StorageControlClient.create()) { + + ListFoldersRequest request = + ListFoldersRequest.newBuilder() + // Set project to "_" to signify globally scoped bucket + .setParent(BucketName.format("_", bucketName)) + .build(); + + Iterable folders = storageControl.listFolders(request).iterateAll(); + for (Folder folder : folders) { + System.out.printf("Found folder: %s%n", folder.getName()); + } + } + } +} +// [END storage_control_list_folders] diff --git a/samples/snippets/src/main/java/com/example/storage/control/v2/RenameFolder.java b/samples/snippets/src/main/java/com/example/storage/control/v2/RenameFolder.java new file mode 100644 index 000000000..e8f95b6f5 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/storage/control/v2/RenameFolder.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +// [START storage_control_rename_folder] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.storage.control.v2.Folder; +import com.google.storage.control.v2.FolderName; +import com.google.storage.control.v2.RenameFolderMetadata; +import com.google.storage.control.v2.RenameFolderRequest; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public final class RenameFolder { + + public static void renameFolder( + String bucketName, String sourceFolderName, String destinationFolderName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // The name of the bucket + // String bucketName = "your-unique-bucket-name"; + + // The name of the folder within the bucket + // String sourceFolderName = "your-unique-source-folder-name"; + + // The new name of the folder within the bucket + // String destinationFolderName = "your-unique-destination-folder-name"; + + try (StorageControlClient storageControl = StorageControlClient.create()) { + + // Set project to "_" to signify globally scoped bucket + String sourceFolderResourceName = FolderName.format("_", bucketName, sourceFolderName); + RenameFolderRequest request = + RenameFolderRequest.newBuilder() + .setName(sourceFolderResourceName) + .setDestinationFolderId(destinationFolderName) + .build(); + + OperationFuture renameOperation = + storageControl.renameFolderAsync(request); + + Folder destinationFolder = renameOperation.get(30, TimeUnit.SECONDS); + + System.out.printf( + "Renamed folder from %s to %s%n", sourceFolderResourceName, destinationFolder.getName()); + } + } +} +// [END storage_control_rename_folder] diff --git a/samples/snippets/src/test/java/com/example/storage/control/v2/FoldersTest.java b/samples/snippets/src/test/java/com/example/storage/control/v2/FoldersTest.java new file mode 100644 index 000000000..7b4f8f214 --- /dev/null +++ b/samples/snippets/src/test/java/com/example/storage/control/v2/FoldersTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.api.gax.rpc.NotFoundException; +import com.google.cloud.storage.BucketInfo; +import com.google.cloud.storage.BucketInfo.HierarchicalNamespace; +import com.google.cloud.storage.BucketInfo.IamConfiguration; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageOptions; +import com.google.cloud.storage.testing.RemoteStorageHelper; +import com.google.cloud.testing.junit4.StdOutCaptureRule; +import com.google.storage.control.v2.BucketName; +import com.google.storage.control.v2.Folder; +import com.google.storage.control.v2.FolderName; +import com.google.storage.control.v2.StorageControlClient; +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public final class FoldersTest { + + @Rule public StdOutCaptureRule stdOut = new StdOutCaptureRule(); + + private Storage storage; + private BucketInfo bucket; + private StorageControlClient storageControl; + + @Before + public void setUp() throws Exception { + storage = StorageOptions.http().build().getService(); + String bucketName = RemoteStorageHelper.generateBucketName(); + BucketInfo bucketInfo = + BucketInfo.newBuilder(bucketName) + .setIamConfiguration( + // Hierarchical namespace buckets must use uniform bucket-level access. + IamConfiguration.newBuilder().setIsUniformBucketLevelAccessEnabled(true).build()) + .setHierarchicalNamespace(HierarchicalNamespace.newBuilder().setEnabled(true).build()) + .build(); + + bucket = storage.create(bucketInfo).asBucketInfo(); + storageControl = StorageControlClient.create(); + } + + @After + public void tearDown() throws Exception { + // Use try-with-resource to handle the dance closing multiple things + //noinspection EmptyTryBlock + try (AutoCloseable ignore1 = storage; + AutoCloseable ignore2 = storageControl) { + // ignore + } + } + + @Test + public void createFolder() throws IOException { + String folderName = UUID.randomUUID().toString(); + CreateFolder.createFolder(bucket.getName(), folderName); + try { + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(folderName); + } finally { + storageControl.deleteFolder(FolderName.of("_", bucket.getName(), folderName)); + } + } + + @Test + public void getFolder() throws IOException { + FolderName folderName = FolderName.of("_", bucket.getName(), UUID.randomUUID().toString()); + Folder gen1 = + storageControl.createFolder( + BucketName.of("_", bucket.getName()), + Folder.getDefaultInstance(), + folderName.getFolder()); + + GetFolder.getFolder(bucket.getName(), folderName.getFolder()); + try { + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(folderName.toString()); + } finally { + storageControl.deleteFolder(folderName); + } + } + + @Test + public void renameFolder() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + FolderName srcFolderName = FolderName.of("_", bucket.getName(), UUID.randomUUID().toString()); + Folder gen1 = + storageControl.createFolder( + BucketName.of("_", bucket.getName()), + Folder.getDefaultInstance(), + srcFolderName.getFolder()); + + FolderName dstFolderName = FolderName.of("_", bucket.getName(), UUID.randomUUID().toString()); + + RenameFolder.renameFolder( + bucket.getName(), srcFolderName.getFolder(), dstFolderName.getFolder()); + try { + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(srcFolderName.toString()); + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(dstFolderName.toString()); + assertThrows(NotFoundException.class, () -> storageControl.getFolder(srcFolderName)); + } finally { + storageControl.deleteFolder(dstFolderName); + } + } + + @Test + public void deleteFolder() throws IOException { + FolderName folderName = FolderName.of("_", bucket.getName(), UUID.randomUUID().toString()); + Folder gen1 = + storageControl.createFolder( + BucketName.of("_", bucket.getName()), + Folder.getDefaultInstance(), + folderName.getFolder()); + + DeleteFolder.deleteFolder(bucket.getName(), folderName.getFolder()); + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(folderName.toString()); + assertThrows(NotFoundException.class, () -> storageControl.getFolder(folderName)); + } + + @Test + public void listFolder() throws IOException { + FolderName folderName = FolderName.of("_", bucket.getName(), UUID.randomUUID().toString()); + Folder gen1 = + storageControl.createFolder( + BucketName.of("_", bucket.getName()), + Folder.getDefaultInstance(), + folderName.getFolder()); + + ListFolders.listFolders(bucket.getName()); + try { + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(folderName.toString()); + } finally { + storageControl.deleteFolder(folderName); + } + } +} diff --git a/samples/snippets/src/test/java/com/example/storage/control/v2/HNSTest.java b/samples/snippets/src/test/java/com/example/storage/control/v2/HNSTest.java new file mode 100644 index 000000000..5d2ec83c1 --- /dev/null +++ b/samples/snippets/src/test/java/com/example/storage/control/v2/HNSTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.storage.control.v2; + +import static com.google.common.truth.Truth.assertThat; + +import com.example.storage.TestBase; +import com.google.cloud.storage.Bucket; +import com.google.cloud.storage.testing.RemoteStorageHelper; +import org.junit.Test; + +public final class HNSTest extends TestBase { + + @Test + public void createHierarchicalNamespaceBucket() throws Exception { + String newBucketName = RemoteStorageHelper.generateBucketName(); + String projectId = storage.getOptions().getProjectId(); + CreateHierarchicalNamespaceBucket.createHierarchicalNamespaceBucket(projectId, newBucketName); + try { + Bucket remoteBucket = storage.get(newBucketName); + assertThat(remoteBucket).isNotNull(); + assertThat(remoteBucket.getHierarchicalNamespace().getEnabled()).isTrue(); + assertThat(stdOut.getCapturedOutputAsUtf8String()).contains(newBucketName); + } finally { + storage.delete(newBucketName); + } + } +}