fluent-plugin-google-cloud 0.8.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97dc07c8c96a6f2901e76e22b62da38e809a843591df62536cfeddba7311775c
4
- data.tar.gz: 4ae7ec58daa1232a7c9a4c8d7462da636801059c21d3e958e305432133bb267b
3
+ metadata.gz: fcb1205d0b6d5f6043f92e06e092a071b34904dc4c02f6860ada3e47714eb840
4
+ data.tar.gz: 4e7571c46da5eaf1ab6c7a53ea49b7b9fd2e1e71756837ddc22d67d700e70c7a
5
5
  SHA512:
6
- metadata.gz: '089da19a00151839f4c0cd037cd446e8a34591a0cb739aa658d7aa1364d582ba236ce5a5c0433e84660b18410cda81bbc166596486f530cd8c0c302513f26e57'
7
- data.tar.gz: 2ec8ca875f52f62bec8003cd458cf3b009061faf8c72965f3d9d4ae2b2b09be00c223a673013ae10750ab7bfff20b30b31a3d6af3f2be62d2f310a9040aea9f9
6
+ metadata.gz: f649b399e71371b43585bc23d74c0d21ba909201ffd648d03fa3668692560f10e5cf6972a30ce05c369742a6c6227d7a0dd2b0d4b9cfe21301835110a1b928d2
7
+ data.tar.gz: 59508e973cede65ed3e5db26fa0ecca549492bbb000b8df3eb0ec53d0eab75c55caceca7d30486e74bfc45788728338da995f699c73824bc4d489a4b9ab0e521
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-google-cloud (0.8.5)
5
- fluentd (= 1.7.4)
4
+ fluent-plugin-google-cloud (0.10.0)
5
+ fluentd (= 1.11.2)
6
6
  google-api-client (= 0.30.8)
7
7
  google-cloud-logging (= 1.6.6)
8
- google-protobuf (= 3.9.0)
8
+ google-protobuf (= 3.12.2)
9
9
  googleapis-common-protos (= 1.3.9)
10
10
  googleauth (= 0.9.0)
11
- grpc (= 1.22.0)
11
+ grpc (= 1.30.2)
12
12
  json (= 2.2.0)
13
13
  opencensus (= 0.5.0)
14
14
  opencensus-stackdriver (= 0.3.2)
@@ -18,8 +18,8 @@ GEM
18
18
  specs:
19
19
  addressable (2.7.0)
20
20
  public_suffix (>= 2.0.2, < 5.0)
21
- ast (2.4.0)
22
- concurrent-ruby (1.1.6)
21
+ ast (2.4.1)
22
+ concurrent-ruby (1.1.7)
23
23
  cool.io (1.6.0)
24
24
  coveralls (0.8.23)
25
25
  json (>= 1.8, < 3)
@@ -29,23 +29,27 @@ GEM
29
29
  tins (~> 1.6)
30
30
  crack (0.4.3)
31
31
  safe_yaml (~> 1.0.0)
32
- declarative (0.0.10)
32
+ declarative (0.0.20)
33
33
  declarative-option (0.1.0)
34
- dig_rb (1.0.1)
35
34
  docile (1.3.2)
36
35
  faraday (0.17.3)
37
36
  multipart-post (>= 1.2, < 3)
38
- fluentd (1.7.4)
37
+ fluentd (1.11.2)
39
38
  cool.io (>= 1.4.5, < 2.0.0)
40
- dig_rb (~> 1.0.0)
41
39
  http_parser.rb (>= 0.5.1, < 0.7.0)
42
- msgpack (>= 1.2.0, < 2.0.0)
40
+ msgpack (>= 1.3.1, < 2.0.0)
43
41
  serverengine (>= 2.0.4, < 3.0.0)
44
42
  sigdump (~> 0.2.2)
45
43
  strptime (>= 0.2.2, < 1.0.0)
46
- tzinfo (~> 2.0)
44
+ tzinfo (>= 1.0, < 3.0)
47
45
  tzinfo-data (~> 1.0)
48
46
  yajl-ruby (~> 1.0)
47
+ gapic-common (0.3.4)
48
+ google-protobuf (~> 3.12, >= 3.12.2)
49
+ googleapis-common-protos (>= 1.3.9, < 2.0)
50
+ googleapis-common-protos-types (>= 1.0.4, < 2.0)
51
+ googleauth (~> 0.9)
52
+ grpc (~> 1.25)
49
53
  google-api-client (0.30.8)
50
54
  addressable (~> 2.5, >= 2.5.1)
51
55
  googleauth (>= 0.5, < 0.10.0)
@@ -57,36 +61,44 @@ GEM
57
61
  google-cloud-core (1.5.0)
58
62
  google-cloud-env (~> 1.0)
59
63
  google-cloud-errors (~> 1.0)
60
- google-cloud-env (1.3.1)
64
+ google-cloud-env (1.3.3)
61
65
  faraday (>= 0.17.3, < 2.0)
62
- google-cloud-errors (1.0.0)
66
+ google-cloud-errors (1.0.1)
63
67
  google-cloud-logging (1.6.6)
64
68
  concurrent-ruby (~> 1.1)
65
69
  google-cloud-core (~> 1.2)
66
70
  google-gax (~> 1.7)
67
71
  googleapis-common-protos-types (>= 1.0.2)
68
72
  stackdriver-core (~> 1.3)
69
- google-cloud-monitoring (0.32.0)
70
- google-gax (~> 1.7)
71
- googleapis-common-protos-types (>= 1.0.2)
72
- google-cloud-trace (0.35.0)
73
+ google-cloud-monitoring (0.38.0)
74
+ google-gax (~> 1.8)
75
+ googleapis-common-protos (>= 1.3.9, < 2.0)
76
+ googleapis-common-protos-types (>= 1.0.4, < 2.0)
77
+ google-cloud-trace (0.40.0)
73
78
  concurrent-ruby (~> 1.1)
74
- google-cloud-core (~> 1.2)
75
- google-gax (~> 1.7)
79
+ google-cloud-core (~> 1.5)
80
+ google-cloud-trace-v1 (~> 0.0)
81
+ google-cloud-trace-v2 (~> 0.0)
76
82
  stackdriver-core (~> 1.3)
77
- google-gax (1.7.1)
78
- google-protobuf (~> 3.2)
79
- googleapis-common-protos (>= 1.3.5, < 2.0)
80
- googleauth (>= 0.6.2, < 0.10.0)
81
- grpc (>= 1.7.2, < 2.0)
83
+ google-cloud-trace-v1 (0.1.2)
84
+ gapic-common (~> 0.3)
85
+ google-cloud-errors (~> 1.0)
86
+ google-cloud-trace-v2 (0.1.2)
87
+ gapic-common (~> 0.3)
88
+ google-cloud-errors (~> 1.0)
89
+ google-gax (1.8.1)
90
+ google-protobuf (~> 3.9)
91
+ googleapis-common-protos (>= 1.3.9, < 2.0)
92
+ googleauth (~> 0.9)
93
+ grpc (~> 1.24)
82
94
  rly (~> 0.2.3)
83
- google-protobuf (3.9.0)
95
+ google-protobuf (3.12.2)
84
96
  googleapis-common-protos (1.3.9)
85
97
  google-protobuf (~> 3.0)
86
98
  googleapis-common-protos-types (~> 1.0)
87
99
  grpc (~> 1.0)
88
- googleapis-common-protos-types (1.0.4)
89
- google-protobuf (~> 3.0)
100
+ googleapis-common-protos-types (1.0.5)
101
+ google-protobuf (~> 3.11)
90
102
  googleauth (0.9.0)
91
103
  faraday (~> 0.12)
92
104
  jwt (>= 1.4, < 3.0)
@@ -94,8 +106,8 @@ GEM
94
106
  multi_json (~> 1.11)
95
107
  os (>= 0.9, < 2.0)
96
108
  signet (~> 0.7)
97
- grpc (1.22.0)
98
- google-protobuf (~> 3.8)
109
+ grpc (1.30.2)
110
+ google-protobuf (~> 3.12)
99
111
  googleapis-common-protos-types (~> 1.0)
100
112
  hashdiff (1.0.1)
101
113
  http_parser.rb (0.6.0)
@@ -108,7 +120,7 @@ GEM
108
120
  mocha (1.9.0)
109
121
  metaclass (~> 0.0.1)
110
122
  msgpack (1.3.3)
111
- multi_json (1.14.1)
123
+ multi_json (1.15.0)
112
124
  multipart-post (2.1.1)
113
125
  opencensus (0.5.0)
114
126
  opencensus-stackdriver (0.3.2)
@@ -116,9 +128,9 @@ GEM
116
128
  google-cloud-monitoring (~> 0.32)
117
129
  google-cloud-trace (~> 0.35)
118
130
  opencensus (~> 0.5)
119
- os (1.1.0)
120
- parser (2.7.1.2)
121
- ast (~> 2.4.0)
131
+ os (1.1.1)
132
+ parser (2.7.1.4)
133
+ ast (~> 2.4.1)
122
134
  power_assert (1.2.0)
123
135
  powerpack (0.1.2)
124
136
  prometheus-client (0.9.0)
@@ -164,7 +176,7 @@ GEM
164
176
  test-unit (3.3.3)
165
177
  power_assert
166
178
  thor (1.0.1)
167
- tins (1.24.1)
179
+ tins (1.25.0)
168
180
  sync
169
181
  tzinfo (2.0.2)
170
182
  concurrent-ruby (~> 1.0)
@@ -10,7 +10,7 @@ eos
10
10
  gem.homepage =
11
11
  'https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud'
12
12
  gem.license = 'Apache-2.0'
13
- gem.version = '0.8.5'
13
+ gem.version = '0.10.0'
14
14
  gem.authors = ['Stackdriver Agents Team']
15
15
  gem.email = ['stackdriver-agents@google.com']
16
16
  gem.required_ruby_version = Gem::Requirement.new('>= 2.2')
@@ -19,13 +19,13 @@ eos
19
19
  gem.test_files = gem.files.grep(/^(test)/)
20
20
  gem.require_paths = ['lib']
21
21
 
22
- gem.add_runtime_dependency 'fluentd', '1.7.4'
22
+ gem.add_runtime_dependency 'fluentd', '1.11.2'
23
23
  gem.add_runtime_dependency 'googleapis-common-protos', '1.3.9'
24
24
  gem.add_runtime_dependency 'googleauth', '0.9.0'
25
25
  gem.add_runtime_dependency 'google-api-client', '0.30.8'
26
26
  gem.add_runtime_dependency 'google-cloud-logging', '1.6.6'
27
- gem.add_runtime_dependency 'google-protobuf', '3.9.0'
28
- gem.add_runtime_dependency 'grpc', '1.22.0'
27
+ gem.add_runtime_dependency 'google-protobuf', '3.12.2'
28
+ gem.add_runtime_dependency 'grpc', '1.30.2'
29
29
  gem.add_runtime_dependency 'json', '2.2.0'
30
30
  gem.add_runtime_dependency 'opencensus', '0.5.0'
31
31
  gem.add_runtime_dependency 'opencensus-stackdriver', '0.3.2'
@@ -0,0 +1,386 @@
1
+ # Copyright 2020 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Common
16
+ # Constants for service names, resource types and etc.
17
+ module ServiceConstants
18
+ APPENGINE_CONSTANTS = {
19
+ service: 'appengine.googleapis.com',
20
+ resource_type: 'gae_app',
21
+ metadata_attributes: %w(gae_backend_name gae_backend_version)
22
+ }.freeze
23
+ COMPUTE_CONSTANTS = {
24
+ service: 'compute.googleapis.com',
25
+ resource_type: 'gce_instance'
26
+ }.freeze
27
+ GKE_CONSTANTS = {
28
+ service: 'container.googleapis.com',
29
+ resource_type: 'gke_container',
30
+ extra_resource_labels: %w(namespace_id pod_id container_name),
31
+ extra_common_labels: %w(namespace_name pod_name),
32
+ metadata_attributes: %w(cluster-name cluster-location),
33
+ stream_severity_map: {
34
+ 'stdout' => 'INFO',
35
+ 'stderr' => 'ERROR'
36
+ }
37
+ }.freeze
38
+ K8S_CONTAINER_CONSTANTS = {
39
+ resource_type: 'k8s_container'
40
+ }.freeze
41
+ K8S_POD_CONSTANTS = {
42
+ resource_type: 'k8s_pod'
43
+ }.freeze
44
+ K8S_NODE_CONSTANTS = {
45
+ resource_type: 'k8s_node'
46
+ }.freeze
47
+ DATAFLOW_CONSTANTS = {
48
+ service: 'dataflow.googleapis.com',
49
+ resource_type: 'dataflow_step',
50
+ extra_resource_labels: %w(region job_name job_id step_id)
51
+ }.freeze
52
+ DATAPROC_CONSTANTS = {
53
+ service: 'cluster.dataproc.googleapis.com',
54
+ resource_type: 'cloud_dataproc_cluster',
55
+ metadata_attributes: %w(dataproc-cluster-uuid dataproc-cluster-name)
56
+ }.freeze
57
+ EC2_CONSTANTS = {
58
+ service: 'ec2.amazonaws.com',
59
+ resource_type: 'aws_ec2_instance'
60
+ }.freeze
61
+ ML_CONSTANTS = {
62
+ service: 'ml.googleapis.com',
63
+ resource_type: 'ml_job',
64
+ extra_resource_labels: %w(job_id task_name)
65
+ }.freeze
66
+
67
+ # The map between a subservice name and a resource type.
68
+ SUBSERVICE_MAP =
69
+ [APPENGINE_CONSTANTS, GKE_CONSTANTS, DATAFLOW_CONSTANTS,
70
+ DATAPROC_CONSTANTS, ML_CONSTANTS]
71
+ .map { |consts| [consts[:service], consts[:resource_type]] }.to_h
72
+ # Default back to GCE if invalid value is detected.
73
+ SUBSERVICE_MAP.default = COMPUTE_CONSTANTS[:resource_type]
74
+ SUBSERVICE_MAP.freeze
75
+
76
+ # The map between a resource type and expected subservice attributes.
77
+ SUBSERVICE_METADATA_ATTRIBUTES =
78
+ [APPENGINE_CONSTANTS, GKE_CONSTANTS, DATAPROC_CONSTANTS].map do |consts|
79
+ [consts[:resource_type], consts[:metadata_attributes].to_set]
80
+ end.to_h.freeze
81
+ end
82
+
83
+ # Name of the the Google cloud logging write scope.
84
+ LOGGING_SCOPE = 'https://www.googleapis.com/auth/logging.write'.freeze
85
+
86
+ # Address of the metadata service.
87
+ METADATA_SERVICE_ADDR = '169.254.169.254'.freeze
88
+
89
+ # "enum" of Platform values
90
+ module Platform
91
+ OTHER = 0 # Other/unkown platform
92
+ GCE = 1 # Google Compute Engine
93
+ EC2 = 2 # Amazon EC2
94
+ end
95
+
96
+ # Utilities for managing the resource used when writing to the
97
+ # Google API.
98
+ class Utils
99
+ include Common::ServiceConstants
100
+
101
+ def initialize(log)
102
+ @log = log
103
+ end
104
+
105
+ # Determine what platform we are running on by consulting the metadata
106
+ # service (unless the user has explicitly disabled using that).
107
+ def detect_platform(use_metadata_service)
108
+ unless use_metadata_service
109
+ @log.info 'use_metadata_service is false; not detecting platform'
110
+ return Platform::OTHER
111
+ end
112
+
113
+ begin
114
+ open('http://' + METADATA_SERVICE_ADDR, proxy: false) do |f|
115
+ if f.meta['metadata-flavor'] == 'Google'
116
+ @log.info 'Detected GCE platform'
117
+ return Platform::GCE
118
+ end
119
+ if f.meta['server'] == 'EC2ws'
120
+ @log.info 'Detected EC2 platform'
121
+ return Platform::EC2
122
+ end
123
+ end
124
+ rescue StandardError => e
125
+ @log.error 'Failed to access metadata service: ', error: e
126
+ end
127
+
128
+ @log.info 'Unable to determine platform'
129
+ Platform::OTHER
130
+ end
131
+
132
+ def fetch_gce_metadata(platform, metadata_path)
133
+ raise "Called fetch_gce_metadata with platform=#{platform}" unless
134
+ platform == Platform::GCE
135
+ # See https://cloud.google.com/compute/docs/metadata
136
+ open('http://' + METADATA_SERVICE_ADDR + '/computeMetadata/v1/' +
137
+ metadata_path, 'Metadata-Flavor' => 'Google', :proxy => false,
138
+ &:read)
139
+ end
140
+
141
+ # EC2 Metadata server returns everything in one call. Store it after the
142
+ # first fetch to avoid making multiple calls.
143
+ def ec2_metadata(platform)
144
+ raise "Called ec2_metadata with platform=#{platform}" unless
145
+ platform == Platform::EC2
146
+ unless @ec2_metadata
147
+ # See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
148
+ open('http://' + METADATA_SERVICE_ADDR +
149
+ '/latest/dynamic/instance-identity/document', proxy: false) do |f|
150
+ contents = f.read
151
+ @ec2_metadata = JSON.parse(contents)
152
+ end
153
+ end
154
+
155
+ @ec2_metadata
156
+ end
157
+
158
+ # Check required variables like @project_id, @vm_id, @vm_name and @zone.
159
+ def check_required_metadata_variables(platform, project_id, zone, vm_id)
160
+ missing = []
161
+ missing << 'project_id' unless project_id
162
+ if platform != Platform::OTHER
163
+ missing << 'zone' unless zone
164
+ missing << 'vm_id' unless vm_id
165
+ end
166
+ return if missing.empty?
167
+ raise Fluent::ConfigError,
168
+ "Unable to obtain metadata parameters: #{missing.join(' ')}"
169
+ end
170
+
171
+ # 1. Return the value if it is explicitly set in the config already.
172
+ # 2. If not, try to retrieve it by calling metadata server directly.
173
+ # 3. If still not set, try to obtain it from the credentials.
174
+ def get_project_id(platform, project_id)
175
+ project_id ||= CredentialsInfo.project_id
176
+ project_id ||= fetch_gce_metadata(platform, 'project/project-id') if
177
+ platform == Platform::GCE
178
+ project_id
179
+ end
180
+
181
+ # 1. Return the value if it is explicitly set in the config already.
182
+ # 2. If not, try to retrieve it by calling metadata servers directly.
183
+ def get_vm_id(platform, vm_id)
184
+ vm_id ||= fetch_gce_metadata(platform, 'instance/id') if
185
+ platform == Platform::GCE
186
+ vm_id ||= ec2_metadata(platform)['instanceId'] if
187
+ platform == Platform::EC2
188
+ vm_id
189
+ rescue StandardError => e
190
+ @log.error 'Failed to obtain vm_id: ', error: e
191
+ end
192
+
193
+ # 1. Return the value if it is explicitly set in the config already.
194
+ # 2. If not, try to retrieve it locally.
195
+ def get_vm_name(vm_name)
196
+ vm_name ||= Socket.gethostname
197
+ vm_name
198
+ rescue StandardError => e
199
+ @log.error 'Failed to obtain vm name: ', error: e
200
+ end
201
+
202
+ # 1. Return the value if it is explicitly set in the config already.
203
+ # 2. If not, try to retrieve it locally.
204
+ def get_location(platform, zone, use_aws_availability_zone)
205
+ # Response format: "projects/<number>/zones/<zone>"
206
+ zone ||= fetch_gce_metadata(platform,
207
+ 'instance/zone').rpartition('/')[2] if
208
+ platform == Platform::GCE
209
+ aws_location_key = if use_aws_availability_zone
210
+ 'availabilityZone'
211
+ else
212
+ 'region'
213
+ end
214
+ zone ||= 'aws:' + ec2_metadata(platform)[aws_location_key] if
215
+ platform == Platform::EC2 &&
216
+ ec2_metadata(platform).key?(aws_location_key)
217
+ zone
218
+ rescue StandardError => e
219
+ @log.error 'Failed to obtain location: ', error: e
220
+ end
221
+
222
+ # Create a monitored resource from type and labels.
223
+ def create_monitored_resource(type, labels)
224
+ Google::Apis::LoggingV2::MonitoredResource.new(
225
+ type: type, labels: labels.to_h)
226
+ end
227
+
228
+ # Retrieve monitored resource via the legacy way.
229
+ #
230
+ # Note: This is just a failover plan if we fail to get metadata from
231
+ # Metadata Agent. Thus it should be equivalent to what Metadata Agent
232
+ # returns.
233
+ def determine_agent_level_monitored_resource_via_legacy(
234
+ platform, subservice_name, detect_subservice, vm_id, zone)
235
+ resource_type = determine_agent_level_monitored_resource_type(
236
+ platform, subservice_name, detect_subservice)
237
+ create_monitored_resource(
238
+ resource_type,
239
+ determine_agent_level_monitored_resource_labels(
240
+ platform, resource_type, vm_id, zone))
241
+ end
242
+
243
+ # Determine agent level monitored resource type.
244
+ def determine_agent_level_monitored_resource_type(
245
+ platform, subservice_name, detect_subservice)
246
+ case platform
247
+ when Platform::OTHER
248
+ # Unknown platform will be defaulted to GCE instance.
249
+ return COMPUTE_CONSTANTS[:resource_type]
250
+
251
+ when Platform::EC2
252
+ return EC2_CONSTANTS[:resource_type]
253
+
254
+ when Platform::GCE
255
+ # Resource types determined by subservice_name config.
256
+ return SUBSERVICE_MAP[subservice_name] if subservice_name
257
+
258
+ # Resource types determined by detect_subservice config.
259
+ if detect_subservice
260
+ begin
261
+ attributes = fetch_gce_metadata(platform,
262
+ 'instance/attributes/').split.to_set
263
+ SUBSERVICE_METADATA_ATTRIBUTES.each do |resource_type, expected|
264
+ return resource_type if attributes.superset?(expected)
265
+ end
266
+ rescue StandardError => e
267
+ @log.error 'Failed to detect subservice: ', error: e
268
+ end
269
+ end
270
+
271
+ # GCE instance.
272
+ return COMPUTE_CONSTANTS[:resource_type]
273
+ end
274
+ end
275
+
276
+ # Determine agent level monitored resource labels based on the resource
277
+ # type. Each resource type has its own labels that need to be filled in.
278
+ def determine_agent_level_monitored_resource_labels(
279
+ platform, type, vm_id, zone)
280
+ case type
281
+ # GAE app.
282
+ when APPENGINE_CONSTANTS[:resource_type]
283
+ return {
284
+ 'module_id' =>
285
+ fetch_gce_metadata(platform,
286
+ 'instance/attributes/gae_backend_name'),
287
+ 'version_id' =>
288
+ fetch_gce_metadata(platform,
289
+ 'instance/attributes/gae_backend_version')
290
+ }
291
+
292
+ # GCE.
293
+ when COMPUTE_CONSTANTS[:resource_type]
294
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
295
+ unless vm_id && zone
296
+ return {
297
+ 'instance_id' => vm_id,
298
+ 'zone' => zone
299
+ }
300
+
301
+ # GKE container.
302
+ when GKE_CONSTANTS[:resource_type]
303
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
304
+ unless vm_id && zone
305
+ return {
306
+ 'instance_id' => vm_id,
307
+ 'zone' => zone,
308
+ 'cluster_name' =>
309
+ fetch_gce_metadata(platform, 'instance/attributes/cluster-name')
310
+ }
311
+
312
+ # Cloud Dataproc.
313
+ when DATAPROC_CONSTANTS[:resource_type]
314
+ return {
315
+ 'cluster_uuid' =>
316
+ fetch_gce_metadata(platform,
317
+ 'instance/attributes/dataproc-cluster-uuid'),
318
+ 'cluster_name' =>
319
+ fetch_gce_metadata(platform,
320
+ 'instance/attributes/dataproc-cluster-name'),
321
+ 'region' =>
322
+ fetch_gce_metadata(platform,
323
+ 'instance/attributes/dataproc-region')
324
+ }
325
+
326
+ # EC2.
327
+ when EC2_CONSTANTS[:resource_type]
328
+ raise "Cannot construct a #{type} resource without vm_id and zone" \
329
+ unless vm_id && zone
330
+ labels = {
331
+ 'instance_id' => vm_id,
332
+ 'region' => zone
333
+ }
334
+ labels['aws_account'] = ec2_metadata(platform)['accountId'] if
335
+ ec2_metadata(platform).key?('accountId')
336
+ return labels
337
+ end
338
+
339
+ {}
340
+ rescue StandardError => e
341
+ if [Platform::GCE, Platform::EC2].include?(platform)
342
+ @log.error "Failed to set monitored resource labels for #{type}: ",
343
+ error: e
344
+ end
345
+ {}
346
+ end
347
+
348
+ # TODO: This functionality should eventually be available in another
349
+ # library, but implement it ourselves for now.
350
+ module CredentialsInfo
351
+ # Determine the project ID from the credentials, if possible.
352
+ # Returns the project ID (as a string) on success, or nil on failure.
353
+ def self.project_id
354
+ creds = Google::Auth.get_application_default(LOGGING_SCOPE)
355
+ if creds.respond_to?(:project_id)
356
+ return creds.project_id if creds.project_id
357
+ end
358
+ if creds.issuer
359
+ id = extract_project_id(creds.issuer)
360
+ return id unless id.nil?
361
+ end
362
+ if creds.client_id
363
+ id = extract_project_id(creds.client_id)
364
+ return id unless id.nil?
365
+ end
366
+ nil
367
+ end
368
+
369
+ # Extracts the project id (either name or number) from str and returns
370
+ # it (as a string) on success, or nil on failure.
371
+ #
372
+ # Recognizes IAM format (account@project-name.iam.gserviceaccount.com)
373
+ # as well as the legacy format with a project number at the front of the
374
+ # string, terminated by a dash (-) which is not part of the ID, i.e.:
375
+ # <PROJECT_ID>-<OTHER_PARTS>.apps.googleusercontent.com
376
+ def self.extract_project_id(str)
377
+ [/^.*@(?<project_id>.+)\.iam\.gserviceaccount\.com/,
378
+ /^(?<project_id>\d+)-/].each do |exp|
379
+ match_data = exp.match(str)
380
+ return match_data['project_id'] unless match_data.nil?
381
+ end
382
+ nil
383
+ end
384
+ end
385
+ end
386
+ end