Skip to content

Commit 352828e

Browse files
Try resolving GCP_PROJECT with ServiceOptions if not provided
1 parent 54e054e commit 352828e

File tree

4 files changed

+78
-11
lines changed

4 files changed

+78
-11
lines changed

gcp-auth-extension/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@ The extension can be configured either by environment variables or system proper
3434

3535
Here is a list of required and optional configuration available for the extension:
3636

37-
#### Required Config
37+
#### Optional Config
3838

3939
- `GOOGLE_CLOUD_PROJECT`: Environment variable that represents the Google Cloud Project ID to which the telemetry needs to be exported.
4040

4141
- Can also be configured using `google.cloud.project` system property.
42-
- This is a required option, the agent configuration will fail if this option is not set.
43-
44-
#### Optional Config
42+
- If neither of these options are set, the extension will attempt to use the `ServiceOptions` class from `google-cloud-core` to determine the project ID. The `ServiceOptions` has a comprehensive logic to determine the project ID, which includes checking the environment variable `GOOGLE_CLOUD_PROJECT`, the `gcloud` configuration, the local metadata server, and the `GOOGLE_APPLICATION_CREDENTIALS` file.
43+
- **Important Note**: The agent configuration will fail if this option is not set or cannot be inferred.
4544

4645
- `GOOGLE_CLOUD_QUOTA_PROJECT`: Environment variable that represents the Google Cloud Quota Project ID which will be charged for the GCP API usage. To learn more about a *quota project*, see the [Quota project overview](https://cloud.google.com/docs/quotas/quota-project) page. Additional details about configuring the *quota project* can be found on the [Set the quota project](https://cloud.google.com/docs/quotas/set-quota-project) page.
4746

gcp-auth-extension/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ dependencies {
2525

2626
// Only dependencies added to `implementation` configuration will be picked up by Shadow plugin
2727
implementation("com.google.auth:google-auth-library-oauth2-http:1.37.1")
28+
implementation("com.google.cloud:google-cloud-core:2.58.1")
2829

2930
// Test dependencies
3031
testCompileOnly("com.google.auto.service:auto-service-annotations")

gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.google.auth.oauth2.GoogleCredentials;
99
import com.google.auto.service.AutoService;
10+
import com.google.cloud.ServiceOptions;
1011
import io.opentelemetry.api.common.AttributeKey;
1112
import io.opentelemetry.api.common.Attributes;
1213
import io.opentelemetry.contrib.gcp.auth.GoogleAuthException.Reason;
@@ -21,6 +22,7 @@
2122
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
2223
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
2324
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
25+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
2426
import io.opentelemetry.sdk.metrics.export.MetricExporter;
2527
import io.opentelemetry.sdk.resources.Resource;
2628
import io.opentelemetry.sdk.trace.export.SpanExporter;
@@ -109,7 +111,11 @@ public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) {
109111
.addMetricExporterCustomizer(
110112
(metricExporter, configProperties) ->
111113
customizeMetricExporter(metricExporter, credentials, configProperties))
112-
.addResourceCustomizer(GcpAuthAutoConfigurationCustomizerProvider::customizeResource);
114+
.addResourceCustomizer((resource, configProperties) -> {
115+
String gcpProjectId = getGoogleProjectId(configProperties);
116+
117+
return customizeResource(resource, gcpProjectId);
118+
});
113119
}
114120

115121
@Override
@@ -227,12 +233,33 @@ private static Map<String, String> getRequiredHeaderMap(
227233
}
228234

229235
// Updates the current resource with the attributes required for ingesting OTLP data on GCP.
230-
private static Resource customizeResource(Resource resource, ConfigProperties configProperties) {
231-
String gcpProjectId =
232-
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties);
233-
Resource res =
234-
Resource.create(
235-
Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), gcpProjectId));
236+
private static Resource customizeResource(Resource resource, String gcpProjectId) {
237+
Resource res = Resource.create(
238+
Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), gcpProjectId));
236239
return resource.merge(res);
237240
}
241+
242+
/**
243+
* Retrieves the Google Cloud Project ID from the configuration properties, falling back to
244+
* google-cloud-core's ServiceOptions project ID resolution if not explicitly set.
245+
*
246+
* @param configProperties The configuration properties containing the GCP project ID.
247+
* @return The Google Cloud Project ID.
248+
*/
249+
@Nonnull
250+
static String getGoogleProjectId(ConfigProperties configProperties) {
251+
String googleProjectId = ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValueWithFallback(
252+
configProperties,
253+
ServiceOptions::getDefaultProjectId);
254+
255+
if (googleProjectId == null || googleProjectId.isEmpty()) {
256+
throw new ConfigurationException(String.format(
257+
"GCP Authentication Extension not configured properly: %s not configured. Configure it by exporting environment variable %s or system property %s",
258+
ConfigurableOption.GOOGLE_CLOUD_PROJECT,
259+
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getEnvironmentVariable(),
260+
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty()));
261+
}
262+
263+
return googleProjectId;
264+
}
238265
}

gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
4040
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
4141
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
42+
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
4243
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
4344
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
4445
import io.opentelemetry.sdk.common.CompletableResultCode;
@@ -538,6 +539,45 @@ public void testTargetSignalsBehavior(TargetSignalBehavior testCase) {
538539
}
539540
}
540541

542+
@Test
543+
void testThrowsExceptionIfGoogleProjectIsNotFound() {
544+
// Clear the system property to ensure it does not interfere with the test
545+
System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
546+
System.clearProperty("GOOGLE_CLOUD_PROJECT");
547+
548+
DefaultConfigProperties configProperties = DefaultConfigProperties.create(
549+
Collections.emptyMap(), Mockito.mock(ComponentLoader.class));
550+
551+
assertThrows(
552+
ConfigurationException.class,
553+
() -> GcpAuthAutoConfigurationCustomizerProvider.getGoogleProjectId(configProperties));
554+
}
555+
556+
@Test
557+
void testResolveGoogleProjectIdFromSystemProperty() {
558+
System.setProperty(
559+
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
560+
561+
DefaultConfigProperties configProperties = DefaultConfigProperties.create(
562+
Collections.emptyMap(), Mockito.mock(ComponentLoader.class));
563+
564+
assertEquals(DUMMY_GCP_RESOURCE_PROJECT_ID, GcpAuthAutoConfigurationCustomizerProvider.getGoogleProjectId(configProperties));
565+
}
566+
567+
@Test
568+
void testResolveGoogleProjectIdFromServiceOptions() {
569+
// Clear the system property to ensure it does not interfere with the test
570+
System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
571+
// Property that the extension expects is google.cloud.project, ServiceOptions works with
572+
// GOOGLE_CLOUD_PROJECT, so this will highlight the fallback to ServiceOptions
573+
System.setProperty("GOOGLE_CLOUD_PROJECT", DUMMY_GCP_RESOURCE_PROJECT_ID);
574+
575+
DefaultConfigProperties configProperties = DefaultConfigProperties.create(
576+
Collections.emptyMap(), Mockito.mock(ComponentLoader.class));
577+
578+
assertEquals(DUMMY_GCP_RESOURCE_PROJECT_ID, GcpAuthAutoConfigurationCustomizerProvider.getGoogleProjectId(configProperties));
579+
}
580+
541581
/** Test cases specifying expected behavior for GOOGLE_OTEL_AUTH_TARGET_SIGNALS */
542582
private static Stream<Arguments> provideTargetSignalBehaviorTestCases() {
543583
return Stream.of(

0 commit comments

Comments
 (0)