fluent-plugin-google-cloud 0.2.3 → 0.2.4
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.
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-plugin-google-cloud (0.2.
|
4
|
+
fluent-plugin-google-cloud (0.2.4)
|
5
5
|
fluentd (>= 0.10)
|
6
6
|
google-api-client (>= 0.8)
|
7
|
+
googleauth (~> 0.4)
|
7
8
|
|
8
9
|
GEM
|
9
10
|
remote: https://rubygems.org/
|
@@ -64,10 +65,14 @@ GEM
|
|
64
65
|
little-plugger (~> 1.1)
|
65
66
|
multi_json (~> 1.10)
|
66
67
|
memoist (0.12.0)
|
68
|
+
metaclass (0.0.4)
|
67
69
|
minitest (5.6.1)
|
70
|
+
mocha (1.1.0)
|
71
|
+
metaclass (~> 0.0.1)
|
68
72
|
msgpack (0.5.11)
|
69
73
|
multi_json (1.11.0)
|
70
74
|
multipart-post (2.0.0)
|
75
|
+
power_assert (0.2.3)
|
71
76
|
rake (10.4.2)
|
72
77
|
retriable (1.4.1)
|
73
78
|
safe_yaml (1.0.4)
|
@@ -79,6 +84,8 @@ GEM
|
|
79
84
|
jwt (~> 1.0)
|
80
85
|
multi_json (~> 1.10)
|
81
86
|
string-scrub (0.0.5)
|
87
|
+
test-unit (3.0.9)
|
88
|
+
power_assert
|
82
89
|
thread_safe (0.3.5)
|
83
90
|
tzinfo (1.2.2)
|
84
91
|
thread_safe (~> 0.1)
|
@@ -94,5 +101,7 @@ PLATFORMS
|
|
94
101
|
|
95
102
|
DEPENDENCIES
|
96
103
|
fluent-plugin-google-cloud!
|
104
|
+
mocha (~> 1.1)
|
97
105
|
rake (>= 10.3.2)
|
106
|
+
test-unit (~> 3.0.2)
|
98
107
|
webmock (>= 1.17.0)
|
@@ -4,7 +4,7 @@ Gem::Specification.new do |gem|
|
|
4
4
|
gem.summary = %q{Fluentd plugin to stream logs to the Google Cloud Platform's logging API}
|
5
5
|
gem.homepage = 'https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud'
|
6
6
|
gem.license = 'Apache 2.0'
|
7
|
-
gem.version = '0.2.
|
7
|
+
gem.version = '0.2.4'
|
8
8
|
gem.authors = ['Todd Derr', 'Alex Robinson']
|
9
9
|
gem.email = ['salty@google.com']
|
10
10
|
|
@@ -14,6 +14,9 @@ Gem::Specification.new do |gem|
|
|
14
14
|
|
15
15
|
gem.add_runtime_dependency 'fluentd', '>= 0.10'
|
16
16
|
gem.add_runtime_dependency 'google-api-client', '>= 0.8'
|
17
|
+
gem.add_runtime_dependency 'googleauth', '~> 0.4'
|
17
18
|
gem.add_development_dependency "rake", '>= 10.3.2'
|
18
19
|
gem.add_development_dependency "webmock", '>= 1.17.0'
|
20
|
+
gem.add_development_dependency "test-unit", "~> 3.0.2"
|
21
|
+
gem.add_development_dependency "mocha", "~> 1.1"
|
19
22
|
end
|
@@ -21,21 +21,29 @@ module Fluent
|
|
21
21
|
COMPUTE_SERVICE = 'compute.googleapis.com'
|
22
22
|
DATAFLOW_SERVICE = 'dataflow.googleapis.com'
|
23
23
|
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# Parameters necessary to use the private_key auth_method.
|
24
|
+
# Name of the the Google cloud logging write scope.
|
25
|
+
LOGGING_SCOPE = 'https://www.googleapis.com/auth/logging.write'
|
26
|
+
|
27
|
+
# DEPRECATED: auth_method (and support for 'private_key') is deprecated in
|
28
|
+
# favor of Google Application Default Credentials as documented at:
|
29
|
+
# https://developers.google.com/identity/protocols/application-default-credentials
|
30
|
+
# 'private_key' is still accepted to support existing users; any other
|
31
|
+
# value is ignored.
|
32
|
+
config_param :auth_method, :string, :default => nil
|
33
|
+
|
34
|
+
# DEPRECATED: Parameters necessary to use the private_key auth_method.
|
35
35
|
config_param :private_key_email, :string, :default => nil
|
36
36
|
config_param :private_key_path, :string, :default => nil
|
37
37
|
config_param :private_key_passphrase, :string, :default => 'notasecret'
|
38
38
|
|
39
|
+
# If fetch_gce_metadata is set to true, we obtain the project_id, zone,
|
40
|
+
# and vm_id from the GCE metadata service. Otherwise, those parameters
|
41
|
+
# must be specified in the config file explicitly.
|
42
|
+
config_param :fetch_gce_metadata, :bool, :default => true
|
43
|
+
config_param :project_id, :string, :default => nil
|
44
|
+
config_param :zone, :string, :default => nil
|
45
|
+
config_param :vm_id, :string, :default => nil
|
46
|
+
|
39
47
|
# TODO: Add a log_name config option rather than just using the tag?
|
40
48
|
|
41
49
|
# Expose attr_readers to make testing of metadata more direct than only
|
@@ -54,30 +62,35 @@ module Fluent
|
|
54
62
|
require 'cgi'
|
55
63
|
require 'google/api_client'
|
56
64
|
require 'google/api_client/auth/compute_service_account'
|
65
|
+
require 'googleauth'
|
57
66
|
require 'open-uri'
|
58
67
|
end
|
59
68
|
|
60
69
|
def configure(conf)
|
61
70
|
super
|
62
71
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
if !@auth_method.nil?
|
73
|
+
$log.warn ('auth_method is deprecated; please migrate to using ' +
|
74
|
+
'Application Default Credentials.')
|
75
|
+
if @auth_method == 'private_key'
|
76
|
+
if !@private_key_email
|
77
|
+
raise Fluent::ConfigError, ('"private_key_email" must be ' +
|
78
|
+
'specified if auth_method is "private_key"')
|
79
|
+
elsif !@private_key_path
|
80
|
+
raise Fluent::ConfigError, ('"private_key_path" must be ' +
|
81
|
+
'specified if auth_method is "private_key"')
|
82
|
+
elsif !@private_key_passphrase
|
83
|
+
raise Fluent::ConfigError, ('"private_key_passphrase" must be ' +
|
84
|
+
'specified if auth_method is "private_key"')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
unless @fetch_gce_metadata
|
90
|
+
unless @project_id && @zone && @vm_id
|
91
|
+
raise Fluent::ConfigError,
|
92
|
+
('Please specify "project_id", "zone" and "vm_id" if you set "fetch_gce_metadata" to false')
|
74
93
|
end
|
75
|
-
when 'compute_engine_service_account'
|
76
|
-
# pass
|
77
|
-
else
|
78
|
-
raise Fluent::ConfigError,
|
79
|
-
('Unrecognized "auth_method" parameter. Please specify either ' +
|
80
|
-
'"compute_engine_service_account" or "private_key".')
|
81
94
|
end
|
82
95
|
end
|
83
96
|
|
@@ -88,18 +101,21 @@ module Fluent
|
|
88
101
|
|
89
102
|
@successful_call = false
|
90
103
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
104
|
+
if @fetch_gce_metadata
|
105
|
+
# Grab metadata about the Google Compute Engine instance that we're on.
|
106
|
+
@project_id = fetch_metadata('project/project-id')
|
107
|
+
fully_qualified_zone = fetch_metadata('instance/zone')
|
108
|
+
@zone = fully_qualified_zone.rpartition('/')[2]
|
109
|
+
@vm_id = fetch_metadata('instance/id')
|
110
|
+
end
|
96
111
|
# TODO: Send instance tags and/or hostname with the logs as well?
|
97
112
|
@common_labels = {}
|
98
113
|
|
99
114
|
# If this is running on a Managed VM, grab the relevant App Engine
|
100
115
|
# metadata as well.
|
101
116
|
# TODO: Add config options for these to allow for running outside GCE?
|
102
|
-
attributes_string =
|
117
|
+
attributes_string = @fetch_gce_metadata ?
|
118
|
+
fetch_metadata('instance/attributes/') : ""
|
103
119
|
attributes = attributes_string.split
|
104
120
|
if (attributes.include?('gae_backend_name') &&
|
105
121
|
attributes.include?('gae_backend_version'))
|
@@ -319,19 +335,19 @@ module Fluent
|
|
319
335
|
def init_api_client
|
320
336
|
@client = Google::APIClient.new(
|
321
337
|
:application_name => 'Fluentd Google Cloud Logging plugin',
|
322
|
-
:application_version => '0.2.
|
338
|
+
:application_version => '0.2.4',
|
323
339
|
:retries => 1)
|
324
340
|
|
325
341
|
if @auth_method == 'private_key'
|
326
342
|
key = Google::APIClient::PKCS12.load_key(@private_key_path,
|
327
343
|
@private_key_passphrase)
|
328
344
|
jwt_asserter = Google::APIClient::JWTAsserter.new(
|
329
|
-
@private_key_email,
|
330
|
-
key)
|
345
|
+
@private_key_email, LOGGING_SCOPE, key)
|
331
346
|
@client.authorization = jwt_asserter.to_authorization
|
332
347
|
@client.authorization.expiry = 3600 # 3600s is the max allowed value
|
333
348
|
else
|
334
|
-
@client.authorization = Google::
|
349
|
+
@client.authorization = Google::Auth.get_application_default(
|
350
|
+
LOGGING_SCOPE)
|
335
351
|
end
|
336
352
|
end
|
337
353
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
{
|
2
|
+
"private_key_id": "cbedb7568906086cab57859bbfc1748749cc46c4",
|
3
|
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEcAASCAmEwggJdAgEAAoGBAKizy6B+aJ0Wua0e\njZ3pkHV0a2Ce1prJGhzGL5NpkbUjk6J11Kwp1yvPikTwALyy4PtUIZ+23D/unVRM\nHlKa2MkHIGjJg+mykX5Bd7eRJOxdJ0iu+eRWh7HiH+mdDntHwaz4xXihJBog71qS\n+9N+r2hy1hicybechchMiXHhmWPbAgMBAAECgYEAnSzeI4qCZxEcLtnPcXeBWpz7\nycpTAWUpycMvsjTiRxR9YRhM65YT3cJ//VhqJ2S1ThOcPCt/KqViuX4tpiKUo7qA\nH1AI9APbTo66wiGpgy+qG0wPJkKIQC8PpITNNcHqcbbAsIr3/XQduihsqxP2W2mT\na0nk5XJghs1Wa0xt28ECQQDgMqZjVDcDQyqM+bcBKJUUc/247KusjpdK70r6sx2o\nkZJGy/w9exlM5QrB6DLpw34/p5x4MoecZ7lS3yHdmaEhAkEAwKHsV4k5SXTUp4+J\nWK6GlQVvnwc+PQdX5gzt4/gWSY0Op5EQ+YD6cC7Lkz+GzXUzvmdp35c0ahS93D1/\nZLTZewJBAIjOc3cHMNadyr5BtulPEUE0ro+EY/GlBS8lu/QlDmkJg2AOI3qEvliM\nvza58S9yKny/U5yJAPVw2cZ3ABxQHeECQDyBX8PrBURuXvE2o5RoVTtvlqziAi3X\nJaPLwdkOLqnxlX3KkgNcoM0l1amtlYDpZcRVcSs0+9TqKOyJoH8YUwsCQA4cJmv3\n119xcijXPM2HZOB5cCxTHj59MRtQlLboNZ2witDCJ20eG9AC3ZcH7csS0H9dz8Jr\nXGEoQMPD2ck4T0U\u003d\n-----END PRIVATE KEY-----\n",
|
4
|
+
"client_email": "847859579879-q8ancssppuvtv8dac0i742pslde81jgl@developer.gserviceaccount.com",
|
5
|
+
"client_id": "847859579879-q8ancssppuvtv8dac0i742pslde81jgl.apps.googleusercontent.com",
|
6
|
+
"type": "service_account"
|
7
|
+
}
|
8
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
{
|
2
|
+
"private_key_id": "cbedb7568906086cab57859bbfc1748749cc46c4",
|
3
|
+
"private_key": "-----BEGIN PRIVATE KEY-----\nCeci n'est pas une cle\n-----END PRIVATE KEY-----\n",
|
4
|
+
"client_email": "847859579879-q8ancssppuvtv8dac0i742pslde81jgl@developer.gserviceaccount.com",
|
5
|
+
"client_id": "847859579879-q8ancssppuvtv8dac0i742pslde81jgl.apps.googleusercontent.com",
|
6
|
+
"type": "service_account"
|
7
|
+
}
|
8
|
+
|
@@ -14,50 +14,34 @@
|
|
14
14
|
|
15
15
|
require 'helper'
|
16
16
|
require 'json'
|
17
|
+
require 'mocha/test_unit'
|
17
18
|
require 'webmock/test_unit'
|
18
19
|
|
19
20
|
class GoogleCloudOutputTest < Test::Unit::TestCase
|
20
21
|
def setup
|
21
22
|
Fluent::Test.setup
|
22
|
-
|
23
|
-
|
24
|
-
stub_metadata_request('project/project-id', PROJECT_ID)
|
25
|
-
stub_metadata_request('instance/zone', FULLY_QUALIFIED_ZONE)
|
26
|
-
stub_metadata_request('instance/id', VM_ID)
|
27
|
-
stub_metadata_request('instance/attributes/',
|
28
|
-
"attribute1\nattribute2\nattribute3")
|
29
|
-
|
30
|
-
stub_request(:post, 'https://accounts.google.com/o/oauth2/token').
|
31
|
-
with(:body => hash_including({:grant_type => AUTH_GRANT_TYPE})).
|
32
|
-
to_return(:body => "{\"access_token\": \"#{FAKE_AUTH_TOKEN}\"}",
|
33
|
-
:status => 200,
|
34
|
-
:headers => {'Content-Length' => FAKE_AUTH_TOKEN,
|
35
|
-
'Content-Type' => 'application/json' })
|
36
|
-
|
23
|
+
ENV.delete('GOOGLE_APPLICATION_CREDENTIALS')
|
24
|
+
setup_auth_stubs
|
37
25
|
@logs_sent = []
|
38
26
|
end
|
39
27
|
|
40
|
-
def setup_logging_stubs
|
41
|
-
[COMPUTE_PARAMS, VMENGINE_PARAMS].each do |params|
|
42
|
-
stub_request(:post, uri_for_log(params)).to_return do |request|
|
43
|
-
@logs_sent << JSON.parse(request.body)
|
44
|
-
{:body => ''}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
28
|
PROJECT_ID = 'test-project-id'
|
50
29
|
ZONE = 'us-central1-b'
|
51
30
|
FULLY_QUALIFIED_ZONE = 'projects/' + PROJECT_ID + '/zones/' + ZONE
|
52
31
|
VM_ID = '9876543210'
|
53
32
|
|
33
|
+
CUSTOM_PROJECT_ID = 'test-custom-project-id'
|
34
|
+
CUSTOM_ZONE = 'us-custom-central1-b'
|
35
|
+
CUSTOM_FULLY_QUALIFIED_ZONE = 'projects/' + PROJECT_ID + '/zones/' + ZONE
|
36
|
+
CUSTOM_VM_ID = 'C9876543210'
|
37
|
+
|
54
38
|
MANAGED_VM_BACKEND_NAME = 'default'
|
55
39
|
MANAGED_VM_BACKEND_VERSION = 'guestbook2.0'
|
56
40
|
|
57
41
|
AUTH_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
58
42
|
FAKE_AUTH_TOKEN = 'abc123'
|
59
43
|
|
60
|
-
|
44
|
+
APPLICATION_DEFAULT_CONFIG = %[
|
61
45
|
]
|
62
46
|
|
63
47
|
PRIVATE_KEY_CONFIG = %[
|
@@ -66,16 +50,25 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
66
50
|
private_key_path test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
|
67
51
|
]
|
68
52
|
|
69
|
-
|
53
|
+
CUSTOM_METADATA_CONFIG = %[
|
54
|
+
fetch_gce_metadata false
|
55
|
+
project_id #{CUSTOM_PROJECT_ID}
|
56
|
+
zone #{CUSTOM_ZONE}
|
57
|
+
vm_id #{CUSTOM_VM_ID}
|
58
|
+
]
|
59
|
+
|
60
|
+
INVALID_CONFIG_MISSING_PRIVATE_KEY_PATH = %[
|
70
61
|
auth_method private_key
|
71
62
|
private_key_email nobody@example.com
|
72
63
|
]
|
73
|
-
|
64
|
+
INVALID_CONFIG_MISSING_PRIVATE_KEY_EMAIL = %[
|
74
65
|
auth_method private_key
|
75
66
|
private_key_path /fake/path/to/key
|
76
67
|
]
|
77
|
-
|
78
|
-
|
68
|
+
INVALID_CONFIG_MISSING_METADATA_VM_ID = %[
|
69
|
+
fetch_gce_metadata false
|
70
|
+
project_id #{CUSTOM_PROJECT_ID}
|
71
|
+
zone #{CUSTOM_ZONE}
|
79
72
|
]
|
80
73
|
|
81
74
|
COMPUTE_SERVICE_NAME = 'compute.googleapis.com'
|
@@ -84,6 +77,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
84
77
|
COMPUTE_PARAMS = {
|
85
78
|
'service_name' => COMPUTE_SERVICE_NAME,
|
86
79
|
'log_name' => 'test',
|
80
|
+
'project_id' => PROJECT_ID,
|
81
|
+
'zone' => ZONE,
|
87
82
|
'labels' => {
|
88
83
|
"#{COMPUTE_SERVICE_NAME}/resource_type" => 'instance',
|
89
84
|
"#{COMPUTE_SERVICE_NAME}/resource_id" => VM_ID
|
@@ -93,6 +88,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
93
88
|
VMENGINE_PARAMS = {
|
94
89
|
'service_name' => APPENGINE_SERVICE_NAME,
|
95
90
|
'log_name' => "#{APPENGINE_SERVICE_NAME}%2Ftest",
|
91
|
+
'project_id' => PROJECT_ID,
|
92
|
+
'zone' => ZONE,
|
96
93
|
'labels' => {
|
97
94
|
"#{APPENGINE_SERVICE_NAME}/module_id" => MANAGED_VM_BACKEND_NAME,
|
98
95
|
"#{APPENGINE_SERVICE_NAME}/version_id" => MANAGED_VM_BACKEND_VERSION,
|
@@ -101,44 +98,73 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
101
98
|
}
|
102
99
|
}
|
103
100
|
|
104
|
-
|
101
|
+
CUSTOM_PARAMS = {
|
102
|
+
'service_name' => COMPUTE_SERVICE_NAME,
|
103
|
+
'log_name' => 'test',
|
104
|
+
'project_id' => CUSTOM_PROJECT_ID,
|
105
|
+
'zone' => CUSTOM_ZONE,
|
106
|
+
'labels' => {
|
107
|
+
"#{COMPUTE_SERVICE_NAME}/resource_type" => 'instance',
|
108
|
+
"#{COMPUTE_SERVICE_NAME}/resource_id" => CUSTOM_VM_ID
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
def create_driver(conf=APPLICATION_DEFAULT_CONFIG)
|
105
113
|
Fluent::Test::BufferedOutputTestDriver.new(
|
106
114
|
Fluent::GoogleCloudOutput).configure(conf)
|
107
115
|
end
|
108
116
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
117
|
+
def test_configure_service_account_application_default
|
118
|
+
setup_gce_metadata_stubs
|
119
|
+
d = create_driver(APPLICATION_DEFAULT_CONFIG)
|
120
|
+
assert d.instance.auth_method.nil?
|
112
121
|
end
|
113
122
|
|
114
|
-
def
|
123
|
+
def test_configure_service_account_private_key
|
124
|
+
setup_gce_metadata_stubs
|
115
125
|
d = create_driver(PRIVATE_KEY_CONFIG)
|
116
126
|
assert_equal 'private_key', d.instance.auth_method
|
117
127
|
end
|
118
128
|
|
129
|
+
def test_configure_custom_metadata
|
130
|
+
d = create_driver(CUSTOM_METADATA_CONFIG)
|
131
|
+
assert_equal CUSTOM_PROJECT_ID, d.instance.project_id
|
132
|
+
assert_equal CUSTOM_ZONE, d.instance.zone
|
133
|
+
assert_equal CUSTOM_VM_ID, d.instance.vm_id
|
134
|
+
end
|
135
|
+
|
119
136
|
def test_configure_invalid_configs
|
137
|
+
exception_count = 0
|
120
138
|
begin
|
121
|
-
d = create_driver(
|
122
|
-
assert false
|
139
|
+
d = create_driver(INVALID_CONFIG_MISSING_PRIVATE_KEY_PATH)
|
123
140
|
rescue Fluent::ConfigError => error
|
124
141
|
assert error.message.include? 'private_key_path'
|
142
|
+
exception_count += 1
|
125
143
|
end
|
144
|
+
assert_equal 1, exception_count
|
145
|
+
|
146
|
+
exception_count = 0
|
126
147
|
begin
|
127
|
-
d = create_driver(
|
128
|
-
assert false
|
148
|
+
d = create_driver(INVALID_CONFIG_MISSING_PRIVATE_KEY_EMAIL)
|
129
149
|
rescue Fluent::ConfigError => error
|
130
150
|
assert error.message.include? 'private_key_email'
|
151
|
+
exception_count += 1
|
131
152
|
end
|
153
|
+
assert_equal 1, exception_count
|
154
|
+
|
155
|
+
exception_count = 0
|
132
156
|
begin
|
133
|
-
d = create_driver(
|
134
|
-
assert false
|
157
|
+
d = create_driver(INVALID_CONFIG_MISSING_METADATA_VM_ID)
|
135
158
|
rescue Fluent::ConfigError => error
|
136
|
-
assert error.message.include? '
|
159
|
+
assert error.message.include? 'fetch_gce_metadata'
|
160
|
+
exception_count += 1
|
137
161
|
end
|
162
|
+
assert_equal 1, exception_count
|
138
163
|
end
|
139
164
|
|
140
165
|
def test_metadata_loading
|
141
|
-
|
166
|
+
setup_gce_metadata_stubs
|
167
|
+
d = create_driver()
|
142
168
|
d.run
|
143
169
|
assert_equal PROJECT_ID, d.instance.project_id
|
144
170
|
assert_equal ZONE, d.instance.zone
|
@@ -147,8 +173,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
147
173
|
end
|
148
174
|
|
149
175
|
def test_managed_vm_metadata_loading
|
176
|
+
setup_gce_metadata_stubs
|
150
177
|
setup_managed_vm_metadata_stubs
|
151
|
-
d = create_driver(
|
178
|
+
d = create_driver()
|
152
179
|
d.run
|
153
180
|
assert_equal PROJECT_ID, d.instance.project_id
|
154
181
|
assert_equal ZONE, d.instance.zone
|
@@ -158,7 +185,53 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
158
185
|
assert_equal MANAGED_VM_BACKEND_VERSION, d.instance.gae_backend_version
|
159
186
|
end
|
160
187
|
|
188
|
+
def test_gce_metadata_does_not_load_when_fetch_gce_metadata_is_false
|
189
|
+
Fluent::GoogleCloudOutput.any_instance.expects(:fetch_metadata).never
|
190
|
+
d = create_driver(CUSTOM_METADATA_CONFIG)
|
191
|
+
d.run
|
192
|
+
assert_equal CUSTOM_PROJECT_ID, d.instance.project_id
|
193
|
+
assert_equal CUSTOM_ZONE, d.instance.zone
|
194
|
+
assert_equal CUSTOM_VM_ID, d.instance.vm_id
|
195
|
+
assert_equal false, d.instance.running_on_managed_vm
|
196
|
+
end
|
197
|
+
|
161
198
|
def test_one_log
|
199
|
+
setup_gce_metadata_stubs
|
200
|
+
setup_logging_stubs
|
201
|
+
d = create_driver()
|
202
|
+
d.emit({'message' => log_entry(0)})
|
203
|
+
d.run
|
204
|
+
verify_log_entries(1, COMPUTE_PARAMS)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_one_log_with_json_credentials
|
208
|
+
setup_gce_metadata_stubs
|
209
|
+
setup_logging_stubs
|
210
|
+
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = 'test/plugin/data/credentials.json'
|
211
|
+
d = create_driver()
|
212
|
+
d.emit({'message' => log_entry(0)})
|
213
|
+
d.run
|
214
|
+
verify_log_entries(1, COMPUTE_PARAMS)
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_one_log_with_invalid_json_credentials
|
218
|
+
setup_gce_metadata_stubs
|
219
|
+
setup_logging_stubs
|
220
|
+
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = 'test/plugin/data/invalid_credentials.json'
|
221
|
+
d = create_driver()
|
222
|
+
d.emit({'message' => log_entry(0)})
|
223
|
+
exception_count = 0
|
224
|
+
begin
|
225
|
+
d.run
|
226
|
+
rescue RuntimeError => error
|
227
|
+
assert error.message.include? 'Unable to read the credential file'
|
228
|
+
exception_count += 1
|
229
|
+
end
|
230
|
+
assert_equal 1, exception_count
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_one_log_private_key
|
234
|
+
setup_gce_metadata_stubs
|
162
235
|
setup_logging_stubs
|
163
236
|
d = create_driver(PRIVATE_KEY_CONFIG)
|
164
237
|
d.emit({'message' => log_entry(0)})
|
@@ -166,9 +239,20 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
166
239
|
verify_log_entries(1, COMPUTE_PARAMS)
|
167
240
|
end
|
168
241
|
|
242
|
+
def test_one_log_custom_metadata
|
243
|
+
Fluent::GoogleCloudOutput.any_instance.expects(:fetch_metadata).never
|
244
|
+
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = 'test/plugin/data/credentials.json'
|
245
|
+
setup_logging_stubs
|
246
|
+
d = create_driver(CUSTOM_METADATA_CONFIG)
|
247
|
+
d.emit({'message' => log_entry(0)})
|
248
|
+
d.run
|
249
|
+
verify_log_entries(1, CUSTOM_PARAMS)
|
250
|
+
end
|
251
|
+
|
169
252
|
def test_struct_payload_log
|
253
|
+
setup_gce_metadata_stubs
|
170
254
|
setup_logging_stubs
|
171
|
-
d = create_driver(
|
255
|
+
d = create_driver()
|
172
256
|
d.emit({'msg' => log_entry(0), 'tag2' => 'test', 'data' => 5000})
|
173
257
|
d.run
|
174
258
|
verify_log_entries(1, COMPUTE_PARAMS, 'structPayload') do |entry|
|
@@ -180,8 +264,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
180
264
|
end
|
181
265
|
|
182
266
|
def test_timestamps
|
267
|
+
setup_gce_metadata_stubs
|
183
268
|
setup_logging_stubs
|
184
|
-
d = create_driver(
|
269
|
+
d = create_driver()
|
185
270
|
expected_ts = []
|
186
271
|
emit_index = 0
|
187
272
|
[Time.at(123456.789), Time.at(0), Time.now].each do |ts|
|
@@ -208,8 +293,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
208
293
|
end
|
209
294
|
|
210
295
|
def test_severities
|
296
|
+
setup_gce_metadata_stubs
|
211
297
|
setup_logging_stubs
|
212
|
-
d = create_driver(
|
298
|
+
d = create_driver()
|
213
299
|
expected_severity = []
|
214
300
|
emit_index = 0
|
215
301
|
# Array of pairs of [parsed_severity, expected_severity]
|
@@ -229,8 +315,9 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
229
315
|
end
|
230
316
|
|
231
317
|
def test_multiple_logs
|
318
|
+
setup_gce_metadata_stubs
|
232
319
|
setup_logging_stubs
|
233
|
-
d = create_driver(
|
320
|
+
d = create_driver()
|
234
321
|
# Only test a few values because otherwise the test can take minutes.
|
235
322
|
[2, 3, 5, 11, 50].each do |n|
|
236
323
|
# The test driver doesn't clear its buffer of entries after running, so
|
@@ -244,11 +331,12 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
244
331
|
end
|
245
332
|
|
246
333
|
def test_client_error
|
334
|
+
setup_gce_metadata_stubs
|
247
335
|
# The API Client should not retry this and the plugin should consume
|
248
336
|
# the exception.
|
249
337
|
stub_request(:post, uri_for_log(COMPUTE_PARAMS)).to_return(
|
250
338
|
:status => 400, :body => "Bad Request")
|
251
|
-
d = create_driver(
|
339
|
+
d = create_driver()
|
252
340
|
d.emit({'message' => log_entry(0)})
|
253
341
|
d.run
|
254
342
|
assert_requested(:post, uri_for_log(COMPUTE_PARAMS), :times => 1)
|
@@ -256,9 +344,10 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
256
344
|
|
257
345
|
# helper for the ClientError retriable special cases below.
|
258
346
|
def client_error_helper(message)
|
347
|
+
setup_gce_metadata_stubs
|
259
348
|
stub_request(:post, uri_for_log(COMPUTE_PARAMS)).to_return(
|
260
349
|
:status => 401, :body => message)
|
261
|
-
d = create_driver(
|
350
|
+
d = create_driver()
|
262
351
|
d.emit({'message' => log_entry(0)})
|
263
352
|
exception_count = 0
|
264
353
|
begin
|
@@ -292,11 +381,12 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
292
381
|
end
|
293
382
|
|
294
383
|
def test_server_error
|
384
|
+
setup_gce_metadata_stubs
|
295
385
|
# The API client should retry this once, then throw an exception which
|
296
386
|
# gets propagated through the plugin.
|
297
387
|
stub_request(:post, uri_for_log(COMPUTE_PARAMS)).to_return(
|
298
388
|
:status => 500, :body => "Server Error")
|
299
|
-
d = create_driver(
|
389
|
+
d = create_driver()
|
300
390
|
d.emit({'message' => log_entry(0)})
|
301
391
|
exception_count = 0
|
302
392
|
begin
|
@@ -310,18 +400,20 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
310
400
|
end
|
311
401
|
|
312
402
|
def test_one_managed_vm_log
|
403
|
+
setup_gce_metadata_stubs
|
313
404
|
setup_managed_vm_metadata_stubs
|
314
405
|
setup_logging_stubs
|
315
|
-
d = create_driver(
|
406
|
+
d = create_driver()
|
316
407
|
d.emit({'message' => log_entry(0)})
|
317
408
|
d.run
|
318
409
|
verify_log_entries(1, VMENGINE_PARAMS)
|
319
410
|
end
|
320
411
|
|
321
412
|
def test_multiple_managed_vm_logs
|
413
|
+
setup_gce_metadata_stubs
|
322
414
|
setup_managed_vm_metadata_stubs
|
323
415
|
setup_logging_stubs
|
324
|
-
d = create_driver(
|
416
|
+
d = create_driver()
|
325
417
|
[2, 3, 5, 11, 50].each do |n|
|
326
418
|
# The test driver doesn't clear its buffer of entries after running, so
|
327
419
|
# do it manually here.
|
@@ -414,7 +506,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
414
506
|
private
|
415
507
|
|
416
508
|
def uri_for_log(config)
|
417
|
-
'https://logging.googleapis.com/v1beta3/projects/' +
|
509
|
+
'https://logging.googleapis.com/v1beta3/projects/' + config['project_id'] +
|
418
510
|
'/logs/' + config['log_name'] + '/entries:write'
|
419
511
|
end
|
420
512
|
|
@@ -424,6 +516,53 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
424
516
|
:headers => {'Content-Length' => response_body.length})
|
425
517
|
end
|
426
518
|
|
519
|
+
def setup_gce_metadata_stubs
|
520
|
+
# Create stubs for all the GCE metadata lookups the agent needs to make.
|
521
|
+
stub_metadata_request('project/project-id', PROJECT_ID)
|
522
|
+
stub_metadata_request('instance/zone', FULLY_QUALIFIED_ZONE)
|
523
|
+
stub_metadata_request('instance/id', VM_ID)
|
524
|
+
stub_metadata_request('instance/attributes/',
|
525
|
+
"attribute1\nattribute2\nattribute3")
|
526
|
+
|
527
|
+
# Used by 'googleauth' to test whether we're running on GCE.
|
528
|
+
# It only cares about the request succeeding with Metdata-Flavor: Google.
|
529
|
+
stub_request(:get, 'http://169.254.169.254').
|
530
|
+
to_return(:status => 200, :headers => {'Metadata-Flavor' => 'Google'})
|
531
|
+
|
532
|
+
# Used by 'googleauth' to fetch the default service account credentials.
|
533
|
+
stub_request(:get, 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token').
|
534
|
+
to_return(:body => "{\"access_token\": \"#{FAKE_AUTH_TOKEN}\"}",
|
535
|
+
:status => 200,
|
536
|
+
:headers => {'Content-Length' => FAKE_AUTH_TOKEN.length,
|
537
|
+
'Content-Type' => 'application/json' })
|
538
|
+
end
|
539
|
+
|
540
|
+
def setup_logging_stubs
|
541
|
+
[COMPUTE_PARAMS, VMENGINE_PARAMS, CUSTOM_PARAMS].each do |params|
|
542
|
+
stub_request(:post, uri_for_log(params)).to_return do |request|
|
543
|
+
@logs_sent << JSON.parse(request.body)
|
544
|
+
{:body => ''}
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
def setup_auth_stubs
|
550
|
+
# Used when loading credentials from a JSON file.
|
551
|
+
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token').
|
552
|
+
with(:body => hash_including({:grant_type => AUTH_GRANT_TYPE})).
|
553
|
+
to_return(:body => "{\"access_token\": \"#{FAKE_AUTH_TOKEN}\"}",
|
554
|
+
:status => 200,
|
555
|
+
:headers => {'Content-Length' => FAKE_AUTH_TOKEN.length,
|
556
|
+
'Content-Type' => 'application/json' })
|
557
|
+
# Used for 'private_key' auth.
|
558
|
+
stub_request(:post, 'https://accounts.google.com/o/oauth2/token').
|
559
|
+
with(:body => hash_including({:grant_type => AUTH_GRANT_TYPE})).
|
560
|
+
to_return(:body => "{\"access_token\": \"#{FAKE_AUTH_TOKEN}\"}",
|
561
|
+
:status => 200,
|
562
|
+
:headers => {'Content-Length' => FAKE_AUTH_TOKEN.length,
|
563
|
+
'Content-Type' => 'application/json' })
|
564
|
+
end
|
565
|
+
|
427
566
|
def setup_managed_vm_metadata_stubs
|
428
567
|
stub_metadata_request(
|
429
568
|
'instance/attributes/',
|
@@ -462,7 +601,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
462
601
|
assert_equal "test log entry #{i}", entry['textPayload'], batch
|
463
602
|
end
|
464
603
|
|
465
|
-
assert_equal
|
604
|
+
assert_equal params['zone'], entry['metadata']['zone']
|
466
605
|
assert_equal params['service_name'], entry['metadata']['serviceName']
|
467
606
|
check_labels entry, batch['commonLabels'], params['labels']
|
468
607
|
if (block_given?)
|
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.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -44,6 +44,22 @@ dependencies:
|
|
44
44
|
- - ! '>='
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0.8'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: googleauth
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0.4'
|
47
63
|
- !ruby/object:Gem::Dependency
|
48
64
|
name: rake
|
49
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,6 +92,38 @@ dependencies:
|
|
76
92
|
- - ! '>='
|
77
93
|
- !ruby/object:Gem::Version
|
78
94
|
version: 1.17.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: test-unit
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 3.0.2
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.0.2
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mocha
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ~>
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '1.1'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ~>
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '1.1'
|
79
127
|
description: Fluentd plugin to stream logs to the Google Cloud Platform's logging
|
80
128
|
API, which will make them viewable in the Developer Console's log viewer and can
|
81
129
|
optionally store them in Google Cloud Storage and/or BigQuery. This is an official
|
@@ -86,17 +134,19 @@ executables: []
|
|
86
134
|
extensions: []
|
87
135
|
extra_rdoc_files: []
|
88
136
|
files:
|
89
|
-
- lib/fluent/plugin/out_google_cloud.rb
|
90
|
-
- Gemfile.lock
|
91
|
-
- CONTRIBUTING
|
92
|
-
- README.rdoc
|
93
137
|
- test/helper.rb
|
94
|
-
- test/plugin/test_out_google_cloud.rb
|
95
138
|
- test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
|
139
|
+
- test/plugin/data/credentials.json
|
140
|
+
- test/plugin/data/invalid_credentials.json
|
141
|
+
- test/plugin/test_out_google_cloud.rb
|
96
142
|
- LICENSE
|
97
143
|
- Rakefile
|
98
|
-
- Gemfile
|
99
144
|
- fluent-plugin-google-cloud.gemspec
|
145
|
+
- lib/fluent/plugin/out_google_cloud.rb
|
146
|
+
- CONTRIBUTING
|
147
|
+
- Gemfile.lock
|
148
|
+
- Gemfile
|
149
|
+
- README.rdoc
|
100
150
|
homepage: https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud
|
101
151
|
licenses:
|
102
152
|
- Apache 2.0
|
@@ -124,5 +174,7 @@ specification_version: 3
|
|
124
174
|
summary: Fluentd plugin to stream logs to the Google Cloud Platform's logging API
|
125
175
|
test_files:
|
126
176
|
- test/helper.rb
|
127
|
-
- test/plugin/test_out_google_cloud.rb
|
128
177
|
- test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
|
178
|
+
- test/plugin/data/credentials.json
|
179
|
+
- test/plugin/data/invalid_credentials.json
|
180
|
+
- test/plugin/test_out_google_cloud.rb
|