fluent-plugin-google-cloud 0.8.4 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb0b416356143a700e7abeb68072df8423e44183cc370dea070c591f47ab5d2d
4
- data.tar.gz: 36764f53fea714492770ac0d93152c5ad96a53c0ac58f79a645bccb8bdb20269
3
+ metadata.gz: f873763395e9eff23e78cf7d645e42277be2b12e022334954b97d5a8b1a96f73
4
+ data.tar.gz: 26a2146530ef1bce151f6ee4d4fe0625f7dfec6019108cb96f68390c1aef6288
5
5
  SHA512:
6
- metadata.gz: 53ee7847c4b048a4d11b812f012587744be59f7abf3dbc039762d786306a740450267b762f1d4a7f0b1e317e6d6c12b31a9a59324c126ec144cae4a19959e312
7
- data.tar.gz: 221ad4d3d2955d81c484aeaf3dcbcaadd83bd04271df4b3ddc9b491e000feb9efb08f831912bd60dce3883902d60f855f8a921aff2188f34e0024d41daa5640f
6
+ metadata.gz: '051824ee94d4a2de635afe4b28e91475e422767d66407d2040e9d315f6a822d7cdaece7014ab2e6ab7211817b948f51fc385779182258d180e1a5492974f0ac1'
7
+ data.tar.gz: 8d373bb349402697ab45a3ec11186b0970fadb8ac66ddf25190bf68c4a6ccf0939b627ceb151922d4d8871e361b20ba3fadcfb254e7422c9d0f10b0ade7cb68b
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-google-cloud (0.8.4)
4
+ fluent-plugin-google-cloud (0.9.1)
5
5
  fluentd (= 1.7.4)
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,7 +18,7 @@ GEM
18
18
  specs:
19
19
  addressable (2.7.0)
20
20
  public_suffix (>= 2.0.2, < 5.0)
21
- ast (2.4.0)
21
+ ast (2.4.1)
22
22
  concurrent-ruby (1.1.6)
23
23
  cool.io (1.6.0)
24
24
  coveralls (0.8.23)
@@ -29,7 +29,7 @@ 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
34
  dig_rb (1.0.1)
35
35
  docile (1.3.2)
@@ -46,6 +46,12 @@ GEM
46
46
  tzinfo (~> 2.0)
47
47
  tzinfo-data (~> 1.0)
48
48
  yajl-ruby (~> 1.0)
49
+ gapic-common (0.3.1)
50
+ google-protobuf (~> 3.12, >= 3.12.2)
51
+ googleapis-common-protos (>= 1.3.9, < 2.0)
52
+ googleapis-common-protos-types (>= 1.0.4, < 2.0)
53
+ googleauth (~> 0.9)
54
+ grpc (~> 1.25)
49
55
  google-api-client (0.30.8)
50
56
  addressable (~> 2.5, >= 2.5.1)
51
57
  googleauth (>= 0.5, < 0.10.0)
@@ -57,36 +63,44 @@ GEM
57
63
  google-cloud-core (1.5.0)
58
64
  google-cloud-env (~> 1.0)
59
65
  google-cloud-errors (~> 1.0)
60
- google-cloud-env (1.3.1)
66
+ google-cloud-env (1.3.3)
61
67
  faraday (>= 0.17.3, < 2.0)
62
- google-cloud-errors (1.0.0)
68
+ google-cloud-errors (1.0.1)
63
69
  google-cloud-logging (1.6.6)
64
70
  concurrent-ruby (~> 1.1)
65
71
  google-cloud-core (~> 1.2)
66
72
  google-gax (~> 1.7)
67
73
  googleapis-common-protos-types (>= 1.0.2)
68
74
  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)
75
+ google-cloud-monitoring (0.38.0)
76
+ google-gax (~> 1.8)
77
+ googleapis-common-protos (>= 1.3.9, < 2.0)
78
+ googleapis-common-protos-types (>= 1.0.4, < 2.0)
79
+ google-cloud-trace (0.40.0)
73
80
  concurrent-ruby (~> 1.1)
74
- google-cloud-core (~> 1.2)
75
- google-gax (~> 1.7)
81
+ google-cloud-core (~> 1.5)
82
+ google-cloud-trace-v1 (~> 0.0)
83
+ google-cloud-trace-v2 (~> 0.0)
76
84
  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)
85
+ google-cloud-trace-v1 (0.1.0)
86
+ gapic-common (~> 0.3)
87
+ google-cloud-errors (~> 1.0)
88
+ google-cloud-trace-v2 (0.1.0)
89
+ gapic-common (~> 0.3)
90
+ google-cloud-errors (~> 1.0)
91
+ google-gax (1.8.1)
92
+ google-protobuf (~> 3.9)
93
+ googleapis-common-protos (>= 1.3.9, < 2.0)
94
+ googleauth (~> 0.9)
95
+ grpc (~> 1.24)
82
96
  rly (~> 0.2.3)
83
- google-protobuf (3.9.0)
97
+ google-protobuf (3.12.2)
84
98
  googleapis-common-protos (1.3.9)
85
99
  google-protobuf (~> 3.0)
86
100
  googleapis-common-protos-types (~> 1.0)
87
101
  grpc (~> 1.0)
88
- googleapis-common-protos-types (1.0.4)
89
- google-protobuf (~> 3.0)
102
+ googleapis-common-protos-types (1.0.5)
103
+ google-protobuf (~> 3.11)
90
104
  googleauth (0.9.0)
91
105
  faraday (~> 0.12)
92
106
  jwt (>= 1.4, < 3.0)
@@ -94,8 +108,8 @@ GEM
94
108
  multi_json (~> 1.11)
95
109
  os (>= 0.9, < 2.0)
96
110
  signet (~> 0.7)
97
- grpc (1.22.0)
98
- google-protobuf (~> 3.8)
111
+ grpc (1.30.2)
112
+ google-protobuf (~> 3.12)
99
113
  googleapis-common-protos-types (~> 1.0)
100
114
  hashdiff (1.0.1)
101
115
  http_parser.rb (0.6.0)
@@ -108,7 +122,7 @@ GEM
108
122
  mocha (1.9.0)
109
123
  metaclass (~> 0.0.1)
110
124
  msgpack (1.3.3)
111
- multi_json (1.14.1)
125
+ multi_json (1.15.0)
112
126
  multipart-post (2.1.1)
113
127
  opencensus (0.5.0)
114
128
  opencensus-stackdriver (0.3.2)
@@ -116,14 +130,14 @@ GEM
116
130
  google-cloud-monitoring (~> 0.32)
117
131
  google-cloud-trace (~> 0.35)
118
132
  opencensus (~> 0.5)
119
- os (1.0.1)
120
- parser (2.7.0.5)
121
- ast (~> 2.4.0)
122
- power_assert (1.1.7)
133
+ os (1.1.0)
134
+ parser (2.7.1.4)
135
+ ast (~> 2.4.1)
136
+ power_assert (1.2.0)
123
137
  powerpack (0.1.2)
124
138
  prometheus-client (0.9.0)
125
139
  quantile (~> 0.2.1)
126
- public_suffix (4.0.3)
140
+ public_suffix (4.0.5)
127
141
  quantile (0.2.1)
128
142
  rainbow (2.2.2)
129
143
  rake
@@ -145,7 +159,7 @@ GEM
145
159
  serverengine (2.2.1)
146
160
  sigdump (~> 0.2.2)
147
161
  sigdump (0.2.4)
148
- signet (0.13.2)
162
+ signet (0.14.0)
149
163
  addressable (~> 2.3)
150
164
  faraday (>= 0.17.3, < 2.0)
151
165
  jwt (>= 1.5, < 3.0)
@@ -157,18 +171,18 @@ GEM
157
171
  simplecov-html (0.10.2)
158
172
  stackdriver-core (1.4.0)
159
173
  google-cloud-core (~> 1.2)
160
- strptime (0.2.3)
174
+ strptime (0.2.4)
161
175
  sync (0.5.0)
162
176
  term-ansicolor (1.7.1)
163
177
  tins (~> 1.0)
164
178
  test-unit (3.3.3)
165
179
  power_assert
166
180
  thor (1.0.1)
167
- tins (1.24.1)
181
+ tins (1.25.0)
168
182
  sync
169
- tzinfo (2.0.1)
183
+ tzinfo (2.0.2)
170
184
  concurrent-ruby (~> 1.0)
171
- tzinfo-data (1.2019.3)
185
+ tzinfo-data (1.2020.1)
172
186
  tzinfo (>= 1.0.0)
173
187
  uber (0.1.0)
174
188
  unicode-display_width (1.7.0)
@@ -192,4 +206,4 @@ DEPENDENCIES
192
206
  webmock (= 3.6.2)
193
207
 
194
208
  BUNDLED WITH
195
- 2.1.1
209
+ 2.1.4
@@ -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.4'
13
+ gem.version = '0.9.1'
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')
@@ -24,8 +24,8 @@ eos
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