fluent-plugin-bigquery 0.2.11 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e93c58d0a0c1da28a59026a81f9d060ec3b0e532
4
- data.tar.gz: ff810e3c6177a362a28a14cd92ea3091294212d4
3
+ metadata.gz: 24d39b32bcb8f6028618041edda11e1ffd3f6d16
4
+ data.tar.gz: a238724b34f64d36f7f319b0d6fc43f578b0dffc
5
5
  SHA512:
6
- metadata.gz: 86e853fdad235e8ab2b014e100b4e1f355ff9e11da27605e30d66aa9676de3af888f8ab0499445b42df60c884114d5d380c4fa79f6b92ee226063554c4f1344c
7
- data.tar.gz: a8e3d37c866073bfd54d25d15482387bb3454191ab5f6a41718c4a7b324d838e275b3dc2a8ce33eb213f57ee0d9a21b66cd878f5b3aec7f555be179238c4dedd
6
+ metadata.gz: 46e8ffbe6007cd2d855114671121285b4fb89b9fab378b59fcc37a5c20bd9f6587a5f8ab96a4f684cf9464d6d9da5b42b7a94f9d74e2cd6fd6769cf9c5f2f5df
7
+ data.tar.gz: 1abae1988128f8b2349aa898f1afb5f847e894c2ee88bd34126cb5981ffa0af5dd3fcf74c2e1f27fdc3c1d45814b2b000b932100f94e795ed27e8ab90e9b7894
data/README.md CHANGED
@@ -110,15 +110,57 @@ section in the Google BigQuery document.
110
110
 
111
111
  There are two methods supported to fetch access token for the service account.
112
112
 
113
- 1. Public-Private key pair
114
- 2. Predefined access token (Compute Engine only)
113
+ 1. Public-Private key pair of GCP(Google Cloud Platform)'s service account
114
+ 2. JSON key of GCP(Google Cloud Platform)'s service account
115
+ 3. Predefined access token (Compute Engine only)
116
+ 4. Google application default credentials (http://goo.gl/IUuyuX)
115
117
 
116
- The examples above use the first one. You first need to create a service account (client ID),
118
+ #### Public-Private key pair of GCP's service account
119
+
120
+ The examples above use the first one. You first need to create a service account (client ID),
117
121
  download its private key and deploy the key with fluentd.
118
122
 
119
- On the other hand, you don't need to explicitly create a service account for fluentd when you
120
- run fluentd in Google Compute Engine. In this second authentication method, you need to
121
- add the API scope "https://www.googleapis.com/auth/bigquery" to the scope list of your
123
+ #### JSON key of GCP(Google Cloud Platform)'s service account
124
+
125
+ You first need to create a service account (client ID),
126
+ download its JSON key and deploy the key with fluentd.
127
+
128
+ ```apache
129
+ <match dummy>
130
+ type bigquery
131
+
132
+ auth_method json_key
133
+ json_key /home/username/.keys/00000000000000000000000000000000-jsonkey.json
134
+
135
+ project yourproject_id
136
+ dataset yourdataset_id
137
+ table tablename
138
+ ...
139
+ </match>
140
+ ```
141
+
142
+ You can also provide `json_key` as embedded JSON string like this.
143
+ You need to only include `private_key` and `client_email` key from JSON key file.
144
+
145
+ ```apache
146
+ <match dummy>
147
+ type bigquery
148
+
149
+ auth_method json_key
150
+ json_key {"private_key": "-----BEGIN PRIVATE KEY-----\n...", "client_email": "xxx@developer.gserviceaccount.com"}
151
+
152
+ project yourproject_id
153
+ dataset yourdataset_id
154
+ table tablename
155
+ ...
156
+ </match>
157
+ ```
158
+
159
+ #### Predefined access token (Compute Engine only)
160
+
161
+ When you run fluentd on Googlce Compute Engine instance,
162
+ you don't need to explicitly create a service account for fluentd.
163
+ In this authentication method, you need to add the API scope "https://www.googleapis.com/auth/bigquery" to the scope list of your
122
164
  Compute Engine instance, then you can configure fluentd like this.
123
165
 
124
166
  ```apache
@@ -141,6 +183,19 @@ Compute Engine instance, then you can configure fluentd like this.
141
183
  </match>
142
184
  ```
143
185
 
186
+ #### Application default credentials
187
+
188
+ The Application Default Credentials provide a simple way to get authorization credentials for use in calling Google APIs, which are described in detail at http://goo.gl/IUuyuX.
189
+
190
+ In this authentication method, the credentials returned are determined by the environment the code is running in. Conditions are checked in the following order:credentials are get from following order.
191
+
192
+ 1. The environment variable `GOOGLE_APPLICATION_CREDENTIALS` is checked. If this variable is specified it should point to a JSON key file that defines the credentials.
193
+ 2. The environment variable `GOOGLE_PRIVATE_KEY` and `GOOGLE_CLIENT_EMAIL` are checked. If this variables are specified `GOOGLE_PRIVATE_KEY` should point to `private_key`, `GOOGLE_CLIENT_EMAIL` should point to `client_email` in a JSON key.
194
+ 3. Well known path is checked. If file is exists, the file used as a JSON key file. This path is `$HOME/.config/gcloud/application_default_credentials.json`.
195
+ 4. System default path is checked. If file is exists, the file used as a JSON key file. This path is `/etc/google/auth/application_default_credentials.json`.
196
+ 5. If you are running in Google Compute Engine production, the built-in service account associated with the virtual machine instance will be used.
197
+ 6. If none of these conditions is true, an error will occur.
198
+
144
199
  ### Table id formatting
145
200
 
146
201
  `table` and `tables` options accept [Time#strftime](http://ruby-doc.org/core-1.9.3/Time.html#method-i-strftime)
@@ -282,9 +337,9 @@ You can set `insert_id_field` option to specify the field to use as `insertId` p
282
337
  ```apache
283
338
  <match dummy>
284
339
  type bigquery
285
-
340
+
286
341
  ...
287
-
342
+
288
343
  insert_id_field uuid
289
344
  field_string uuid
290
345
  </match>
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "test-unit-rr", "~> 1.0.3"
25
25
 
26
26
  spec.add_runtime_dependency "google-api-client", "~> 0.8.0"
27
+ spec.add_runtime_dependency "googleauth"
27
28
  spec.add_runtime_dependency "fluentd"
28
29
  spec.add_runtime_dependency "fluent-mixin-plaintextformatter", '>= 0.2.1'
29
30
  spec.add_runtime_dependency "fluent-mixin-config-placeholders", ">= 0.3.0"
@@ -1,6 +1,6 @@
1
1
  module Fluent
2
2
  module BigQueryPlugin
3
- VERSION = "0.2.11"
3
+ VERSION = "0.2.12"
4
4
  end
5
5
  end
6
6
 
@@ -38,14 +38,17 @@ module Fluent
38
38
  # config_param :client_secret, :string
39
39
 
40
40
  # Available methods are:
41
- # * private_key -- Use service account credential
41
+ # * private_key -- Use service account credential from pkcs12 private key file
42
42
  # * compute_engine -- Use access token available in instances of ComputeEngine
43
+ # * private_json_key -- Use service account credential from JSON key
44
+ # * application_default -- Use application default credential
43
45
  config_param :auth_method, :string, default: 'private_key'
44
46
 
45
47
  ### Service Account credential
46
48
  config_param :email, :string, default: nil
47
49
  config_param :private_key_path, :string, default: nil
48
50
  config_param :private_key_passphrase, :string, default: 'notasecret', secret: true
51
+ config_param :json_key, default: nil
49
52
 
50
53
  # see as simple reference
51
54
  # https://github.com/abronte/BigQuery/blob/master/lib/bigquery.rb
@@ -128,9 +131,10 @@ module Fluent
128
131
  super
129
132
  require 'json'
130
133
  require 'google/api_client'
131
- require 'google/api_client/client_secrets'
132
- require 'google/api_client/auth/installed_app'
133
- require 'google/api_client/auth/compute_service_account'
134
+ require 'googleauth'
135
+
136
+ # MEMO: signet-0.6.1 depend on Farady.default_connection
137
+ Faraday.default_connection.options.timeout = 60
134
138
  end
135
139
 
136
140
  # Define `log` method for v0.10.42 or earlier
@@ -148,6 +152,12 @@ module Fluent
148
152
  end
149
153
  when 'compute_engine'
150
154
  # Do nothing
155
+ when 'json_key'
156
+ unless @json_key
157
+ raise Fluent::ConfigError, "'json_key' must be specified if auth_method == 'json_key'"
158
+ end
159
+ when 'application_default'
160
+ # Do nothing
151
161
  else
152
162
  raise Fluent::ConfigError, "unrecognized 'auth_method': #{@auth_method}"
153
163
  end
@@ -227,26 +237,41 @@ module Fluent
227
237
  application_version: Fluent::BigQueryPlugin::VERSION
228
238
  )
229
239
 
240
+ scope = "https://www.googleapis.com/auth/bigquery"
241
+
230
242
  case @auth_method
231
243
  when 'private_key'
232
- key = Google::APIClient::PKCS12.load_key( @private_key_path, @private_key_passphrase )
233
- asserter = Google::APIClient::JWTAsserter.new(
234
- @email,
235
- "https://www.googleapis.com/auth/bigquery",
236
- key
237
- )
238
- # refresh_auth
239
- client.authorization = asserter.authorize
244
+ key = Google::APIClient::KeyUtils.load_from_pkcs12(@private_key_path, @private_key_passphrase)
245
+ auth = Signet::OAuth2::Client.new(
246
+ token_credential_uri: "https://accounts.google.com/o/oauth2/token",
247
+ audience: "https://accounts.google.com/o/oauth2/token",
248
+ scope: scope,
249
+ issuer: @email,
250
+ signing_key: key)
240
251
 
241
252
  when 'compute_engine'
242
- auth = Google::APIClient::ComputeServiceAccount.new
243
- auth.fetch_access_token!
244
- client.authorization = auth
253
+ auth = Google::Auth::GCECredentials.new
254
+
255
+ when 'json_key'
256
+ if File.exist?(@json_key)
257
+ auth = File.open(@json_key) do |f|
258
+ Google::Auth::ServiceAccountCredentials.new(json_key_io: f, scope: scope)
259
+ end
260
+ else
261
+ key = StringIO.new(@json_key)
262
+ auth = Google::Auth::ServiceAccountCredentials.new(json_key_io: key, scope: scope)
263
+ end
264
+
265
+ when 'application_default'
266
+ auth = Google::Auth.get_application_default([scope])
245
267
 
246
268
  else
247
269
  raise ConfigError, "Unknown auth method: #{@auth_method}"
248
270
  end
249
271
 
272
+ auth.fetch_access_token!
273
+ client.authorization = auth
274
+
250
275
  @cached_client_expiration = Time.now + 1800
251
276
  @cached_client = client
252
277
  end
@@ -349,7 +374,7 @@ module Fluent
349
374
  if @replace_record_key
350
375
  record = replace_record_key(record)
351
376
  end
352
-
377
+
353
378
  row = @fields.format(@add_time_field.call(record, time))
354
379
  unless row.empty?
355
380
  row = {"json" => row}
@@ -442,7 +467,7 @@ module Fluent
442
467
  ### https://developers.google.com/bigquery/docs/tables
443
468
  # Each field has the following properties:
444
469
  #
445
- # name - The name must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_),
470
+ # name - The name must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_),
446
471
  # and must start with a letter or underscore. The maximum length is 128 characters.
447
472
  # https://cloud.google.com/bigquery/docs/reference/v2/tables#schema.fields.name
448
473
  unless name =~ /^[_A-Za-z][_A-Za-z0-9]{,127}$/
@@ -468,7 +493,7 @@ module Fluent
468
493
  end
469
494
 
470
495
  def format_one(value)
471
- raise NotImplementedError, "Must implement in a subclass"
496
+ raise NotImplementedError, "Must implement in a subclass"
472
497
  end
473
498
 
474
499
  def to_h
@@ -1,5 +1,6 @@
1
1
  require 'helper'
2
2
  require 'google/api_client'
3
+ require 'googleauth'
3
4
  require 'fluent/plugin/buf_memory'
4
5
 
5
6
  class BigQueryOutputTest < Test::Unit::TestCase
@@ -60,14 +61,20 @@ class BigQueryOutputTest < Test::Unit::TestCase
60
61
  }
61
62
  end
62
63
 
63
- def test_configure_auth
64
+ def test_configure_auth_private_key
64
65
  key = stub!
65
- mock(Google::APIClient::PKCS12).load_key('/path/to/key', 'notasecret') { key }
66
+ mock(Google::APIClient::KeyUtils).load_from_pkcs12('/path/to/key', 'notasecret') { key }
66
67
  authorization = Object.new
67
- asserter = mock!.authorize { authorization }
68
- mock(Google::APIClient::JWTAsserter).new('foo@bar.example', API_SCOPE, key) { asserter }
69
-
70
- mock.proxy(Google::APIClient).new.with_any_args {
68
+ mock(authorization).fetch_access_token!
69
+ stub(Signet::OAuth2::Client).new
70
+ mock(Signet::OAuth2::Client).new(
71
+ token_credential_uri: "https://accounts.google.com/o/oauth2/token",
72
+ audience: "https://accounts.google.com/o/oauth2/token",
73
+ scope: API_SCOPE,
74
+ issuer: 'foo@bar.example',
75
+ signing_key: key) { authorization }
76
+
77
+ mock.proxy(Google::APIClient).new.with_any_args {
71
78
  mock!.__send__(:authorization=, authorization) {}
72
79
  }
73
80
 
@@ -75,6 +82,88 @@ class BigQueryOutputTest < Test::Unit::TestCase
75
82
  driver.instance.client()
76
83
  end
77
84
 
85
+ def test_configure_auth_compute_engine
86
+ authorization = Object.new
87
+ mock(authorization).fetch_access_token!
88
+ mock(Google::Auth::GCECredentials).new { authorization }
89
+
90
+ mock.proxy(Google::APIClient).new.with_any_args {
91
+ mock!.__send__(:authorization=, authorization) {}
92
+ }
93
+
94
+ driver = create_driver(%[
95
+ table foo
96
+ auth_method compute_engine
97
+ project yourproject_id
98
+ dataset yourdataset_id
99
+ field_integer time,status,bytes
100
+ ])
101
+ driver.instance.client()
102
+ end
103
+
104
+ def test_configure_auth_json_key_as_file
105
+ json_key_path = 'test/plugin/testdata/json_key.json'
106
+ authorization = Object.new
107
+ mock(authorization).fetch_access_token!
108
+ mock(Google::Auth::ServiceAccountCredentials).new(json_key_io: File.open(json_key_path), scope: API_SCOPE) { authorization }
109
+
110
+ mock.proxy(Google::APIClient).new.with_any_args {
111
+ mock!.__send__(:authorization=, authorization) {}
112
+ }
113
+
114
+ driver = create_driver(%[
115
+ table foo
116
+ auth_method json_key
117
+ json_key #{json_key_path}
118
+ project yourproject_id
119
+ dataset yourdataset_id
120
+ field_integer time,status,bytes
121
+ ])
122
+ driver.instance.client()
123
+ end
124
+
125
+ def test_configure_auth_json_key_as_string
126
+ json_key = '{"private_key": "X", "client_email": "xxx@developer.gserviceaccount.com"}'
127
+ json_key_io = StringIO.new(json_key)
128
+ mock(StringIO).new(json_key) { json_key_io }
129
+ authorization = Object.new
130
+ mock(authorization).fetch_access_token!
131
+ mock(Google::Auth::ServiceAccountCredentials).new(json_key_io: json_key_io, scope: API_SCOPE) { authorization }
132
+
133
+ mock.proxy(Google::APIClient).new.with_any_args {
134
+ mock!.__send__(:authorization=, authorization) {}
135
+ }
136
+
137
+ driver = create_driver(%[
138
+ table foo
139
+ auth_method json_key
140
+ json_key #{json_key}
141
+ project yourproject_id
142
+ dataset yourdataset_id
143
+ field_integer time,status,bytes
144
+ ])
145
+ driver.instance.client()
146
+ end
147
+
148
+ def test_configure_auth_application_default
149
+ authorization = Object.new
150
+ mock(authorization).fetch_access_token!
151
+ mock(Google::Auth).get_application_default([API_SCOPE]) { authorization }
152
+
153
+ mock.proxy(Google::APIClient).new.with_any_args {
154
+ mock!.__send__(:authorization=, authorization) {}
155
+ }
156
+
157
+ driver = create_driver(%[
158
+ table foo
159
+ auth_method application_default
160
+ project yourproject_id
161
+ dataset yourdataset_id
162
+ field_integer time,status,bytes
163
+ ])
164
+ driver.instance.client()
165
+ end
166
+
78
167
  def test_configure_fieldname_stripped
79
168
  driver = create_driver(%[
80
169
  table foo
@@ -86,10 +175,10 @@ class BigQueryOutputTest < Test::Unit::TestCase
86
175
  time_format %s
87
176
  time_field time
88
177
 
89
- field_integer time , status , bytes
178
+ field_integer time , status , bytes
90
179
  field_string _log_name, vhost, path, method, protocol, agent, referer, remote.host, remote.ip, remote.user
91
- field_float requesttime
92
- field_boolean bot_access , loginsession
180
+ field_float requesttime
181
+ field_boolean bot_access , loginsession
93
182
  ])
94
183
  fields = driver.instance.instance_eval{ @fields }
95
184
 
@@ -483,7 +572,7 @@ class BigQueryOutputTest < Test::Unit::TestCase
483
572
  assert fields["tty"]
484
573
  assert_equal :string, fields["tty"].type
485
574
  assert_equal :nullable, fields["tty"].mode
486
-
575
+
487
576
  assert fields["pwd"]
488
577
  assert_equal :string, fields["pwd"].type
489
578
  assert_equal :required, fields["pwd"].mode
@@ -560,7 +649,7 @@ class BigQueryOutputTest < Test::Unit::TestCase
560
649
  assert fields["tty"]
561
650
  assert_equal :string, fields["tty"].type
562
651
  assert_equal :nullable, fields["tty"].mode
563
-
652
+
564
653
  assert fields["pwd"]
565
654
  assert_equal :string, fields["pwd"].type
566
655
  assert_equal :required, fields["pwd"].mode
@@ -0,0 +1,7 @@
1
+ {
2
+ "private_key_id": "1",
3
+ "private_key": "X",
4
+ "client_email": "xxx@developer.gserviceaccount.com",
5
+ "client_id": "xxx.apps.googleusercontent.com",
6
+ "type": "service_account"
7
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-bigquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naoya Ito
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-24 00:00:00.000000000 Z
11
+ date: 2015-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.8.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: googleauth
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: fluentd
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -171,6 +185,7 @@ files:
171
185
  - test/helper.rb
172
186
  - test/plugin/test_out_bigquery.rb
173
187
  - test/plugin/testdata/apache.schema
188
+ - test/plugin/testdata/json_key.json
174
189
  - test/plugin/testdata/sudo.schema
175
190
  - test/test_load_request_body_wrapper.rb
176
191
  homepage: https://github.com/kaizenplatform/fluent-plugin-bigquery
@@ -201,5 +216,6 @@ test_files:
201
216
  - test/helper.rb
202
217
  - test/plugin/test_out_bigquery.rb
203
218
  - test/plugin/testdata/apache.schema
219
+ - test/plugin/testdata/json_key.json
204
220
  - test/plugin/testdata/sudo.schema
205
221
  - test/test_load_request_body_wrapper.rb