From 1afd3aa9a4bc7b4223716c966b7791bbcd096725 Mon Sep 17 00:00:00 2001 From: Mridula <66699525+mpeddada1@users.noreply.github.com> Date: Wed, 2 Mar 2022 14:42:44 -0500 Subject: [PATCH] docs(sample): Add sample for Native Image Support (#711) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(sample): Add sample for Native Image Support * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix setup for standard java mmode * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * use Java 8; clean up integration test Co-authored-by: Owl Bot --- README.md | 1 + samples/native-image-sample/README.md | 78 ++++++++ samples/native-image-sample/pom.xml | 173 ++++++++++++++++++ .../NativeImageSecretManagerSample.java | 112 ++++++++++++ .../NativeImageSecretManagerSampleIT.java | 70 +++++++ samples/pom.xml | 1 + 6 files changed, 435 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/README.md b/README.md index ba88dd75..35ec4ac7 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/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..73150240 --- /dev/null +++ b/samples/native-image-sample/pom.xml @@ -0,0 +1,173 @@ + + + 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 + + + + + 1.8 + 1.8 + 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 + + + + true + dependency-jars/ + 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..b4b660a9 --- /dev/null +++ b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java @@ -0,0 +1,112 @@ +/* + * 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]; + } +} 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..653c6b41 --- /dev/null +++ b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java @@ -0,0 +1,70 @@ +/* + * 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; + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + } + + @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