From b4284b421285134bae76fa03769eef71a60a21ed Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Feb 2022 22:35:58 -0500 Subject: [PATCH 1/6] docs(sample): Add sample for Native Image Support --- samples/native-image-sample/README.md | 78 ++++++++ samples/native-image-sample/pom.xml | 170 ++++++++++++++++++ .../NativeImageSecretManagerSample.java | 119 ++++++++++++ .../NativeImageSecretManagerSampleIT.java | 71 ++++++++ samples/pom.xml | 1 + 5 files changed, 439 insertions(+) create mode 100644 samples/native-image-sample/README.md create mode 100644 samples/native-image-sample/pom.xml create mode 100644 samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java create mode 100644 samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java diff --git a/samples/native-image-sample/README.md b/samples/native-image-sample/README.md new file mode 100644 index 00000000..326375d2 --- /dev/null +++ b/samples/native-image-sample/README.md @@ -0,0 +1,78 @@ +# Secret Manager Sample Application with Native Image + +The Secret Manager sample application demonstrates some common operations with [Google Cloud Secret Manager](https://cloud.google.com/secret-manager) and is compatible with Native Image compilation. + +This application will create a new secret named `native-secretmanager-test-secret` if it does not already exist. +It will then add a new version of the secret and then attempt to read it. + +## Setup Instructions + +You will need to follow these prerequisite steps in order to run these samples: + +1. If you have not already, [create a Google Cloud Platform Project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project). + +2. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) which will allow you to run the sample with your project's credentials. + + Once installed, log in with Application Default Credentials using the following command: + + ``` + gcloud auth application-default login + ``` + + **Note:** Authenticating with Application Default Credentials is convenient to use during development, but we recommend [alternate methods of authentication](https://cloud.google.com/docs/authentication/production) during production use. + +3. Install the GraalVM compiler. + + You can follow the [official installation instructions](https://www.graalvm.org/docs/getting-started/#install-graalvm) from the GraalVM website. + After following the instructions, ensure that you install the Native Image extension installed by running: + + ``` + gu install native-image + ``` + + Once you finish following the instructions, verify that the default version of Java is set to the GraalVM version by running `java -version` in a terminal. + + You will see something similar to the below output: + + ``` + $ java -version + + openjdk version "11.0.7" 2020-04-14 + OpenJDK Runtime Environment GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02) + OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02, mixed mode, sharing) + ``` + +4. [Enable the Secret Manager APIs](https://console.cloud.google.com/apis/api/secretmanager.googleapis.com). + +### Run with Native Image Compilation + +Navigate to this directory in a new terminal. + +1. Compile the application using the Native Image Compiler. This step may take a few minutes. + + ``` + mvn package -P native -DskipTests + ``` + +2. Run the application: + + ``` + ./target/native-image-sample + ``` + +3. The application runs through some basic Secret Manager operations (create, update, read) and then prints some results of the operations. + + ``` + Created secret: projects/xxxxxx/secrets/graal-secretmanager-test-secret + Added Secret Version: projects/xxxxxx/secrets/graal-secretmanager-test-secret/versions/1 + Reading secret value: Hello World + (Note: Don't print secret values in prod!) + ``` + +## Sample Integration test with Native Image Support + +In order to run the sample integration test as a native image, call the following command: + + ``` + mvn test -Pnative + ``` \ No newline at end of file diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml new file mode 100644 index 00000000..288cf4f0 --- /dev/null +++ b/samples/native-image-sample/pom.xml @@ -0,0 +1,170 @@ + + + 4.0.0 + com.google.cloud + native-image-sample + Native Image Sample + https://github.com/googleapis/java-secretmanager + + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + 11 + 11 + UTF-8 + + + + + + com.google.cloud + libraries-bom + 24.3.0 + pom + import + + + + + + + com.google.cloud + google-cloud-core + + + com.google.cloud + google-cloud-secretmanager + + + + junit + junit + 4.13.2 + test + + + com.google.truth + truth + 1.1.3 + test + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + + secretmanager.NativeImageSecretManagerSample + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.2.0 + + + copy-dependencies + package + + copy-dependencies + + + + ${project.build.directory}/dependency-jars/ + + + + + + + + + + + + native + + + + com.google.cloud + native-image-support + 0.12.0 + + + org.junit.vintage + junit-vintage-engine + 5.8.2 + test + + + org.graalvm.buildtools + junit-platform-native + 0.9.9 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + 2.22.2 + + + **/*IT + + + + + org.graalvm.buildtools + native-maven-plugin + 0.9.9 + true + + secretmanager.NativeImageSecretManagerSample + + --no-fallback + --no-server + + + + + build-native + + build + test + + package + + + test-native + + test + + test + + + + + + + + \ No newline at end of file diff --git a/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java new file mode 100644 index 00000000..2866b425 --- /dev/null +++ b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java @@ -0,0 +1,119 @@ +/* + * Copyright 2022 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 + * + * https://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 secretmanager; + +import com.google.cloud.ServiceOptions; +import com.google.cloud.secretmanager.v1.AccessSecretVersionResponse; +import com.google.cloud.secretmanager.v1.ProjectName; +import com.google.cloud.secretmanager.v1.Replication; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient.ListSecretsPagedResponse; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.cloud.secretmanager.v1.SecretPayload; +import com.google.cloud.secretmanager.v1.SecretVersion; +import com.google.protobuf.ByteString; +import java.io.IOException; + +/** + * Sample application demonstrating Native Image compatibility with Google Cloud Secret Manager + * APIs. + */ +public class NativeImageSecretManagerSample { + + private static final String NATIVE_TEST_SECRET_ID = "native-secretmanager-test-secret"; + + /** + * Runs the Secret Manager sample application. + */ + public static void main(String[] args) throws IOException { + String projectId = ServiceOptions.getDefaultProjectId(); + + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + if (!hasSecret(client, projectId, NATIVE_TEST_SECRET_ID)) { + createSecret(client, projectId, NATIVE_TEST_SECRET_ID); + } else { + System.out.println("Project already has secret: " + NATIVE_TEST_SECRET_ID); + } + + SecretVersion version = addSecretVersion(client, projectId, NATIVE_TEST_SECRET_ID); + printSecretVersion(client, version); + } + } + + static void createSecret( + SecretManagerServiceClient client, String projectId, String secretId) { + + Secret secret = + Secret.newBuilder() + .setReplication( + Replication.newBuilder() + .setAutomatic(Replication.Automatic.newBuilder().build()) + .build()) + .build(); + ProjectName projectName = ProjectName.of(projectId); + Secret createdSecret = client.createSecret(projectName, secretId, secret); + System.out.println("Created secret: " + createdSecret.getName()); + } + + static boolean hasSecret( + SecretManagerServiceClient client, String projectId, String secretId) { + + ProjectName projectName = ProjectName.of(projectId); + ListSecretsPagedResponse pagedResponse = client.listSecrets(projectName); + + for (Secret secret : pagedResponse.iterateAll()) { + String otherSecretId = extractSecretId(secret); + if (secretId.equals(otherSecretId)) { + return true; + } + } + + return false; + } + + static SecretVersion addSecretVersion( + SecretManagerServiceClient client, String projectId, String secretId) { + + SecretName secretName = SecretName.of(projectId, secretId); + SecretPayload payload = + SecretPayload.newBuilder() + .setData(ByteString.copyFromUtf8("Hello World")) + .build(); + + SecretVersion version = client.addSecretVersion(secretName, payload); + System.out.println("Added Secret Version: " + version.getName()); + return version; + } + + static void printSecretVersion( + SecretManagerServiceClient client, SecretVersion version) { + AccessSecretVersionResponse response = client.accessSecretVersion(version.getName()); + String payload = response.getPayload().getData().toStringUtf8(); + System.out.println("Reading secret value: " + payload); + System.out.println("(Note: Don't print secret values in prod!)"); + } + + /** + * Returns the secret ID from the fully-qualified secret name which has the format: + * projects/YOUR_PROJECT_ID/secrets/YOUR_SECRET_ID. + */ + private static String extractSecretId(Secret secret) { + String[] secretNameTokens = secret.getName().split("/"); + return secretNameTokens[secretNameTokens.length - 1]; + } +} \ No newline at end of file diff --git a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java new file mode 100644 index 00000000..0a1a392f --- /dev/null +++ b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java @@ -0,0 +1,71 @@ +/* + * Copyright 2022 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 + * + * https://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 secretmanager; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.ServiceOptions; +import com.google.cloud.secretmanager.v1.DeleteSecretRequest; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.cloud.secretmanager.v1.SecretVersion; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class NativeImageSecretManagerSampleIT { + + private static final String NATIVE_TEST_SECRET_ID = "native-test-secret" + UUID.randomUUID(); + private static String PROJECT_ID = ServiceOptions.getDefaultProjectId(); + private ByteArrayOutputStream bout; + private PrintStream out; + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + System.setOut(out); + } + + @AfterClass + public static void afterAll() throws Exception { + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + + // Delete the secret created by quickstart + SecretName name = SecretName.of(PROJECT_ID, NATIVE_TEST_SECRET_ID); + DeleteSecretRequest deleteRequest = + DeleteSecretRequest.newBuilder().setName(name.toString()).build(); + + client.deleteSecret(deleteRequest); + } + } + + @Test + public void testCreateAndPrintSecret() throws IOException { + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + NativeImageSecretManagerSample.createSecret(client, PROJECT_ID, NATIVE_TEST_SECRET_ID); + SecretVersion version = NativeImageSecretManagerSample.addSecretVersion(client, PROJECT_ID, + NATIVE_TEST_SECRET_ID); + NativeImageSecretManagerSample.printSecretVersion(client, version); + assertThat(bout.toString()).contains("Reading secret value: Hello World"); + } + } +} diff --git a/samples/pom.xml b/samples/pom.xml index 4a0dcba6..b8efa4c0 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -31,6 +31,7 @@ install-without-bom snapshot snippets + native-image-sample From 378b1ae2f9927bb34b65b73c4e1751646f96d00f Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Mon, 28 Feb 2022 18:42:44 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 1 + .../NativeImageSecretManagerSample.java | 19 ++++++------------- .../NativeImageSecretManagerSampleIT.java | 5 +++-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 2445a62f..6e14e406 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-secretmanager | Sample | Source Code | Try it | | --------------------------- | --------------------------------- | ------ | +| Native Image Secret Manager Sample | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java) | | Access Secret Version | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/AccessSecretVersion.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/AccessSecretVersion.java) | | Add Secret Version | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/AddSecretVersion.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/AddSecretVersion.java) | | Create Secret | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/CreateSecret.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/CreateSecret.java) | diff --git a/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java index 2866b425..b4b660a9 100644 --- a/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java +++ b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java @@ -37,9 +37,7 @@ public class NativeImageSecretManagerSample { private static final String NATIVE_TEST_SECRET_ID = "native-secretmanager-test-secret"; - /** - * Runs the Secret Manager sample application. - */ + /** Runs the Secret Manager sample application. */ public static void main(String[] args) throws IOException { String projectId = ServiceOptions.getDefaultProjectId(); @@ -55,8 +53,7 @@ public static void main(String[] args) throws IOException { } } - static void createSecret( - SecretManagerServiceClient client, String projectId, String secretId) { + static void createSecret(SecretManagerServiceClient client, String projectId, String secretId) { Secret secret = Secret.newBuilder() @@ -70,8 +67,7 @@ static void createSecret( System.out.println("Created secret: " + createdSecret.getName()); } - static boolean hasSecret( - SecretManagerServiceClient client, String projectId, String secretId) { + static boolean hasSecret(SecretManagerServiceClient client, String projectId, String secretId) { ProjectName projectName = ProjectName.of(projectId); ListSecretsPagedResponse pagedResponse = client.listSecrets(projectName); @@ -91,17 +87,14 @@ static SecretVersion addSecretVersion( SecretName secretName = SecretName.of(projectId, secretId); SecretPayload payload = - SecretPayload.newBuilder() - .setData(ByteString.copyFromUtf8("Hello World")) - .build(); + SecretPayload.newBuilder().setData(ByteString.copyFromUtf8("Hello World")).build(); SecretVersion version = client.addSecretVersion(secretName, payload); System.out.println("Added Secret Version: " + version.getName()); return version; } - static void printSecretVersion( - SecretManagerServiceClient client, SecretVersion version) { + static void printSecretVersion(SecretManagerServiceClient client, SecretVersion version) { AccessSecretVersionResponse response = client.accessSecretVersion(version.getName()); String payload = response.getPayload().getData().toStringUtf8(); System.out.println("Reading secret value: " + payload); @@ -116,4 +109,4 @@ private static String extractSecretId(Secret secret) { String[] secretNameTokens = secret.getName().split("/"); return secretNameTokens[secretNameTokens.length - 1]; } -} \ No newline at end of file +} diff --git a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java index 0a1a392f..24468c76 100644 --- a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java +++ b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java @@ -62,8 +62,9 @@ public static void afterAll() throws Exception { public void testCreateAndPrintSecret() throws IOException { try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { NativeImageSecretManagerSample.createSecret(client, PROJECT_ID, NATIVE_TEST_SECRET_ID); - SecretVersion version = NativeImageSecretManagerSample.addSecretVersion(client, PROJECT_ID, - NATIVE_TEST_SECRET_ID); + SecretVersion version = + NativeImageSecretManagerSample.addSecretVersion( + client, PROJECT_ID, NATIVE_TEST_SECRET_ID); NativeImageSecretManagerSample.printSecretVersion(client, version); assertThat(bout.toString()).contains("Reading secret value: Hello World"); } From f4fd2026ca31d614647bf4ce2a6d2ac987d7a29a Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Tue, 1 Mar 2022 10:01:22 -0500 Subject: [PATCH 3/6] fix setup for standard java mmode --- samples/native-image-sample/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index 288cf4f0..246bd287 100644 --- a/samples/native-image-sample/pom.xml +++ b/samples/native-image-sample/pom.xml @@ -68,6 +68,8 @@ + true + dependency-jars/ secretmanager.NativeImageSecretManagerSample From ac35e5018af0acc2bd5d4b8d85e8bcf594720b9a Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 1 Mar 2022 15:04:29 +0000 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6e14e406..b967617c 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-secretmanager' If you are using Gradle without BOM, add this to your dependencies ```Groovy -implementation 'com.google.cloud:google-cloud-secretmanager:2.1.1' +implementation 'com.google.cloud:google-cloud-secretmanager:2.1.2' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-secretmanager" % "2.1.1" +libraryDependencies += "com.google.cloud" % "google-cloud-secretmanager" % "2.1.2" ``` ## Authentication From 4102d63aa3ecaf144c4f49d7cad9fa71c9648e86 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Tue, 1 Mar 2022 19:16:55 -0500 Subject: [PATCH 5/6] use Java 8; clean up integration test --- samples/native-image-sample/pom.xml | 7 ++++--- .../secretmanager/NativeImageSecretManagerSampleIT.java | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index 246bd287..f945e9a3 100644 --- a/samples/native-image-sample/pom.xml +++ b/samples/native-image-sample/pom.xml @@ -1,7 +1,7 @@ 4.0.0 - com.google.cloud + com.example.cloud native-image-sample Native Image Sample https://github.com/googleapis/java-secretmanager @@ -17,8 +17,9 @@ - 11 - 11 + + 1.8 + 1.8 UTF-8 diff --git a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java index 24468c76..653c6b41 100644 --- a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java +++ b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java @@ -36,13 +36,11 @@ public class NativeImageSecretManagerSampleIT { private static final String NATIVE_TEST_SECRET_ID = "native-test-secret" + UUID.randomUUID(); private static String PROJECT_ID = ServiceOptions.getDefaultProjectId(); private ByteArrayOutputStream bout; - private PrintStream out; @Before public void setUp() { bout = new ByteArrayOutputStream(); - out = new PrintStream(bout); - System.setOut(out); + System.setOut(new PrintStream(bout)); } @AfterClass From c368c4ed9f8ffdcdc69cd9734601dd09f509d506 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Tue, 1 Mar 2022 19:19:33 -0500 Subject: [PATCH 6/6] small clean up --- samples/native-image-sample/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index f945e9a3..73150240 100644 --- a/samples/native-image-sample/pom.xml +++ b/samples/native-image-sample/pom.xml @@ -1,7 +1,7 @@ 4.0.0 - com.example.cloud + com.google.cloud native-image-sample Native Image Sample https://github.com/googleapis/java-secretmanager