diff --git a/source/extensions/tracers/opencensus/config.cc b/source/extensions/tracers/opencensus/config.cc index 5f9902f990a7a..537e2db13b6ec 100644 --- a/source/extensions/tracers/opencensus/config.cc +++ b/source/extensions/tracers/opencensus/config.cc @@ -18,7 +18,8 @@ OpenCensusTracerFactory::OpenCensusTracerFactory() : FactoryBase(TracerNames::ge Tracing::HttpTracerPtr OpenCensusTracerFactory::createHttpTracerTyped( const envoy::config::trace::v3::OpenCensusConfig& proto_config, Server::Instance& server) { - Tracing::DriverPtr driver = std::make_unique(proto_config, server.localInfo()); + Tracing::DriverPtr driver = + std::make_unique(proto_config, server.localInfo(), server.api()); return std::make_unique(std::move(driver), server.localInfo()); } diff --git a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc index 2b3f91d7bc35c..1d77f53440f14 100644 --- a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc +++ b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc @@ -233,10 +233,43 @@ Tracing::SpanPtr Span::spawnChild(const Tracing::Config& /*config*/, const std:: void Span::setSampled(bool sampled) { span_.AddAnnotation("setSampled", {{"sampled", sampled}}); } +class GoogleUserProjHeaderInterceptor : public grpc::experimental::Interceptor { +public: + GoogleUserProjHeaderInterceptor(const std::string& project_id) : project_id_(project_id) {} + + virtual void Intercept(grpc::experimental::InterceptorBatchMethods* methods) { + if (methods->QueryInterceptionHookPoint( + grpc::experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) { + auto* metadata_map = methods->GetSendInitialMetadata(); + if (metadata_map != nullptr) { + metadata_map->insert(std::make_pair("x-goog-user-project", project_id_)); + } + } + methods->Proceed(); + } + +private: + const std::string& project_id_; +}; + +class GoogleUserProjHeaderInterceptorFactory + : public grpc::experimental::ClientInterceptorFactoryInterface { +public: + GoogleUserProjHeaderInterceptorFactory(const std::string& project_id) : project_id_(project_id) {} + + virtual grpc::experimental::Interceptor* + CreateClientInterceptor(grpc::experimental::ClientRpcInfo*) override { + return new GoogleUserProjHeaderInterceptor(project_id_); + } + +private: + std::string project_id_; +}; + } // namespace Driver::Driver(const envoy::config::trace::v3::OpenCensusConfig& oc_config, - const LocalInfo::LocalInfo& localinfo) + const LocalInfo::LocalInfo& localinfo, Api::Api& api) : oc_config_(oc_config), local_info_(localinfo) { if (oc_config.has_trace_config()) { applyTraceConfig(oc_config.trace_config()); @@ -251,8 +284,22 @@ Driver::Driver(const envoy::config::trace::v3::OpenCensusConfig& oc_config, sts_port = port_iter->second.string_value(); } if (oc_config.stackdriver_exporter_enabled()) { + // Try get GCP project ID from node metadata. + std::string project_id; + auto platform_md_iter = node_metadata.fields().find("PLATFORM_METADATA"); + if (platform_md_iter != node_metadata.fields().end()) { + auto platform_md = platform_md_iter->second.struct_value(); + auto proj_id_iter = platform_md.fields().find("gcp_project"); + if (proj_id_iter != platform_md.fields().end()) { + project_id = proj_id_iter->second.string_value(); + } + } ::opencensus::exporters::trace::StackdriverOptions opts; - opts.project_id = oc_config.stackdriver_project_id(); + if (!oc_config.stackdriver_project_id().empty()) { + opts.project_id = oc_config.stackdriver_project_id(); + } else if (!project_id.empty()) { + opts.project_id = project_id; + } if (!oc_config.stackdriver_address().empty()) { auto channel = grpc::CreateChannel(oc_config.stackdriver_address(), grpc::InsecureChannelCredentials()); @@ -265,11 +312,17 @@ Driver::Driver(const envoy::config::trace::v3::OpenCensusConfig& oc_config, sts_options.scope = "https://www.googleapis.com/auth/cloud-platform"; auto call_creds = grpc::experimental::StsCredentials(sts_options); auto ssl_creds_options = grpc::SslCredentialsOptions(); - ssl_creds_options.pem_root_certs = "/etc/ssl/certs/ca-certificates.crt"; + ssl_creds_options.pem_root_certs = + api.fileSystem().fileReadToEnd("/etc/ssl/certs/ca-certificates.crt"); auto channel_creds = grpc::SslCredentials(ssl_creds_options); - auto channel = - ::grpc::CreateChannel("cloudtrace.googleapis.com", - grpc::CompositeChannelCredentials(channel_creds, call_creds)); + // Create an custom channel which includes an interceptor that inject user project header. + grpc::ChannelArguments args; + std::vector> creators; + creators.push_back(std::unique_ptr( + new GoogleUserProjHeaderInterceptorFactory(project_id))); + auto channel = ::grpc::experimental::CreateCustomChannelWithInterceptors( + "cloudtrace.googleapis.com", grpc::CompositeChannelCredentials(channel_creds, call_creds), + args, std::move(creators)); opts.trace_service_stub = ::google::devtools::cloudtrace::v2::TraceService::NewStub(channel); } ::opencensus::exporters::trace::StackdriverExporter::Register(std::move(opts)); diff --git a/source/extensions/tracers/opencensus/opencensus_tracer_impl.h b/source/extensions/tracers/opencensus/opencensus_tracer_impl.h index af2aec7a98041..b89b33525774e 100644 --- a/source/extensions/tracers/opencensus/opencensus_tracer_impl.h +++ b/source/extensions/tracers/opencensus/opencensus_tracer_impl.h @@ -1,6 +1,8 @@ #pragma once +#include "envoy/api/api.h" #include "envoy/config/trace/v3/trace.pb.h" +#include "envoy/config/trace/v2/trace.pb.validate.h" #include "envoy/local_info/local_info.h" #include "envoy/tracing/http_tracer.h" @@ -17,7 +19,7 @@ namespace OpenCensus { class Driver : public Tracing::Driver, Logger::Loggable { public: Driver(const envoy::config::trace::v3::OpenCensusConfig& oc_config, - const LocalInfo::LocalInfo& localinfo); + const LocalInfo::LocalInfo& localinfo, Api::Api& api); /** * Implements the abstract Driver's startSpan operation. diff --git a/test/extensions/tracers/opencensus/tracer_test.cc b/test/extensions/tracers/opencensus/tracer_test.cc index c5f990315f312..29ae264071018 100644 --- a/test/extensions/tracers/opencensus/tracer_test.cc +++ b/test/extensions/tracers/opencensus/tracer_test.cc @@ -103,7 +103,8 @@ TEST(OpenCensusTracerTest, Span) { registerSpanCatcher(); OpenCensusConfig oc_config; NiceMock local_info; - std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); + Api::ApiPtr api = Api::createApiForTest(); + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info, *api)); NiceMock config; Http::TestHeaderMapImpl request_headers{ @@ -182,6 +183,7 @@ void testIncomingHeaders( registerSpanCatcher(); OpenCensusConfig oc_config; NiceMock local_info; + Api::ApiPtr api = Api::createApiForTest(); oc_config.add_incoming_trace_context(OpenCensusConfig::NONE); oc_config.add_incoming_trace_context(OpenCensusConfig::B3); oc_config.add_incoming_trace_context(OpenCensusConfig::TRACE_CONTEXT); @@ -192,7 +194,7 @@ void testIncomingHeaders( oc_config.add_outgoing_trace_context(OpenCensusConfig::TRACE_CONTEXT); oc_config.add_outgoing_trace_context(OpenCensusConfig::GRPC_TRACE_BIN); oc_config.add_outgoing_trace_context(OpenCensusConfig::CLOUD_TRACE_CONTEXT); - std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info, *api)); NiceMock config; Http::TestHeaderMapImpl request_headers{ {":path", "/"}, @@ -279,7 +281,8 @@ namespace { int SamplerTestHelper(const OpenCensusConfig& oc_config) { registerSpanCatcher(); NiceMock local_info; - std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); + Api::ApiPtr api = Api::createApiForTest(); + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info, *api)); auto span = ::opencensus::trace::Span::StartSpan("test_span"); span.End(); // Retrieve SpanData from the OpenCensus trace exporter.