diff --git a/functions/v2/label-compute-instance/pom.xml b/functions/v2/label-compute-instance/pom.xml
new file mode 100644
index 00000000000..cb574889593
--- /dev/null
+++ b/functions/v2/label-compute-instance/pom.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+ 4.0.0
+
+ com.example.cloud.functions
+ label-compute-instance
+
+
+ com.google.cloud.samples
+ shared-configuration
+ 1.0.23
+
+
+
+ 11
+ 11
+ UTF-8
+
+
+
+
+
+ com.google.cloud.functions
+ functions-framework-api
+ 1.0.4
+ provided
+
+
+ com.google.cloud
+ google-cloud-compute
+ 1.5.0-alpha
+
+
+ com.google.code.gson
+ gson
+ 2.8.8
+ compile
+
+
+ com.google.protobuf
+ protobuf-java-util
+ 4.0.0-rc-2
+
+
+
+
+ com.google.truth
+ truth
+ 1.1.3
+ test
+
+
+ com.google.guava
+ guava-testlib
+ 31.0-jre
+ test
+
+
+ io.cloudevents
+ cloudevents-core
+ 2.2.0
+ test
+
+
+
+
+
+
+
+ com.google.cloud.functions
+ function-maven-plugin
+ 0.10.0
+
+ functions.AutoLabelInstance
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ 3.0.0-M5
+
+
+ **/*Test.java
+
+ ${skipTests}
+ sponge_log
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/functions/v2/label-compute-instance/src/main/java/functions/AutoLabelInstance.java b/functions/v2/label-compute-instance/src/main/java/functions/AutoLabelInstance.java
new file mode 100644
index 00000000000..6fe51bc95dc
--- /dev/null
+++ b/functions/v2/label-compute-instance/src/main/java/functions/AutoLabelInstance.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2021 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 functions;
+
+import com.google.cloud.compute.v1.GetInstanceRequest;
+import com.google.cloud.compute.v1.Instance;
+import com.google.cloud.compute.v1.InstancesClient;
+import com.google.cloud.compute.v1.InstancesSetLabelsRequest;
+import com.google.cloud.compute.v1.SetLabelsInstanceRequest;
+import com.google.cloud.functions.CloudEventsFunction;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import io.cloudevents.CloudEvent;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Logger;
+
+public class AutoLabelInstance implements CloudEventsFunction {
+ private static final Logger logger = Logger.getLogger(AutoLabelInstance.class.getName());
+
+ @Override
+ public void accept(CloudEvent event) throws Exception {
+ // Extract CloudEvent data
+ if (event.getData() != null) {
+ String cloudEventData = new String(event.getData().toBytes(), StandardCharsets.UTF_8);
+
+ // Convert data to JSON
+ JsonObject eventData;
+ try {
+ Gson gson = new Gson();
+ eventData = gson.fromJson(cloudEventData, JsonObject.class);
+ } catch (JsonSyntaxException error) {
+ throw new RuntimeException("CloudEvent data is not valid JSON: " + error.getMessage());
+ }
+
+ // Extract the Cloud Audit Logging entry from the data's protoPayload
+ JsonObject payload = eventData.getAsJsonObject("protoPayload");
+ JsonObject auth = payload.getAsJsonObject("authenticationInfo");
+
+ // Extract the email address of the authenticated user
+ // (or service account on behalf of third party principal) making the request
+ String creator = auth.get("principalEmail").getAsString();
+ if (creator == null) {
+ throw new RuntimeException("`principalEmail` not found in protoPayload.");
+ }
+ // Format the 'creator' parameter to match GCE label validation requirements
+ creator = creator.toLowerCase().replaceAll("\\W", "-");
+
+ // Get relevant VM instance details from the CloudEvent `subject` property
+ // Example: compute.googleapis.com/projects//zones//instances/
+ String subject = event.getSubject();
+ if (subject == null || subject == "") {
+ throw new RuntimeException("Missing CloudEvent `subject`.");
+ }
+ String[] params = subject.split("/");
+
+ // Validate data
+ if (params.length < 7) {
+ throw new RuntimeException("Can not parse resource from CloudEvent `subject`: " + subject);
+ }
+ String project = params[2];
+ String zone = params[4];
+ String instanceName = params[6];
+
+ // Instantiate the Compute Instances client
+ try (InstancesClient instancesClient = InstancesClient.create()) {
+ // Get the newly-created VM instance's label fingerprint
+ // This is required by the Compute Engine API to prevent duplicate labels
+ GetInstanceRequest getInstanceRequest =
+ GetInstanceRequest.newBuilder()
+ .setInstance(instanceName)
+ .setProject(project)
+ .setZone(zone)
+ .build();
+ Instance instance = instancesClient.get(getInstanceRequest);
+ String fingerPrint = instance.getLabelFingerprint();
+
+ // Label the instance with its creator
+ SetLabelsInstanceRequest setLabelRequest =
+ SetLabelsInstanceRequest.newBuilder()
+ .setInstance(instanceName)
+ .setProject(project)
+ .setZone(zone)
+ .setInstancesSetLabelsRequestResource(
+ InstancesSetLabelsRequest.newBuilder()
+ .putLabels("creator", creator)
+ .setLabelFingerprint(fingerPrint)
+ .build())
+ .build();
+
+ instancesClient.setLabels(setLabelRequest);
+ logger.info(
+ String.format(
+ "Adding label, \"{'creator': '%s'}\", to instance, \"%s\".",
+ creator, instanceName));
+ } catch (Exception error) {
+ throw new RuntimeException(
+ String.format(
+ "Error trying to label VM instance, %s: %s", instanceName, error.toString()));
+ }
+ }
+ }
+}
diff --git a/functions/v2/label-compute-instance/src/test/java/functions/AutoLabelInstanceTest.java b/functions/v2/label-compute-instance/src/test/java/functions/AutoLabelInstanceTest.java
new file mode 100644
index 00000000000..986e381e67e
--- /dev/null
+++ b/functions/v2/label-compute-instance/src/test/java/functions/AutoLabelInstanceTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 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 functions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.testing.TestLogHandler;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+import java.net.URI;
+import java.util.logging.Logger;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AutoLabelInstanceTest {
+ private static final Logger logger = Logger.getLogger(AutoLabelInstance.class.getName());
+ private static final TestLogHandler logHandler = new TestLogHandler();
+
+ private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
+ private static final String ZONE = "us-central1-a";
+ private static final String INSTANCE = "lite1";
+
+ @BeforeClass
+ public static void beforeClass() {
+ logger.addHandler(logHandler);
+ }
+
+ @Test
+ public void functionsAutoLabelInstance() throws Exception {
+ // Build a CloudEvent Log Entry
+ JsonObject protoPayload = new JsonObject();
+ JsonObject authInfo = new JsonObject();
+ String email = "test@gmail.com";
+ authInfo.addProperty("principalEmail", email);
+
+ protoPayload.add("authenticationInfo", authInfo);
+
+ String resource =
+ String.format(
+ "compute.googleapis.com/projects/%s/zones/%s/instances/%s", PROJECT_ID, ZONE, INSTANCE);
+ protoPayload.addProperty("resourceName", resource);
+ protoPayload.addProperty("methodName", "beta.compute.instances.insert");
+
+ JsonObject encodedData = new JsonObject();
+ encodedData.add("protoPayload", protoPayload);
+ encodedData.addProperty("name", "test name");
+
+ CloudEvent event =
+ CloudEventBuilder.v1()
+ .withId("0")
+ .withSubject(resource)
+ .withType("google.cloud.audit.log.v1.written")
+ .withSource(URI.create("https://example.com"))
+ .withData(new Gson().toJson(encodedData).getBytes())
+ .build();
+
+ new AutoLabelInstance().accept(event);
+
+ assertThat(
+ String.format(
+ "Adding label, \"{'creator': '%s'}\", to instance, \"%s\".",
+ "test-gmail-com", INSTANCE))
+ .isEqualTo(logHandler.getStoredLogRecords().get(0).getMessage());
+ }
+}