-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add native image sample for google-cloud-secretmanager (#10805)
* chore: add native image sample for google-cloud-secretmanager
- Loading branch information
Showing
9 changed files
with
465 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# 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 native image compiler. | ||
You can follow the [official installation instructions](https://www.graalvm.org/docs/getting-started/#install-graalvm). | ||
After following the instructions, ensure that you install the Native Image extension installed by running: | ||
``` | ||
gu install native-image | ||
``` | ||
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
|
||
<parent> | ||
<artifactId>google-cloud-samples</artifactId> | ||
<groupId>com.google.cloud</groupId> | ||
<version>0.1.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>native-image-sample</artifactId> | ||
<name>Native Image Sample</name> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>com.google.cloud</groupId> | ||
<artifactId>libraries-bom</artifactId> | ||
<version>26.38.0</version> | ||
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.google.cloud</groupId> | ||
<artifactId>google-cloud-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.cloud</groupId> | ||
<artifactId>google-cloud-secretmanager</artifactId> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-deploy-plugin</artifactId> | ||
<version>3.1.2</version> | ||
<configuration> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
|
||
<!-- This plugin enables building the application to a JAR *not* using native image compilation --> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<version>3.3.0</version> | ||
<configuration> | ||
<archive> | ||
<manifest> | ||
<addClasspath>true</addClasspath> | ||
<classpathPrefix>dependency-jars/</classpathPrefix> | ||
<mainClass>com.google.cloud.example.NativeImageSecretManagerSample</mainClass> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-dependency-plugin</artifactId> | ||
<version>3.3.0</version> | ||
<executions> | ||
<execution> | ||
<id>copy-dependencies</id> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>copy-dependencies</goal> | ||
</goals> | ||
<configuration> | ||
<outputDirectory> | ||
${project.build.directory}/dependency-jars/ | ||
</outputDirectory> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<profiles> | ||
<!-- Native Profile--> | ||
<!-- TODO(10840): Use maven properties to track versions once https://github.com/googleapis/java-shared-config/pull/824 is merged. --> | ||
<profile> | ||
<id>native</id> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.opentest4j</groupId> | ||
<artifactId>opentest4j</artifactId> | ||
<version>1.3.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.vintage</groupId> | ||
<artifactId>junit-vintage-engine</artifactId> | ||
<version>5.10.2</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<version>3.2.5</version> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.junit.vintage</groupId> | ||
<artifactId>junit-vintage-engine</artifactId> | ||
<version>5.10.2</version> | ||
</dependency> | ||
</dependencies> | ||
<configuration> | ||
<excludes combine.self="override" /> | ||
<includes> | ||
<include>**/IT*.java</include> | ||
</includes> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.graalvm.buildtools</groupId> | ||
<artifactId>native-maven-plugin</artifactId> | ||
<version>0.10.1</version> | ||
<extensions>true</extensions> | ||
<configuration> | ||
<mainClass>com.google.cloud.example.NativeImageSecretManagerSample</mainClass> | ||
<buildArgs> | ||
<buildArg>--no-fallback</buildArg> | ||
</buildArgs> | ||
</configuration> | ||
<executions> | ||
|
||
<!-- Configuration to build sample with native image compilation --> | ||
<execution> | ||
<id>build-native</id> | ||
<goals> | ||
<goal>build</goal> | ||
<goal>test</goal> | ||
</goals> | ||
<phase>package</phase> | ||
</execution> | ||
|
||
<!-- Configuration to run ITNativeImageSecretManager with native image compilation --> | ||
<execution> | ||
<id>test-native</id> | ||
<goals> | ||
<goal>test</goal> | ||
</goals> | ||
<phase>test</phase> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</profile> | ||
</profiles> | ||
</project> |
112 changes: 112 additions & 0 deletions
112
...e-image-sample/src/main/java/com/google/cloud/example/NativeImageSecretManagerSample.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* 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 | ||
* | ||
* 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 com.google.cloud.example; | ||
|
||
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 { | ||
|
||
public static void main(String[] args) throws IOException { | ||
String secretId = "native-secretmanager-test-secret"; | ||
String projectId = ServiceOptions.getDefaultProjectId(); | ||
|
||
try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { | ||
if (!hasSecret(client, projectId, secretId)) { | ||
createSecret(client, projectId, secretId); | ||
} else { | ||
System.out.println("Project already has secret: " + secretId); | ||
} | ||
|
||
SecretVersion version = addSecretVersion(client, projectId, secretId); | ||
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. | ||
* | ||
* @param secret {@link Secret} to extract id from. | ||
* @return a {@link String} representing the secret id | ||
*/ | ||
private static String extractSecretId(Secret secret) { | ||
String[] secretNameTokens = secret.getName().split("/"); | ||
return secretNameTokens[secretNameTokens.length - 1]; | ||
} | ||
} |
Oops, something went wrong.