Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new module for resource-detector support library #276

Merged
merged 26 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c8b206e
Add new module for resource-detector support library
psx95 Dec 1, 2023
7baeb6e
Rname GCPResource -> GCPResourceProvider
psx95 Dec 3, 2023
cb3911d
Extract GCPMetadataConfig into support library
psx95 Dec 12, 2023
60e4df8
Refactor platform detection from resource provider
psx95 Dec 31, 2023
f3f6105
Refactor platform detection to enhance testing
psx95 Jan 3, 2024
38e9ced
make EnvironmentVariables package-private
psx95 Jan 4, 2024
27184e3
Add license headers to the newly added files
psx95 Jan 4, 2024
cbaaa31
Fix spotless style findings
psx95 Jan 4, 2024
5c9500f
Remove CloudLocationUtil class
psx95 Jan 4, 2024
ec479f5
change attribute map to hold string instead of optional values
psx95 Jan 5, 2024
8ab8080
add tests to verify resource attributes mapping
psx95 Jan 5, 2024
601b4f0
add javadoc to public classes
psx95 Jan 6, 2024
a224469
add unit test for ServiceLoader discoverability
psx95 Jan 6, 2024
e4d4321
Remove no-args constructor for simplified testing
psx95 Jan 7, 2024
249d2d7
Update gradle files to support junit5 testing
psx95 Jan 8, 2024
f4577d0
Add missing attribute in GKE mapping
psx95 Jan 8, 2024
1730be4
Add tests for resources-support library
psx95 Jan 8, 2024
cf476da
Update copyright year in GoogleCloudRun.java
psx95 Jan 8, 2024
6041f89
Add missing newline
psx95 Jan 8, 2024
afe9e19
Update resource-detector tests to JUnit5
psx95 Jan 8, 2024
0764e4a
Remove non-GCP attributes from GKE detection
psx95 Jan 9, 2024
6662d71
Add missing attributes in detected GCE environment
psx95 Jan 9, 2024
eb613b6
Update tests for GAE
psx95 Jan 9, 2024
4d577f0
Add CLOUD_ACCOUNT_ID to all supported platforms
psx95 Jan 9, 2024
d529469
Rename support package: detectors -> detection
psx95 Jan 11, 2024
dccc767
Undo breaking changes
psx95 Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,11 @@ subprojects {
openTelemetryInstrumentationVersion = '1.31.0'
openTelemetrySemconvVersion = '1.22.0'
junitVersion = '4.13'
junit5Version = '5.10.0'
mockitoVersion = '3.5.10'
pubSubVersion = '1.125.11'
testContainersVersion = '1.15.1'
wiremockVersion = '2.27.2'
wiremockVersion = '2.35.0'
springWebVersion = '2.4.5'
springOpenFeignVersion = '3.0.0'
springOtelVersion = '1.0.0-M8'
Expand Down Expand Up @@ -194,6 +195,9 @@ subprojects {
testLibraries = [
assertj : "org.assertj:assertj-core:${assertjVersion}",
junit : "junit:junit:${junitVersion}",
junit5 : "org.junit.jupiter:junit-jupiter-api:${junit5Version}",
junit5_runtime : "org.junit.jupiter:junit-jupiter-engine:${junit5Version}",
junit5_params : "org.junit.jupiter:junit-jupiter-params:${junit5Version}",
mockito : "org.mockito:mockito-inline:${mockitoVersion}",
slf4j_simple: "org.slf4j:slf4j-simple:${slf4jVersion}",
opentelemetry_sdk_testing: "io.opentelemetry:opentelemetry-sdk-testing:${openTelemetryVersion}",
Expand Down
36 changes: 36 additions & 0 deletions detectors/resources-support/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.
*/
description = 'Support library for Google Cloud Resource Detector'

dependencies {
testImplementation(testLibraries.assertj)
testImplementation(testLibraries.wiremock)
testImplementation(testLibraries.mockito)
testImplementation(testLibraries.junit5)
testImplementation(testLibraries.junit5_params)
testRuntimeOnly(testLibraries.junit5_runtime)
}

afterEvaluate {
tasks.named("compileJava"){
options.release = 8
}
}

test {
// required for discovering JUnit 5 tests
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.google.cloud.opentelemetry.detectors;

/**
* Contains constants that act as keys for the known attributes for {@link
* com.google.cloud.opentelemetry.detectors.GCPPlatformDetector.SupportedPlatform}s.
*/
public final class AttributeKeys {
// GCE Attributes
public static final String GCE_PROJECT_ID = AttributeKeys.PROJECT_ID;
public static final String GCE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
public static final String GCE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;
public static final String GCE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;
public static final String GCE_INSTANCE_NAME = AttributeKeys.INSTANCE_NAME;
public static final String GCE_MACHINE_TYPE = AttributeKeys.MACHINE_TYPE;

// GKE Attributes
public static final String GKE_POD_NAME = "gke_pod_name";
psx95 marked this conversation as resolved.
Show resolved Hide resolved
public static final String GKE_NAMESPACE = "gke_namespace";
public static final String GKE_CONTAINER_NAME = "gke_container_name";
public static final String GKE_CLUSTER_NAME = "gke_cluster_name";
public static final String GKE_CLUSTER_LOCATION_TYPE = "gke_cluster_location_type";
public static final String GKE_CLUSTER_LOCATION = "gke_cluster_location";
public static final String GKE_HOST_ID = AttributeKeys.INSTANCE_ID;

// GKE Location Constants
public static final String GKE_LOCATION_TYPE_ZONE = "ZONE";
public static final String GKE_LOCATION_TYPE_REGION = "REGION";

// GAE Attributes
public static final String GAE_MODULE_NAME = "gae_module_name";
public static final String GAE_APP_VERSION = "gae_app_version";
public static final String GAE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;
public static final String GAE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
public static final String GAE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;

// Google Serverless Compute Attributes
public static final String SERVERLESS_COMPUTE_NAME = "serverless_compute_name";
public static final String SERVERLESS_COMPUTE_REVISION = "serverless_compute_revision";
public static final String SERVERLESS_COMPUTE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
public static final String SERVERLESS_COMPUTE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;
public static final String SERVERLESS_COMPUTE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;

static final String PROJECT_ID = "project_id";
static final String AVAILABILITY_ZONE = "availability_zone";
static final String CLOUD_REGION = "cloud_region";
static final String INSTANCE_ID = "instance_id";
static final String INSTANCE_NAME = "instance_name";
static final String MACHINE_TYPE = "machine_type";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.google.cloud.opentelemetry.detectors;

import java.util.Map;

/** Represents a GCP specific platform on which a cloud application can run. */
public interface DetectedPlatform {
/**
* Method to retrieve the underlying compute platform on which application is running.
*
* @return the {@link GCPPlatformDetector.SupportedPlatform} representing the Google Cloud
* platform on which application is running.
*/
GCPPlatformDetector.SupportedPlatform getSupportedPlatform();

/**
* Method to retrieve the attributes associated with the compute platform on which the application
* is running as key-value pairs.
*
* @return a {@link Map} of attributes specific to the underlying compute platform.
*/
Map<String, String> getAttributes();
dashpole marked this conversation as resolved.
Show resolved Hide resolved
}
psx95 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* 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.
Expand All @@ -19,8 +19,9 @@
* Provides API to fetch environment variables. This is useful in order to create a mock class for
* testing.
*/
public interface EnvVars {
EnvVars DEFAULT_INSTANCE = System::getenv;
interface EnvironmentVariables {
/** Returns the current environment variables of the platform this is running in. */
EnvironmentVariables DEFAULT_INSTANCE = System::getenv;

/**
* Grabs the system environment variable. Returns null on failure.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* 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.
Expand Down Expand Up @@ -32,28 +32,36 @@
* https://cloud.google.com/compute/docs/storing-retrieving-metadata</a>
*/
final class GCPMetadataConfig {
private static final String DEFAULT_URL = "http://metadata.google.internal/computeMetadata/v1/";
public static final GCPMetadataConfig DEFAULT_INSTANCE = new GCPMetadataConfig(DEFAULT_URL);
static final GCPMetadataConfig DEFAULT_INSTANCE = new GCPMetadataConfig();

private static final String DEFAULT_URL = "http://metadata.google.internal/computeMetadata/v1/";
private final String url;
private final Map<String, String> cachedAttributes = new HashMap<>();

// For testing only
public GCPMetadataConfig(String url) {
this.url = url;
private GCPMetadataConfig() {
this.url = DEFAULT_URL;
}

boolean isRunningOnGcp() {
return getProjectId() != null && !getProjectId().isEmpty();
// For testing only
GCPMetadataConfig(String url) {
this.url = url;
}

// Returns null on failure to retrieve from metadata server
String getProjectId() {
return getAttribute("project/project-id");
}

// Example response: projects/640212054955/zones/australia-southeast1-a
// Returns null on failure to retrieve from metadata server
/**
* Method to extract cloud availability zone from the metadata server.
*
* <p>Example response: projects/640212054955/zones/australia-southeast1-a
*
* <p>Example zone: australia-southeast1-a
*
* @return the extracted zone from the metadata server response or null in case of failure to
* retrieve from metadata server.
*/
String getZone() {
String zone = getAttribute("instance/zone");
if (zone != null && zone.contains("/")) {
Expand All @@ -62,10 +70,14 @@ String getZone() {
return zone;
}

// Use this method only when the region cannot be parsed from the zone. Known use-cases of this
// method involve detecting region in GAE standard environment
// Example response: projects/5689182099321/regions/us-central1
// Returns null on failure to retrieve from metadata server
/**
* Use this method only when the region cannot be parsed from the zone. Known use-cases of this
* method involve detecting region in GAE standard environment.
*
* <p>Example response: projects/5689182099321/regions/us-central1.
*
* @return the retrieved region or null in case of failure to retrieve from metadata server
*/
String getRegion() {
String region = getAttribute("instance/region");
if (region != null && region.contains("/")) {
Expand All @@ -74,6 +86,27 @@ String getRegion() {
return region;
}

/**
* Use this method to parse region from zone.
*
* <p>Example region: australia-southeast1
*
* @return parsed region from the zone, if zone is not found or is invalid, this method returns
* null.
*/
String getRegionFromZone() {
String region = null;
String zone = getZone();
if (zone != null && !zone.isEmpty()) {
// Parsing required to scope up to a region
String[] splitArr = zone.split("-");
if (splitArr.length > 2) {
region = String.join("-", splitArr[0], splitArr[1]);
}
}
return region;
}

// Example response: projects/640212054955/machineTypes/e2-medium
String getMachineType() {
String machineType = getAttribute("instance/machine-type");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* 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.google.cloud.opentelemetry.detectors;

public class GCPPlatformDetector {
public static final GCPPlatformDetector DEFAULT_INSTANCE = new GCPPlatformDetector();

private final GCPMetadataConfig metadataConfig;
private final EnvironmentVariables environmentVariables;

// for testing only
GCPPlatformDetector(GCPMetadataConfig metadataConfig, EnvironmentVariables environmentVariables) {
this.metadataConfig = metadataConfig;
this.environmentVariables = environmentVariables;
}

private GCPPlatformDetector() {
this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE;
this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE;
}

/**
* Detects the GCP platform on which the application is running.
*
* @return the specific GCP platform on which the application is running.
*/
public DetectedPlatform detectPlatform() {
return generateDetectedPlatform(detectSupportedPlatform());
}

private SupportedPlatform detectSupportedPlatform() {
if (!isRunningOnGcp()) {
return SupportedPlatform.UNKNOWN_PLATFORM;
}
// Note: Order of detection matters here
if (environmentVariables.get("KUBERNETES_SERVICE_HOST") != null) {
return SupportedPlatform.GOOGLE_KUBERNETES_ENGINE;
} else if (environmentVariables.get("K_CONFIGURATION") != null
&& environmentVariables.get("FUNCTION_TARGET") == null) {
return SupportedPlatform.GOOGLE_CLOUD_RUN;
} else if (environmentVariables.get("FUNCTION_TARGET") != null) {
return SupportedPlatform.GOOGLE_CLOUD_FUNCTIONS;
} else if (environmentVariables.get("GAE_SERVICE") != null) {
return SupportedPlatform.GOOGLE_APP_ENGINE;
}
return SupportedPlatform.GOOGLE_COMPUTE_ENGINE; // default to GCE
}

private boolean isRunningOnGcp() {
return metadataConfig.getProjectId() != null && !metadataConfig.getProjectId().isEmpty();
}

private DetectedPlatform generateDetectedPlatform(SupportedPlatform platform) {
DetectedPlatform detectedPlatform;
switch (platform) {
case GOOGLE_KUBERNETES_ENGINE:
detectedPlatform = new GoogleKubernetesEngine(environmentVariables, metadataConfig);
break;
case GOOGLE_CLOUD_RUN:
detectedPlatform = new GoogleCloudRun(environmentVariables, metadataConfig);
break;
case GOOGLE_CLOUD_FUNCTIONS:
detectedPlatform = new GoogleCloudFunction(environmentVariables, metadataConfig);
break;
case GOOGLE_APP_ENGINE:
detectedPlatform = new GoogleAppEngine(environmentVariables, metadataConfig);
break;
case GOOGLE_COMPUTE_ENGINE:
detectedPlatform = new GoogleComputeEngine(metadataConfig);
break;
default:
detectedPlatform = new UnknownPlatform();
}
return detectedPlatform;
}

/**
* SupportedPlatform represents the GCP platforms that can currently be detected by the
* resource-detector.
*/
public enum SupportedPlatform {
/** Represents the Google Compute Engine platform. */
GOOGLE_COMPUTE_ENGINE,
/** Represents the Google Kubernetes Engine platform. */
GOOGLE_KUBERNETES_ENGINE,
/** Represents the Google App Engine platform. Could either be flex or standard. */
GOOGLE_APP_ENGINE,
/** Represents the Google Cloud Run platform. */
GOOGLE_CLOUD_RUN,
/** Represents the Google Cloud Functions platform. */
GOOGLE_CLOUD_FUNCTIONS,
/** Represents the case when the application is not running on GCP. */
UNKNOWN_PLATFORM,
}
}
Loading
Loading