fluent-plugin-google-cloud 0.4.17 → 0.5.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
  SHA1:
3
- metadata.gz: 4caeb3e6a9cec431492945788635d7e99e3a0b16
4
- data.tar.gz: a88c1ce91b2335bac4b4a37f0c5899c864652046
3
+ metadata.gz: 1989b8ce8911575be17949674d1d8dfb137dbeda
4
+ data.tar.gz: f5ac2f7ca47a5c61dfc7a32a9254b6de841a2182
5
5
  SHA512:
6
- metadata.gz: f7130260e115f6547ba0db5782534f9f890655298c37beaafa4d9f254adf1f1489bf26b0a31df225e19dc694d81954d91c60aa12a7ffbd20e0018d3cacb50603
7
- data.tar.gz: f8dda17b58fe377783f29f91f93f71bbb2a53f7dca2c440485288efa684c3fba9b3d51e53948add7b8e991d328858972cfab0aec660f2ece1311eea58e3bfe39
6
+ metadata.gz: 9de731cc6f29055be014d6894f0b4930c7c6b5d836c149789d0ae06fe7e14a09687307485b559b6cf77335770a1f84003945468ed9b863d11c49a079142dad1a
7
+ data.tar.gz: aa07feea223b293e68da01fcf7e35facef3aa3af7ce3a8ba014304479e3521129809f004bb94a342ac6a00a2ee83bb0fe4132a2caae87ecdfcc4691cf6adbb5b
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-google-cloud (0.4.16)
4
+ fluent-plugin-google-cloud (0.5.0)
5
5
  fluentd (~> 0.10)
6
6
  google-api-client (> 0.9)
7
7
  googleauth (~> 0.4)
@@ -38,7 +38,7 @@ for authorization - for additional information see
38
38
  {here}[https://cloud.google.com/logging/docs/agent/authorization].
39
39
 
40
40
  <em>The previously documented parameters auth_method, private_key_email,
41
- and private_key_path are deprecated and should no longer be used.</em>
41
+ and private_key_path are removed, and can no longer be used.</em>
42
42
 
43
43
  == Copyright
44
44
 
data/Rakefile CHANGED
@@ -16,7 +16,17 @@ Rake::TestTask.new(:test) do |test|
16
16
  test.verbose = true
17
17
  end
18
18
 
19
+ # Building the gem will use the local file mode, so ensure it's world-readable.
20
+ # https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/issues/53
21
+ desc 'Check plugin file permissions'
22
+ task :check_perms do
23
+ plugin = 'lib/fluent/plugin/out_google_cloud.rb'
24
+ mode = File.stat(plugin).mode & 0777
25
+ fail "Unexpected mode #{mode.to_s(8)} for #{plugin}" unless
26
+ mode & 0444 == 0444
27
+ end
28
+
19
29
  desc 'Run unit tests and RuboCop to check for style violations'
20
- task all: [:test, :rubocop]
30
+ task all: [:test, :rubocop, :check_perms]
21
31
 
22
32
  task default: :all
@@ -10,25 +10,23 @@ 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.4.17'
13
+ gem.version = '0.5.0'
14
14
  gem.authors = ['Todd Derr', 'Alex Robinson']
15
15
  gem.email = ['salty@google.com']
16
+ gem.required_ruby_version = Gem::Requirement.new('>= 2.0')
16
17
 
17
18
  gem.files = Dir['**/*'].keep_if { |file| File.file?(file) }
18
19
  gem.test_files = gem.files.grep(/^(test)/)
19
20
  gem.require_paths = ['lib']
20
21
 
21
22
  gem.add_runtime_dependency 'fluentd', '~> 0.10'
22
- gem.add_runtime_dependency 'google-api-client', '>= 0.8.6', '< 0.9'
23
+ gem.add_runtime_dependency 'google-api-client', '> 0.9'
23
24
  gem.add_runtime_dependency 'googleauth', '~> 0.4'
24
25
  gem.add_runtime_dependency 'json', '~> 1.8'
25
- # workaround for jwt 1.5.3 breaking ruby 1.9 support (included by googleauth)
26
- # see https://github.com/jwt/ruby-jwt/issues/132
27
- gem.add_runtime_dependency 'jwt', '< 1.5.3'
28
26
 
29
27
  gem.add_development_dependency 'mocha', '~> 1.1'
30
28
  gem.add_development_dependency 'rake', '~> 10.3'
31
- gem.add_development_dependency 'rubocop', '= 0.34.2'
29
+ gem.add_development_dependency 'rubocop', '= 0.35.0'
32
30
  gem.add_development_dependency 'webmock', '~> 1.17'
33
31
  gem.add_development_dependency 'test-unit', '~> 3.0'
34
32
  end
@@ -11,14 +11,13 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- require 'cgi'
15
- require 'google/api_client'
16
- require 'google/api_client/auth/compute_service_account'
17
- require 'googleauth'
18
14
  require 'json'
19
15
  require 'open-uri'
20
16
  require 'socket'
21
17
  require 'yaml'
18
+ require 'google/apis'
19
+ require 'google/apis/logging_v1beta3'
20
+ require 'googleauth'
22
21
 
23
22
  module Fluent
24
23
  # fluentd output plugin for the Google Cloud Logging API
@@ -26,7 +25,7 @@ module Fluent
26
25
  Fluent::Plugin.register_output('google_cloud', self)
27
26
 
28
27
  PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'
29
- PLUGIN_VERSION = '0.4.17'
28
+ PLUGIN_VERSION = '0.5.0'
30
29
 
31
30
  # Constants for service names.
32
31
  APPENGINE_SERVICE = 'appengine.googleapis.com'
@@ -42,28 +41,9 @@ module Fluent
42
41
  # Address of the metadata service.
43
42
  METADATA_SERVICE_ADDR = '169.254.169.254'
44
43
 
45
- # Fields allowed in httpRequest object
46
- HTTP_REQUEST_FIELDS = %w(requestMethod requestUrl requestSize status
47
- responseSize userAgent remoteIp referer
48
- cacheHit validatedWithOriginServer)
49
-
50
44
  # Disable this warning to conform to fluentd config_param conventions.
51
45
  # rubocop:disable Style/HashSyntax
52
46
 
53
- # DEPRECATED: auth_method (and support for 'private_key') is deprecated in
54
- # favor of Google Application Default Credentials as documented at:
55
- # https://developers.google.com/identity/protocols/application-default-credentials
56
- # 'private_key' is still accepted to support existing users; any other
57
- # value is ignored.
58
- config_param :auth_method, :string, :default => nil
59
-
60
- # DEPRECATED: Parameters necessary to use the private_key auth_method.
61
- config_param :private_key_email, :string, :default => nil
62
- config_param :private_key_path, :string, :default => nil
63
- config_param :private_key_passphrase, :string,
64
- :default => 'notasecret',
65
- :secret => true
66
-
67
47
  # Specify project/instance metadata.
68
48
  #
69
49
  # project_id, zone, and vm_id are required to have valid values, which
@@ -117,6 +97,15 @@ module Fluent
117
97
  # }
118
98
  config_param :label_map, :hash, :default => nil
119
99
 
100
+ # DEPRECATED: The following parameters, if present in the config
101
+ # indicate that the plugin configuration must be updated.
102
+ config_param :auth_method, :string, :default => nil
103
+ config_param :private_key_email, :string, :default => nil
104
+ config_param :private_key_path, :string, :default => nil
105
+ config_param :private_key_passphrase, :string,
106
+ :default => nil,
107
+ :secret => true
108
+
120
109
  # rubocop:enable Style/HashSyntax
121
110
 
122
111
  # TODO: Add a log_name config option rather than just using the tag?
@@ -141,21 +130,19 @@ module Fluent
141
130
  def configure(conf)
142
131
  super
143
132
 
144
- unless @auth_method.nil?
145
- @log.warn 'auth_method is deprecated; please migrate to using ' \
146
- 'Application Default Credentials.'
147
- if @auth_method == 'private_key'
148
- if !@private_key_email
149
- fail Fluent::ConfigError, '"private_key_email" must be ' \
150
- 'specified if auth_method is "private_key"'
151
- elsif !@private_key_path
152
- fail Fluent::ConfigError, '"private_key_path" must be ' \
153
- 'specified if auth_method is "private_key"'
154
- elsif !@private_key_passphrase
155
- fail Fluent::ConfigError, '"private_key_passphrase" must be ' \
156
- 'specified if auth_method is "private_key"'
157
- end
158
- end
133
+ # Alert on old authentication configuration.
134
+ unless @auth_method.nil? && @private_key_email.nil? &&
135
+ @private_key_path.nil? && @private_key_passphrase.nil?
136
+ extra = []
137
+ extra << 'auth_method' unless @auth_method.nil?
138
+ extra << 'private_key_email' unless @private_key_email.nil?
139
+ extra << 'private_key_path' unless @private_key_path.nil?
140
+ extra << 'private_key_passphrase' unless @private_key_passphrase.nil?
141
+
142
+ fail Fluent::ConfigError,
143
+ "#{PLUGIN_NAME} no longer supports auth_method.\n" \
144
+ 'Please remove configuration parameters: ' +
145
+ extra.join(' ')
159
146
  end
160
147
 
161
148
  # TODO: Send instance tags as labels as well?
@@ -350,14 +337,13 @@ module Fluent
350
337
  arr.each do |time, record|
351
338
  next unless record.is_a?(Hash)
352
339
 
353
- entry = {
354
- 'metadata' => {
355
- 'serviceName' => @service_name,
356
- 'projectId' => @project_id,
357
- 'zone' => @zone,
358
- 'labels' => {}
359
- }
360
- }
340
+ entry = Google::Apis::LoggingV1beta3::LogEntry.new(
341
+ metadata: Google::Apis::LoggingV1beta3::LogEntryMetadata.new(
342
+ service_name: @service_name,
343
+ project_id: @project_id,
344
+ zone: @zone,
345
+ labels: {}
346
+ ))
361
347
 
362
348
  if @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
363
349
  @cloudfunctions_log_match =
@@ -365,7 +351,7 @@ module Fluent
365
351
  end
366
352
  if @service_name == CONTAINER_SERVICE
367
353
  # Move the stdout/stderr annotation from the record into a label
368
- field_to_label(record, 'stream', entry['metadata']['labels'],
354
+ field_to_label(record, 'stream', entry.metadata.labels,
369
355
  "#{CONTAINER_SERVICE}/stream")
370
356
  # If the record has been annotated by the kubernetes_metadata_filter
371
357
  # plugin, then use that metadata. Otherwise, rely on commonLabels
@@ -403,87 +389,75 @@ module Fluent
403
389
  # and do not send that field as part of the payload.
404
390
  if @label_map
405
391
  @label_map.each do |field, label|
406
- field_to_label(record, field, entry['metadata']['labels'], label)
392
+ field_to_label(record, field, entry.metadata.labels, label)
407
393
  end
408
394
  end
409
395
 
410
396
  if @service_name == CLOUDFUNCTIONS_SERVICE &&
411
397
  @cloudfunctions_log_match &&
412
398
  @cloudfunctions_log_match['execution_id']
413
- entry['metadata']['labels']['execution_id'] =
399
+ entry.metadata.labels['execution_id'] =
414
400
  @cloudfunctions_log_match['execution_id']
415
401
  end
416
402
 
417
403
  set_payload(record, entry, is_container_json)
418
-
419
- # Remove the labels metadata if we didn't populate it with anything.
420
- if entry['metadata']['labels'].empty?
421
- entry['metadata'].delete('labels')
422
- end
404
+ entry.metadata.labels = nil if entry.metadata.labels.empty?
423
405
 
424
406
  entries.push(entry)
425
407
  end
426
408
  # Don't send an empty request if we rejected all the entries.
427
409
  next if entries.empty?
428
410
 
429
- log_name = CGI.escape(log_name(tag, labels))
430
- url = 'https://logging.googleapis.com/v1beta3/projects/' \
431
- "#{@project_id}/logs/#{log_name}/entries:write"
411
+ log_name = log_name(tag, labels)
432
412
 
433
413
  begin
414
+ # Does the actual write to the cloud logging api.
415
+ # The URI of the write is constructed by the Google::Api request;
416
+ # it is equivalent to this URL:
417
+ # 'https://logging.googleapis.com/v1beta3/projects/' \
418
+ # "#{@project_id}/logs/#{log_name}/entries:write"
419
+
434
420
  client = api_client
435
- request = client.generate_request(
436
- uri: url,
437
- http_method: 'POST',
438
- authenticated: true,
439
- body_object: {
440
- 'commonLabels' => labels,
441
- 'entries' => entries
442
- }
443
- )
444
- client.execute!(request)
421
+
422
+ write_request = \
423
+ Google::Apis::LoggingV1beta3::WriteLogEntriesRequest.new(
424
+ common_labels: labels,
425
+ entries: entries)
426
+
427
+ # TODO: RequestOptions
428
+ client.write_log_entries(@project_id, log_name, write_request)
429
+
445
430
  # Let the user explicitly know when the first call succeeded,
446
431
  # to aid with verification and troubleshooting.
447
432
  unless @successful_call
448
433
  @successful_call = true
449
434
  @log.info 'Successfully sent to Google Cloud Logging API.'
450
435
  end
451
- # Allow most exceptions to propagate, which will cause fluentd to
452
- # retry (with backoff), but in some cases we catch the error and
453
- # drop the request (we will emit a log message in those cases).
454
- rescue Google::APIClient::ClientError => error
436
+
437
+ rescue Google::Apis::ServerError => error
438
+ # Server error, so retry via re-raising the error.
439
+ raise error
440
+
441
+ rescue Google::Apis::AuthorizationError => error
442
+ # Authorization error.
443
+ # These are usually solved via a `gcloud auth` call, or by modifying
444
+ # the permissions on the Google Cloud project.
445
+ dropped = entries.length
446
+ @log.warn "Dropping #{dropped} log message(s)",
447
+ error_class: error.class.to_s, error: error.to_s
448
+
449
+ rescue Google::Apis::ClientError => error
455
450
  # Most ClientErrors indicate a problem with the request itself and
456
- # should not be retried, unless it is an authentication issue, in
457
- # which case we will retry the request via re-raising the exception.
458
- raise error if retriable_client_error?(error)
459
- log_write_failure(entries.length, error)
460
- rescue JSON::GeneratorError => error
461
- # This happens if the request contains illegal characters;
462
- # do not retry it because it will fail repeatedly.
463
- log_write_failure(entries.length, error)
451
+ # should not be retried.
452
+ dropped = entries.length
453
+ @log.warn "Dropping #{dropped} log message(s)",
454
+ error_class: error.class.to_s, error: error.to_s
464
455
  end
465
456
  end
466
457
  end
467
458
 
468
459
  private
469
460
 
470
- RETRIABLE_CLIENT_ERRORS = Set.new [
471
- 'Invalid Credentials',
472
- 'Request had invalid credentials.',
473
- 'The caller does not have permission',
474
- 'Project has not enabled the API. Please use Google Developers ' \
475
- 'Console to activate the API for your project.',
476
- 'Unable to fetch access token (no scopes configured?)']
477
-
478
- def retriable_client_error?(error)
479
- RETRIABLE_CLIENT_ERRORS.include?(error.message)
480
- end
481
-
482
- def log_write_failure(dropped, error)
483
- @log.warn "Dropping #{dropped} log message(s)",
484
- error_class: error.class.to_s, error: error.to_s
485
- end
486
-
487
461
  def parse_json_or_nil(input)
488
462
  # Only here to please rubocop...
489
463
  return nil if input.nil?
@@ -512,11 +486,11 @@ module Fluent
512
486
 
513
487
  begin
514
488
  open('http://' + METADATA_SERVICE_ADDR) do |f|
515
- if (f.meta['metadata-flavor'] == 'Google')
489
+ if f.meta['metadata-flavor'] == 'Google'
516
490
  @log.info 'Detected GCE platform'
517
491
  return Platform::GCE
518
492
  end
519
- if (f.meta['server'] == 'EC2ws')
493
+ if f.meta['server'] == 'EC2ws'
520
494
  @log.info 'Detected EC2 platform'
521
495
  return Platform::EC2
522
496
  end
@@ -554,7 +528,6 @@ module Fluent
554
528
  # Determine the project ID from the credentials, if possible.
555
529
  # Returns the project ID (as a string) on success, or nil on failure.
556
530
  def self.project_id
557
- return nil if @auth_method == 'private_key'
558
531
  creds = Google::Auth.get_application_default(LOGGING_SCOPE)
559
532
  if creds.issuer
560
533
  id = extract_project_id(creds.issuer)
@@ -610,16 +583,14 @@ module Fluent
610
583
  record.delete('timestamp')
611
584
  elsif record.key?('timestampSeconds') &&
612
585
  record.key?('timestampNanos')
613
- ts_secs = record['timestampSeconds']
614
- ts_nanos = record['timestampNanos']
615
- record.delete('timestampSeconds')
616
- record.delete('timestampNanos')
586
+ ts_secs = record.delete('timestampSeconds')
587
+ ts_nanos = record.delete('timestampNanos')
617
588
  elsif record.key?('timeNanos')
618
589
  # This is deprecated since the precision is insufficient.
619
590
  # Use timestampSeconds/timestampNanos instead
620
- ts_secs = (record['timeNanos'] / 1_000_000_000).to_i
621
- ts_nanos = record['timeNanos'] % 1_000_000_000
622
- record.delete('timeNanos')
591
+ nanos = record.delete('timeNanos')
592
+ ts_secs = (nanos / 1_000_000_000).to_i
593
+ ts_nanos = nanos % 1_000_000_000
623
594
  unless @timenanos_warning
624
595
  # Warn the user this is deprecated, but only once to avoid spam.
625
596
  @timenanos_warning = true
@@ -636,47 +607,51 @@ module Fluent
636
607
  ts_secs = timestamp.tv_sec
637
608
  ts_nanos = timestamp.tv_nsec
638
609
  end
639
- entry['metadata']['timestamp'] = {
640
- 'seconds' => ts_secs,
641
- 'nanos' => ts_nanos
610
+ entry.metadata.timestamp = {
611
+ seconds: ts_secs,
612
+ nanos: ts_nanos
642
613
  }
643
614
  end
644
615
 
645
616
  def set_severity(record, entry)
646
617
  if @service_name == CLOUDFUNCTIONS_SERVICE
647
618
  if @cloudfunctions_log_match && @cloudfunctions_log_match['severity']
648
- entry['metadata']['severity'] =
619
+ entry.metadata.severity =
649
620
  parse_severity(@cloudfunctions_log_match['severity'])
650
621
  elsif record.key?('stream') && record['stream'] == 'stdout'
651
- entry['metadata']['severity'] = 'INFO'
622
+ entry.metadata.severity = 'INFO'
652
623
  record.delete('stream')
653
624
  elsif record.key?('stream') && record['stream'] == 'stderr'
654
- entry['metadata']['severity'] = 'ERROR'
625
+ entry.metadata.severity = 'ERROR'
655
626
  record.delete('stream')
656
627
  else
657
- entry['metadata']['severity'] = 'DEFAULT'
628
+ entry.metadata.severity = 'DEFAULT'
658
629
  end
659
630
  elsif record.key?('severity')
660
- entry['metadata']['severity'] = parse_severity(record['severity'])
631
+ entry.metadata.severity = parse_severity(record['severity'])
661
632
  record.delete('severity')
662
633
  else
663
- entry['metadata']['severity'] = 'DEFAULT'
634
+ entry.metadata.severity = 'DEFAULT'
664
635
  end
665
636
  end
666
637
 
667
638
  def set_http_request(record, entry)
668
- return unless record['httpRequest'].is_a?(Hash)
669
-
670
- entry['httpRequest'] = {}
671
-
672
- HTTP_REQUEST_FIELDS.each do |field|
673
- if record['httpRequest'].key?(field)
674
- entry['httpRequest'][field] = record['httpRequest'][field]
675
- record['httpRequest'].delete(field)
676
- end
677
- end
678
-
679
- record.delete('httpRequest') if record['httpRequest'].empty?
639
+ return nil unless record['httpRequest'].is_a?(Hash)
640
+ input = record['httpRequest']
641
+ output = Google::Apis::LoggingV1beta3::HttpRequest.new
642
+ output.request_method = input.delete('requestMethod')
643
+ output.request_url = input.delete('requestUrl')
644
+ output.request_size = input.delete('requestSize')
645
+ output.status = input.delete('status')
646
+ output.response_size = input.delete('responseSize')
647
+ output.user_agent = input.delete('userAgent')
648
+ output.remote_ip = input.delete('remoteIp')
649
+ output.referer = input.delete('referer')
650
+ output.cache_hit = input.delete('cacheHit')
651
+ output.validated_with_origin_server = \
652
+ input.delete('validatedWithOriginServer')
653
+ record.delete('httpRequest') if input.empty?
654
+ entry.http_request = output
680
655
  end
681
656
 
682
657
  # Values permitted by the API for 'severity' (which is an enum).
@@ -748,13 +723,13 @@ module Fluent
748
723
  def handle_container_metadata(record, entry)
749
724
  fields = %w(namespace_id namespace_name pod_id pod_name container_name)
750
725
  fields.each do |field|
751
- field_to_label(record['kubernetes'], field, entry['metadata']['labels'],
726
+ field_to_label(record['kubernetes'], field, entry.metadata.labels,
752
727
  "#{CONTAINER_SERVICE}/#{field}")
753
728
  end
754
729
  # Prepend label/ to all user-defined labels' keys.
755
730
  if record['kubernetes'].key?('labels')
756
731
  record['kubernetes']['labels'].each do |key, value|
757
- entry['metadata']['labels']["label/#{key}"] = value
732
+ entry.metadata.labels["label/#{key}"] = value
758
733
  end
759
734
  end
760
735
  # We've explicitly consumed all the fields we care about -- don't litter
@@ -777,20 +752,20 @@ module Fluent
777
752
  # 3. This is an unstructured Container log and the 'log' key is available
778
753
  # 4. The only remaining key is 'message'
779
754
  if @service_name == CLOUDFUNCTIONS_SERVICE && @cloudfunctions_log_match
780
- entry['textPayload'] = @cloudfunctions_log_match['text']
755
+ entry.text_payload = @cloudfunctions_log_match['text']
781
756
  elsif @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
782
- entry['textPayload'] = record['log']
757
+ entry.text_payload = record['log']
783
758
  elsif @service_name == CONTAINER_SERVICE && record.key?('log') &&
784
759
  !is_container_json
785
- entry['textPayload'] = record['log']
760
+ entry.text_payload = record['log']
786
761
  elsif record.size == 1 && record.key?('message')
787
- entry['textPayload'] = record['message']
762
+ entry.text_payload = record['message']
788
763
  else
789
- entry['structPayload'] = record
764
+ entry.struct_payload = record
790
765
  end
791
766
  end
792
767
 
793
- def log_name(tag, commonLabels)
768
+ def log_name(tag, common_labels)
794
769
  if @service_name == CLOUDFUNCTIONS_SERVICE
795
770
  return 'cloud-functions'
796
771
  elsif @running_on_managed_vm
@@ -800,30 +775,20 @@ module Fluent
800
775
  # For Kubernetes logs, use just the container name as the log name
801
776
  # if we have it.
802
777
  container_name_key = "#{CONTAINER_SERVICE}/container_name"
803
- if commonLabels && commonLabels.key?(container_name_key)
804
- return commonLabels[container_name_key]
778
+ if common_labels && common_labels.key?(container_name_key)
779
+ return common_labels[container_name_key]
805
780
  end
806
781
  end
807
782
  tag
808
783
  end
809
784
 
810
785
  def init_api_client
811
- @client = Google::APIClient.new(
812
- application_name: PLUGIN_NAME,
813
- application_version: PLUGIN_VERSION,
814
- retries: 1)
815
-
816
- if @auth_method == 'private_key'
817
- key = Google::APIClient::PKCS12.load_key(@private_key_path,
818
- @private_key_passphrase)
819
- jwt_asserter = Google::APIClient::JWTAsserter.new(
820
- @private_key_email, LOGGING_SCOPE, key)
821
- @client.authorization = jwt_asserter.to_authorization
822
- @client.authorization.expiry = 3600 # 3600s is the max allowed value
823
- else
824
- @client.authorization = Google::Auth.get_application_default(
825
- LOGGING_SCOPE)
826
- end
786
+ # TODO: Use a non-default ClientOptions object.
787
+ Google::Apis::ClientOptions.default.application_name = PLUGIN_NAME
788
+ Google::Apis::ClientOptions.default.application_version = PLUGIN_VERSION
789
+ @client = Google::Apis::LoggingV1beta3::LoggingService.new
790
+ @client.authorization = Google::Auth.get_application_default(
791
+ LOGGING_SCOPE)
827
792
  end
828
793
 
829
794
  def api_client
@@ -16,6 +16,7 @@ require 'helper'
16
16
  require 'json'
17
17
  require 'mocha/test_unit'
18
18
  require 'webmock/test_unit'
19
+ require 'google/apis'
19
20
 
20
21
  # Unit tests for Google Cloud Logging plugin
21
22
  class GoogleCloudOutputTest < Test::Unit::TestCase
@@ -117,9 +118,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
117
118
 
118
119
  # rubocop:disable Metrics/LineLength
119
120
  PRIVATE_KEY_CONFIG = %(
120
- auth_method private_key
121
- private_key_email 271661262351-ft99kc9kjro9rrihq3k2n3s2inbplu0q@developer.gserviceaccount.com
122
- private_key_path test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
121
+ auth_method private_key
122
+ private_key_email 271661262351-ft99kc9kjro9rrihq3k2n3s2inbplu0q@developer.gserviceaccount.com
123
+ private_key_path test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
123
124
  )
124
125
  # rubocop:enable Metrics/LineLength
125
126
 
@@ -138,14 +139,6 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
138
139
  vm_name #{CUSTOM_HOSTNAME}
139
140
  )
140
141
 
141
- CONFIG_MISSING_PRIVATE_KEY_PATH = %(
142
- auth_method private_key
143
- private_key_email nobody@example.com
144
- )
145
- CONFIG_MISSING_PRIVATE_KEY_EMAIL = %(
146
- auth_method private_key
147
- private_key_path /fake/path/to/key
148
- )
149
142
  CONFIG_MISSING_METADATA_PROJECT_ID = %(
150
143
  zone #{CUSTOM_ZONE}
151
144
  vm_id #{CUSTOM_VM_ID}
@@ -331,43 +324,28 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
331
324
  def test_configure_service_account_application_default
332
325
  setup_gce_metadata_stubs
333
326
  d = create_driver(APPLICATION_DEFAULT_CONFIG)
334
- assert d.instance.auth_method.nil?
327
+ assert_equal HOSTNAME, d.instance.vm_name
335
328
  end
336
329
 
337
330
  def test_configure_service_account_private_key
331
+ # Using out-of-date config method.
338
332
  setup_gce_metadata_stubs
339
- d = create_driver(PRIVATE_KEY_CONFIG)
340
- assert_equal 'private_key', d.instance.auth_method
341
- end
342
-
343
- def test_configure_custom_metadata
344
- setup_no_metadata_service_stubs
345
- d = create_driver(CUSTOM_METADATA_CONFIG)
346
- assert_equal CUSTOM_PROJECT_ID, d.instance.project_id
347
- assert_equal CUSTOM_ZONE, d.instance.zone
348
- assert_equal CUSTOM_VM_ID, d.instance.vm_id
349
- end
350
-
351
- def test_configure_invalid_private_key_missing_path
352
333
  exception_count = 0
353
334
  begin
354
- _d = create_driver(CONFIG_MISSING_PRIVATE_KEY_PATH)
335
+ _d = create_driver(PRIVATE_KEY_CONFIG)
355
336
  rescue Fluent::ConfigError => error
356
- assert error.message.include? 'private_key_path'
337
+ assert error.message.include? 'Please remove configuration parameters'
357
338
  exception_count += 1
358
339
  end
359
340
  assert_equal 1, exception_count
360
341
  end
361
342
 
362
- def test_configure_invalid_private_key_missing_email
363
- exception_count = 0
364
- begin
365
- _d = create_driver(CONFIG_MISSING_PRIVATE_KEY_EMAIL)
366
- rescue Fluent::ConfigError => error
367
- assert error.message.include? 'private_key_email'
368
- exception_count += 1
369
- end
370
- assert_equal 1, exception_count
343
+ def test_configure_custom_metadata
344
+ setup_no_metadata_service_stubs
345
+ d = create_driver(CUSTOM_METADATA_CONFIG)
346
+ assert_equal CUSTOM_PROJECT_ID, d.instance.project_id
347
+ assert_equal CUSTOM_ZONE, d.instance.zone
348
+ assert_equal CUSTOM_VM_ID, d.instance.vm_id
371
349
  end
372
350
 
373
351
  def test_configure_invalid_metadata_missing_project_id_no_metadata_service
@@ -569,15 +547,6 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
569
547
  assert_equal 1, exception_count
570
548
  end
571
549
 
572
- def test_one_log_private_key
573
- setup_gce_metadata_stubs
574
- setup_logging_stubs
575
- d = create_driver(PRIVATE_KEY_CONFIG)
576
- d.emit('message' => log_entry(0))
577
- d.run
578
- verify_log_entries(1, COMPUTE_PARAMS)
579
- end
580
-
581
550
  def test_one_log_custom_metadata
582
551
  # don't set up any metadata stubs, so the test will fail if we try to
583
552
  # fetch metadata (and explicitly check this as well).
@@ -795,7 +764,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
795
764
  assert @logs_sent.empty?
796
765
  end
797
766
 
798
- def test_client_error
767
+ def test_client_400
799
768
  setup_gce_metadata_stubs
800
769
  # The API Client should not retry this and the plugin should consume
801
770
  # the exception.
@@ -807,43 +776,19 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
807
776
  assert_requested(:post, uri_for_log(COMPUTE_PARAMS), times: 1)
808
777
  end
809
778
 
810
- # helper for the ClientError retriable special cases below.
811
- def client_error_helper(message)
779
+ # All credentials errors resolve to a 401.
780
+ def test_client_401
812
781
  setup_gce_metadata_stubs
813
782
  stub_request(:post, uri_for_log(COMPUTE_PARAMS))
814
- .to_return(status: 401, body: message)
783
+ .to_return(status: 401, body: 'Unauthorized')
815
784
  d = create_driver
816
785
  d.emit('message' => log_entry(0))
817
- exception_count = 0
818
786
  begin
819
787
  d.run
820
- rescue Google::APIClient::ClientError => error
821
- assert_equal message, error.message
822
- exception_count += 1
788
+ rescue Google::Apis::AuthorizationError => error
789
+ assert_equal 'Unauthorized', error.message
823
790
  end
824
791
  assert_requested(:post, uri_for_log(COMPUTE_PARAMS), times: 2)
825
- assert_equal 1, exception_count
826
- end
827
-
828
- def test_client_error_invalid_credentials
829
- client_error_helper('Invalid Credentials')
830
- end
831
-
832
- def test_client_error_caller_does_not_have_permission
833
- client_error_helper('The caller does not have permission')
834
- end
835
-
836
- def test_client_error_request_had_invalid_credentials
837
- client_error_helper('Request had invalid credentials.')
838
- end
839
-
840
- def test_client_error_project_has_not_enabled_the_api
841
- client_error_helper('Project has not enabled the API. Please use ' \
842
- 'Google Developers Console to activate the API for your project.')
843
- end
844
-
845
- def test_client_error_unable_to_fetch_accesss_token
846
- client_error_helper('Unable to fetch access token (no scopes configured?)')
847
792
  end
848
793
 
849
794
  def test_server_error
@@ -857,11 +802,11 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
857
802
  exception_count = 0
858
803
  begin
859
804
  d.run
860
- rescue Google::APIClient::ServerError => error
861
- assert_equal 'Server Error', error.message
805
+ rescue Google::Apis::ServerError => error
806
+ assert_equal 'Server error', error.message
862
807
  exception_count += 1
863
808
  end
864
- assert_requested(:post, uri_for_log(COMPUTE_PARAMS), times: 2)
809
+ assert_requested(:post, uri_for_log(COMPUTE_PARAMS), times: 1)
865
810
  assert_equal 1, exception_count
866
811
  end
867
812
 
@@ -1266,14 +1211,6 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
1266
1211
  status: 200,
1267
1212
  headers: { 'Content-Length' => FAKE_AUTH_TOKEN.length,
1268
1213
  'Content-Type' => 'application/json' })
1269
-
1270
- # Used for 'private_key' auth.
1271
- stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
1272
- .with(body: hash_including(grant_type: AUTH_GRANT_TYPE))
1273
- .to_return(body: %({"access_token": "#{FAKE_AUTH_TOKEN}"}),
1274
- status: 200,
1275
- headers: { 'Content-Length' => FAKE_AUTH_TOKEN.length,
1276
- 'Content-Type' => 'application/json' })
1277
1214
  end
1278
1215
 
1279
1216
  def setup_managed_vm_metadata_stubs
@@ -1376,7 +1313,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
1376
1313
  assert entry.key?(payload_type), 'Entry did not contain expected ' \
1377
1314
  "#{payload_type} key: " + entry.to_s
1378
1315
  # Check the payload for textPayload, otherwise it's up to the caller.
1379
- if (payload_type == 'textPayload')
1316
+ if payload_type == 'textPayload'
1380
1317
  assert_equal "test log entry #{i}", entry['textPayload'], batch
1381
1318
  end
1382
1319
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-google-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.17
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Derr
@@ -29,20 +29,14 @@ dependencies:
29
29
  name: google-api-client
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: 0.8.6
35
- - - "<"
32
+ - - ">"
36
33
  - !ruby/object:Gem::Version
37
34
  version: '0.9'
38
35
  type: :runtime
39
36
  prerelease: false
40
37
  version_requirements: !ruby/object:Gem::Requirement
41
38
  requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- version: 0.8.6
45
- - - "<"
39
+ - - ">"
46
40
  - !ruby/object:Gem::Version
47
41
  version: '0.9'
48
42
  - !ruby/object:Gem::Dependency
@@ -73,20 +67,6 @@ dependencies:
73
67
  - - "~>"
74
68
  - !ruby/object:Gem::Version
75
69
  version: '1.8'
76
- - !ruby/object:Gem::Dependency
77
- name: jwt
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "<"
81
- - !ruby/object:Gem::Version
82
- version: 1.5.3
83
- type: :runtime
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "<"
88
- - !ruby/object:Gem::Version
89
- version: 1.5.3
90
70
  - !ruby/object:Gem::Dependency
91
71
  name: mocha
92
72
  requirement: !ruby/object:Gem::Requirement
@@ -121,14 +101,14 @@ dependencies:
121
101
  requirements:
122
102
  - - '='
123
103
  - !ruby/object:Gem::Version
124
- version: 0.34.2
104
+ version: 0.35.0
125
105
  type: :development
126
106
  prerelease: false
127
107
  version_requirements: !ruby/object:Gem::Requirement
128
108
  requirements:
129
109
  - - '='
130
110
  - !ruby/object:Gem::Version
131
- version: 0.34.2
111
+ version: 0.35.0
132
112
  - !ruby/object:Gem::Dependency
133
113
  name: webmock
134
114
  requirement: !ruby/object:Gem::Requirement
@@ -194,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
174
  requirements:
195
175
  - - ">="
196
176
  - !ruby/object:Gem::Version
197
- version: '0'
177
+ version: '2.0'
198
178
  required_rubygems_version: !ruby/object:Gem::Requirement
199
179
  requirements:
200
180
  - - ">="