fluent-plugin-google-cloud 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
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
|