Skip to content

Commit 6289413

Browse files
committed
Move code from resource detection support library to inline
1 parent 3523ba6 commit 6289413

20 files changed

Lines changed: 1409 additions & 81 deletions

gcp-resources/build.gradle.kts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ dependencies {
1212
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
1313
api("io.opentelemetry:opentelemetry-sdk")
1414

15-
// Provides GCP resource detection support
16-
implementation("com.google.cloud.opentelemetry:detector-resources-support:0.36.0")
17-
1815
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
1916

2017
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
@@ -26,7 +23,9 @@ dependencies {
2623
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
2724

2825
testImplementation("org.mockito:mockito-core")
26+
testImplementation("org.mockito:mockito-inline")
2927
testImplementation("com.google.guava:guava")
3028

3129
testImplementation("org.junit.jupiter:junit-jupiter-api")
30+
testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.0")
3231
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.gcp.resource;
7+
8+
/**
9+
* Contains constants that act as keys for the known attributes for {@link
10+
* GcpPlatformDetector.SupportedPlatform}s.
11+
*/
12+
final class AttributeKeys {
13+
private AttributeKeys() {}
14+
15+
// GCE Attributes
16+
public static final String GCE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
17+
public static final String GCE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;
18+
public static final String GCE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;
19+
public static final String GCE_INSTANCE_NAME = AttributeKeys.INSTANCE_NAME;
20+
public static final String GCE_MACHINE_TYPE = AttributeKeys.MACHINE_TYPE;
21+
public static final String GCE_INSTANCE_HOSTNAME = "instance_hostname";
22+
23+
// GKE Attributes
24+
public static final String GKE_CLUSTER_NAME = "gke_cluster_name";
25+
public static final String GKE_CLUSTER_LOCATION_TYPE = "gke_cluster_location_type";
26+
public static final String GKE_CLUSTER_LOCATION = "gke_cluster_location";
27+
public static final String GKE_HOST_ID = AttributeKeys.INSTANCE_ID;
28+
29+
// GKE Location Constants
30+
public static final String GKE_LOCATION_TYPE_ZONE = "ZONE";
31+
public static final String GKE_LOCATION_TYPE_REGION = "REGION";
32+
33+
// GAE Attributes
34+
public static final String GAE_MODULE_NAME = "gae_module_name";
35+
public static final String GAE_APP_VERSION = "gae_app_version";
36+
public static final String GAE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;
37+
public static final String GAE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
38+
public static final String GAE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;
39+
40+
// Google Serverless Compute Attributes
41+
public static final String SERVERLESS_COMPUTE_NAME = "serverless_compute_name";
42+
public static final String SERVERLESS_COMPUTE_REVISION = "serverless_compute_revision";
43+
public static final String SERVERLESS_COMPUTE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE;
44+
public static final String SERVERLESS_COMPUTE_CLOUD_REGION = AttributeKeys.CLOUD_REGION;
45+
public static final String SERVERLESS_COMPUTE_INSTANCE_ID = AttributeKeys.INSTANCE_ID;
46+
47+
// Cloud Run Job Specific Attributes
48+
public static final String GCR_JOB_EXECUTION_KEY = "gcr_job_execution_key";
49+
public static final String GCR_JOB_TASK_INDEX = "gcr_job_task_index";
50+
51+
static final String AVAILABILITY_ZONE = "availability_zone";
52+
static final String CLOUD_REGION = "cloud_region";
53+
static final String INSTANCE_ID = "instance_id";
54+
static final String INSTANCE_NAME = "instance_name";
55+
static final String MACHINE_TYPE = "machine_type";
56+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.gcp.resource;
7+
8+
import java.util.Map;
9+
10+
/** Represents a GCP specific platform on which a cloud application can run. */
11+
interface DetectedPlatform {
12+
/**
13+
* Method to retrieve the underlying compute platform on which application is running.
14+
*
15+
* @return the {@link GcpPlatformDetector.SupportedPlatform} representing the Google Cloud
16+
* platform on which application is running.
17+
*/
18+
GcpPlatformDetector.SupportedPlatform getSupportedPlatform();
19+
20+
/**
21+
* Method to retrieve the GCP Project ID in which the GCP specific platform exists. Every valid
22+
* platform must have a GCP Project ID associated with it.
23+
*
24+
* @return the Google Cloud project ID.
25+
*/
26+
String getProjectId();
27+
28+
/**
29+
* Method to retrieve the attributes associated with the compute platform on which the application
30+
* is running as key-value pairs. The valid keys to query on this {@link Map} are specified in the
31+
* {@link AttributeKeys}.
32+
*
33+
* @return a {@link Map} of attributes specific to the underlying compute platform.
34+
*/
35+
Map<String, String> getAttributes();
36+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.gcp.resource;
7+
8+
/**
9+
* Provides API to fetch environment variables. This is useful in order to create a mock class for
10+
* testing.
11+
*/
12+
interface EnvironmentVariables {
13+
/** Returns the current environment variables of the platform this is running in. */
14+
EnvironmentVariables DEFAULT_INSTANCE = System::getenv;
15+
16+
/**
17+
* Grabs the system environment variable. Returns null on failure.
18+
*
19+
* @param key the key of the environment variable in {@code System.getenv()}
20+
* @return the value received by {@code System.getenv(key)}
21+
*/
22+
String get(String key);
23+
}

gcp-resources/src/main/java/io/opentelemetry/contrib/gcp/resource/GCPResourceProvider.java

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,30 @@
55

66
package io.opentelemetry.contrib.gcp.resource;
77

8-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GAE_APP_VERSION;
9-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GAE_AVAILABILITY_ZONE;
10-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GAE_CLOUD_REGION;
11-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GAE_INSTANCE_ID;
12-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GAE_MODULE_NAME;
13-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_AVAILABILITY_ZONE;
14-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_CLOUD_REGION;
15-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_INSTANCE_HOSTNAME;
16-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_INSTANCE_ID;
17-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_INSTANCE_NAME;
18-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCE_MACHINE_TYPE;
19-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCR_JOB_EXECUTION_KEY;
20-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GCR_JOB_TASK_INDEX;
21-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_CLUSTER_LOCATION;
22-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_CLUSTER_LOCATION_TYPE;
23-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_CLUSTER_NAME;
24-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_HOST_ID;
25-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_LOCATION_TYPE_REGION;
26-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.GKE_LOCATION_TYPE_ZONE;
27-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.SERVERLESS_COMPUTE_AVAILABILITY_ZONE;
28-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.SERVERLESS_COMPUTE_CLOUD_REGION;
29-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.SERVERLESS_COMPUTE_INSTANCE_ID;
30-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.SERVERLESS_COMPUTE_NAME;
31-
import static com.google.cloud.opentelemetry.detection.AttributeKeys.SERVERLESS_COMPUTE_REVISION;
8+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GAE_APP_VERSION;
9+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GAE_AVAILABILITY_ZONE;
10+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GAE_CLOUD_REGION;
11+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GAE_INSTANCE_ID;
12+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GAE_MODULE_NAME;
13+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_AVAILABILITY_ZONE;
14+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_CLOUD_REGION;
15+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_INSTANCE_HOSTNAME;
16+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_INSTANCE_ID;
17+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_INSTANCE_NAME;
18+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCE_MACHINE_TYPE;
19+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCR_JOB_EXECUTION_KEY;
20+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GCR_JOB_TASK_INDEX;
21+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_CLUSTER_LOCATION;
22+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_CLUSTER_LOCATION_TYPE;
23+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_CLUSTER_NAME;
24+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_HOST_ID;
25+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_LOCATION_TYPE_REGION;
26+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.GKE_LOCATION_TYPE_ZONE;
27+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.SERVERLESS_COMPUTE_AVAILABILITY_ZONE;
28+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.SERVERLESS_COMPUTE_CLOUD_REGION;
29+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.SERVERLESS_COMPUTE_INSTANCE_ID;
30+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.SERVERLESS_COMPUTE_NAME;
31+
import static io.opentelemetry.contrib.gcp.resource.AttributeKeys.SERVERLESS_COMPUTE_REVISION;
3232
import static io.opentelemetry.contrib.gcp.resource.IncubatingAttributes.CLOUD_ACCOUNT_ID;
3333
import static io.opentelemetry.contrib.gcp.resource.IncubatingAttributes.CLOUD_AVAILABILITY_ZONE;
3434
import static io.opentelemetry.contrib.gcp.resource.IncubatingAttributes.CLOUD_PLATFORM;
@@ -50,8 +50,6 @@
5050
import static io.opentelemetry.contrib.gcp.resource.IncubatingAttributes.HOST_TYPE;
5151
import static io.opentelemetry.contrib.gcp.resource.IncubatingAttributes.K8S_CLUSTER_NAME;
5252

53-
import com.google.cloud.opentelemetry.detection.DetectedPlatform;
54-
import com.google.cloud.opentelemetry.detection.GCPPlatformDetector;
5553
import io.opentelemetry.api.common.Attributes;
5654
import io.opentelemetry.api.common.AttributesBuilder;
5755
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
@@ -66,15 +64,15 @@ public class GCPResourceProvider implements ConditionalResourceProvider {
6664

6765
private static final Logger LOGGER = Logger.getLogger(GCPResourceProvider.class.getSimpleName());
6866

69-
private final GCPPlatformDetector detector;
67+
private final GcpPlatformDetector detector;
7068

7169
// for testing only
72-
GCPResourceProvider(GCPPlatformDetector detector) {
70+
GCPResourceProvider(GcpPlatformDetector detector) {
7371
this.detector = detector;
7472
}
7573

7674
public GCPResourceProvider() {
77-
this.detector = GCPPlatformDetector.DEFAULT_INSTANCE;
75+
this.detector = GcpPlatformDetector.DEFAULT_INSTANCE;
7876
}
7977

8078
@Override
@@ -91,7 +89,7 @@ public final boolean shouldApply(ConfigProperties config, Resource existing) {
9189
public Attributes getAttributes() {
9290
DetectedPlatform detectedPlatform = detector.detectPlatform();
9391
if (detectedPlatform.getSupportedPlatform()
94-
== GCPPlatformDetector.SupportedPlatform.UNKNOWN_PLATFORM) {
92+
== GcpPlatformDetector.SupportedPlatform.UNKNOWN_PLATFORM) {
9593
return Attributes.empty();
9694
}
9795

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.gcp.resource;
7+
8+
import java.io.BufferedReader;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.io.InputStreamReader;
12+
import java.net.HttpURLConnection;
13+
import java.net.URL;
14+
import java.nio.charset.StandardCharsets;
15+
import java.util.Map;
16+
import java.util.concurrent.ConcurrentHashMap;
17+
import javax.annotation.Nullable;
18+
19+
/**
20+
* Retrieves Google Cloud project-id and a limited set of instance attributes from Metadata server.
21+
*
22+
* @see <a href= "https://cloud.google.com/compute/docs/storing-retrieving-metadata">
23+
* https://cloud.google.com/compute/docs/storing-retrieving-metadata</a>
24+
*/
25+
final class GcpMetadataConfig {
26+
static final GcpMetadataConfig DEFAULT_INSTANCE = new GcpMetadataConfig();
27+
28+
private static final String DEFAULT_URL = "http://metadata.google.internal/computeMetadata/v1/";
29+
private final String url;
30+
private final Map<String, String> cachedAttributes = new ConcurrentHashMap<>();
31+
32+
private GcpMetadataConfig() {
33+
this.url = DEFAULT_URL;
34+
}
35+
36+
// For testing only
37+
GcpMetadataConfig(String url) {
38+
this.url = url;
39+
}
40+
41+
// Returns null on failure to retrieve from metadata server
42+
String getProjectId() {
43+
return getAttribute("project/project-id");
44+
}
45+
46+
/**
47+
* Method to extract cloud availability zone from the metadata server.
48+
*
49+
* <p>Example response: projects/640212054955/zones/australia-southeast1-a
50+
*
51+
* <p>Example zone: australia-southeast1-a
52+
*
53+
* @return the extracted zone from the metadata server response or null in case of failure to
54+
* retrieve from metadata server.
55+
*/
56+
String getZone() {
57+
String zone = getAttribute("instance/zone");
58+
if (zone != null && zone.contains("/")) {
59+
zone = zone.substring(zone.lastIndexOf('/') + 1);
60+
}
61+
return zone;
62+
}
63+
64+
/**
65+
* Use this method only when the region cannot be parsed from the zone. Known use-cases of this
66+
* method involve detecting region in GAE standard environment.
67+
*
68+
* <p>Example response: projects/5689182099321/regions/us-central1.
69+
*
70+
* @return the retrieved region or null in case of failure to retrieve from metadata server
71+
*/
72+
String getRegion() {
73+
String region = getAttribute("instance/region");
74+
if (region != null && region.contains("/")) {
75+
region = region.substring(region.lastIndexOf('/') + 1);
76+
}
77+
return region;
78+
}
79+
80+
/**
81+
* Use this method to parse region from zone.
82+
*
83+
* <p>Example region: australia-southeast1
84+
*
85+
* @return parsed region from the zone, if zone is not found or is invalid, this method returns
86+
* null.
87+
*/
88+
@Nullable
89+
String getRegionFromZone() {
90+
String region = null;
91+
String zone = getZone();
92+
if (zone != null && !zone.isEmpty()) {
93+
// Parsing required to scope up to a region
94+
String[] splitArr = zone.split("-");
95+
if (splitArr.length > 2) {
96+
region = String.join("-", splitArr[0], splitArr[1]);
97+
}
98+
}
99+
return region;
100+
}
101+
102+
// Example response: projects/640212054955/machineTypes/e2-medium
103+
String getMachineType() {
104+
String machineType = getAttribute("instance/machine-type");
105+
if (machineType != null && machineType.contains("/")) {
106+
machineType = machineType.substring(machineType.lastIndexOf('/') + 1);
107+
}
108+
return machineType;
109+
}
110+
111+
// Returns null on failure to retrieve from metadata server
112+
String getInstanceId() {
113+
return getAttribute("instance/id");
114+
}
115+
116+
// Returns null on failure to retrieve from metadata server
117+
String getClusterName() {
118+
return getAttribute("instance/attributes/cluster-name");
119+
}
120+
121+
// Returns null on failure to retrieve from metadata server
122+
String getClusterLocation() {
123+
return getAttribute("instance/attributes/cluster-location");
124+
}
125+
126+
// Returns null on failure to retrieve from metadata server
127+
String getInstanceHostName() {
128+
return getAttribute("instance/hostname");
129+
}
130+
131+
// Returns null on failure to retrieve from metadata server
132+
String getInstanceName() {
133+
return getAttribute("instance/name");
134+
}
135+
136+
// Returns null on failure to retrieve from metadata server
137+
private String getAttribute(String attributeName) {
138+
return cachedAttributes.computeIfAbsent(attributeName, this::fetchAttribute);
139+
}
140+
141+
// Return the attribute received at <attributeName> relative path or null on
142+
// failure
143+
@Nullable
144+
private String fetchAttribute(String attributeName) {
145+
try {
146+
URL url = new URL(this.url + attributeName);
147+
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
148+
connection.setRequestProperty("Metadata-Flavor", "Google");
149+
if (connection.getResponseCode() == 200
150+
&& "Google".equals(connection.getHeaderField("Metadata-Flavor"))) {
151+
InputStream input = connection.getInputStream();
152+
try (BufferedReader reader =
153+
new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
154+
return reader.readLine();
155+
}
156+
}
157+
} catch (IOException ignore) {
158+
// ignore
159+
}
160+
return null;
161+
}
162+
}

0 commit comments

Comments
 (0)