fluent-plugin-gcloud-pubsub-custom 0.1.4 → 0.2.0

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: 8c9f2243c6c609552b125ea53d060467197681fe
4
- data.tar.gz: 42ebb7ee74c628d14954f1fccc713be595b9a577
3
+ metadata.gz: 08c5555e386df16b94ce1a8db279f952893b3f3b
4
+ data.tar.gz: e6eee873e191628778e9793a4545baf4a9d90344
5
5
  SHA512:
6
- metadata.gz: af2b11d0ecda25cdc2a6b6db2a0a640277ce0a69c722d0899da60a6306f3fb3c00a3676113942a3c4ef7c3c6c5c77673deea7462fa0ac882e3b95d1cb4a797f2
7
- data.tar.gz: adc7c0a09c842e96540e1638c36ab3dec913f2cebc4ed73a599df0f4d74e85a94f31f97da99745787649d4555b557859476f1e5e58925bc8513b84444f72e717
6
+ metadata.gz: eb8869520add948a27084fd46c58740455432f35bc29210efc77e4578901f5b10762c2b24a56eede4df04bfa54b57eaa210de5d022a11bcd5555e925939849aa
7
+ data.tar.gz: 3d2ef099388aa1a0260061e3cc134d84c9326c29202414643a2fe3612ca27fed9697b763ddd2ead9c3f68aa3ef3adb85d55b1e00de77b1b6d79e035b16e452a7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  ## ChangeLog
2
2
 
3
+ - Release 0.2.0 - 2016/10/15
4
+ - Input plugin
5
+ - Add HTTP RPC feature
3
6
  - Release 0.1.4 - 2016/09/19
4
7
  - Input plugin
5
8
  - `pull_interval` can be specified float value
data/README.md CHANGED
@@ -89,6 +89,9 @@ Use `gcloud_pubsub` input plugin.
89
89
  return_immediately true
90
90
  pull_interval 0.5
91
91
  format json
92
+ enable_rpc true
93
+ rpc_bind 0.0.0.0
94
+ rpc_port 24680
92
95
  </source>
93
96
  ```
94
97
 
@@ -110,11 +113,17 @@ Use `gcloud_pubsub` input plugin.
110
113
  - See maxMessages on https://cloud.google.com/pubsub/subscriber#receiving-pull-messages
111
114
  - `return_immediately` (optional, default: `true`)
112
115
  - See returnImmediately on https://cloud.google.com/pubsub/subscriber#receiving-pull-messages
113
- - If `return_immediately` is `false`, this plugin ignore `pull_interval`.
116
+ - If `return_immediately` is `true` and pulling message is stopped by HTTP RPC, this plugin wait `pull_interval` each pull.
114
117
  - `pull_interval` (optional, default: `5.0`)
115
118
  - Pulling messages by intervals of specified seconds.
116
119
  - `format` (optional, default: `json`)
117
120
  - Set input format. See format section in http://docs.fluentd.org/articles/in_tail
121
+ - `enable_rpc` (optional, default: `false`)
122
+ - If `true` is specified, HTTP RPC to stop or start pulling message is enabled.
123
+ - `rpc_bind` (optional, default: `0.0.0.0`)
124
+ - Bind IP address for HTTP RPC.
125
+ - `rpc_port` (optional, default: `24680`)
126
+ - Port for HTTP RPC.
118
127
 
119
128
  ## Contributing
120
129
 
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
7
7
  gem.license = "MIT"
8
8
  gem.homepage = "https://github.com/mia-0032/fluent-plugin-gcloud-pubsub-custom"
9
9
  gem.summary = gem.description
10
- gem.version = "0.1.4"
10
+ gem.version = "0.2.0"
11
11
  gem.authors = ["Yoshihiro MIYAI"]
12
12
  gem.email = "msparrow17@gmail.com"
13
13
  gem.has_rdoc = false
@@ -1,3 +1,6 @@
1
+ require 'json'
2
+ require 'webrick'
3
+
1
4
  require 'fluent/input'
2
5
  require 'fluent/parser'
3
6
 
@@ -8,14 +11,18 @@ module Fluent
8
11
  Fluent::Plugin.register_input('gcloud_pubsub', self)
9
12
 
10
13
  config_param :tag, :string
11
- config_param :project, :string, :default => nil
12
- config_param :key, :string, :default => nil
14
+ config_param :project, :string, default: nil
15
+ config_param :key, :string, default: nil
13
16
  config_param :topic, :string
14
17
  config_param :subscription, :string
15
- config_param :pull_interval, :float, :default => 5.0
16
- config_param :max_messages, :integer, :default => 100
17
- config_param :return_immediately, :bool, :default => true
18
- config_param :format, :string, :default => 'json'
18
+ config_param :pull_interval, :float, default: 5.0
19
+ config_param :max_messages, :integer, default: 100
20
+ config_param :return_immediately, :bool, default: true
21
+ config_param :format, :string, default: 'json'
22
+ # for HTTP RPC
23
+ config_param :enable_rpc, :bool, default: false
24
+ config_param :rpc_bind, :string, default: '0.0.0.0'
25
+ config_param :rpc_port, :integer, default: 24680
19
26
 
20
27
  unless method_defined?(:log)
21
28
  define_method("log") { $log }
@@ -25,33 +32,118 @@ module Fluent
25
32
  define_method("router") { Fluent::Engine }
26
33
  end
27
34
 
35
+ class RPCServlet < WEBrick::HTTPServlet::AbstractServlet
36
+ class Error < StandardError; end
37
+
38
+ def initialize(server, plugin)
39
+ super
40
+ @plugin = plugin
41
+ end
42
+
43
+ def do_GET(req, res)
44
+ begin
45
+ code, header, body = process(req, res)
46
+ rescue
47
+ code, header, body = render_json(500, {
48
+ 'ok' => false,
49
+ 'message' => 'Internal Server Error',
50
+ 'error' => "#{$!}",
51
+ 'backtrace'=> $!.backtrace
52
+ })
53
+ end
54
+
55
+ res.status = code
56
+ header.each_pair {|k,v|
57
+ res[k] = v
58
+ }
59
+ res.body = body
60
+ end
61
+
62
+ def render_json(code, obj)
63
+ [code, {'Content-Type' => 'application/json'}, obj.to_json]
64
+ end
65
+
66
+ def process(req, res)
67
+ case req.path_info
68
+ when '/stop'
69
+ @plugin.stop_pull
70
+ when '/start'
71
+ @plugin.start_pull
72
+ else
73
+ raise Error.new "Invalid path_info: #{req.path_info}"
74
+ end
75
+ render_json(200, {'ok' => true})
76
+ end
77
+ end
78
+
28
79
  def configure(conf)
29
80
  super
81
+ @rpc_srv = nil
82
+ @rpc_thread = nil
83
+ @stop_pull = false
84
+
30
85
  @parser = Plugin.new_parser(@format)
31
86
  @parser.configure(conf)
32
87
  end
33
88
 
34
89
  def start
35
90
  super
91
+ start_rpc if @enable_rpc
92
+
36
93
  @subscriber = Fluent::GcloudPubSub::Subscriber.new @project, @key, @topic, @subscription
37
94
  log.debug "connected subscription:#{@subscription} in project #{@project}"
95
+
38
96
  @stop_subscribing = false
39
97
  @subscribe_thread = Thread.new(&method(:subscribe))
40
98
  end
41
99
 
42
100
  def shutdown
43
101
  super
102
+ if @rpc_srv
103
+ @rpc_srv.shutdown
104
+ @rpc_srv = nil
105
+ end
106
+ if @rpc_thread
107
+ @rpc_thread.join
108
+ @rpc_thread = nil
109
+ end
44
110
  @stop_subscribing = true
45
111
  @subscribe_thread.join
46
112
  end
47
113
 
114
+ def stop_pull
115
+ @stop_pull = true
116
+ log.info "stop pull from subscription:#{@subscription}"
117
+ end
118
+
119
+ def start_pull
120
+ @stop_pull = false
121
+ log.info "start pull from subscription:#{@subscription}"
122
+ end
123
+
48
124
  private
49
125
 
126
+ def start_rpc
127
+ log.info "listening http rpc server on http://#{@rpc_bind}:#{@rpc_port}/"
128
+ @rpc_srv = WEBrick::HTTPServer.new(
129
+ {
130
+ BindAddress: @rpc_bind,
131
+ Port: @rpc_port,
132
+ Logger: WEBrick::Log.new(STDERR, WEBrick::Log::FATAL),
133
+ AccessLog: []
134
+ }
135
+ )
136
+ @rpc_srv.mount('/api/in_gcloud_pubsub/pull/', RPCServlet, self)
137
+ @rpc_thread = Thread.new {
138
+ @rpc_srv.start
139
+ }
140
+ end
141
+
50
142
  def subscribe
51
143
  until @stop_subscribing
52
- _subscribe
144
+ _subscribe unless @stop_pull
53
145
 
54
- if @return_immediately
146
+ if @return_immediately || @stop_pull
55
147
  sleep @pull_interval
56
148
  end
57
149
  end
@@ -1,3 +1,5 @@
1
+ require 'net/http'
2
+
1
3
  require_relative "../test_helper"
2
4
 
3
5
  class GcloudPubSubInputTest < Test::Unit::TestCase
@@ -10,10 +12,19 @@ class GcloudPubSubInputTest < Test::Unit::TestCase
10
12
  format json
11
13
  ]
12
14
 
15
+ DEFAULT_HOST = '127.0.0.1'
16
+ DEFAULT_PORT = 24680
17
+
13
18
  def create_driver(conf=CONFIG)
14
19
  Fluent::Test::InputTestDriver.new(Fluent::GcloudPubSubInput).configure(conf)
15
20
  end
16
21
 
22
+ def http_get(path)
23
+ http = Net::HTTP.new(DEFAULT_HOST, DEFAULT_PORT)
24
+ req = Net::HTTP::Get.new(path, {'Content-Type' => 'application/x-www-form-urlencoded'})
25
+ http.request(req)
26
+ end
27
+
17
28
  setup do
18
29
  Fluent::Test.setup
19
30
  end
@@ -30,6 +41,9 @@ class GcloudPubSubInputTest < Test::Unit::TestCase
30
41
  return_immediately true
31
42
  pull_interval 2
32
43
  format ltsv
44
+ enable_rpc true
45
+ rpc_bind 127.0.0.1
46
+ rpc_port 24681
33
47
  ])
34
48
 
35
49
  assert_equal('test', d.instance.tag)
@@ -41,6 +55,9 @@ class GcloudPubSubInputTest < Test::Unit::TestCase
41
55
  assert_equal(1000, d.instance.max_messages)
42
56
  assert_equal(true, d.instance.return_immediately)
43
57
  assert_equal('ltsv', d.instance.format)
58
+ assert_equal(true, d.instance.enable_rpc)
59
+ assert_equal('127.0.0.1', d.instance.rpc_bind)
60
+ assert_equal(24681, d.instance.rpc_port)
44
61
  end
45
62
 
46
63
  test 'default values are configured' do
@@ -49,6 +66,9 @@ class GcloudPubSubInputTest < Test::Unit::TestCase
49
66
  assert_equal(100, d.instance.max_messages)
50
67
  assert_equal(true, d.instance.return_immediately)
51
68
  assert_equal('json', d.instance.format)
69
+ assert_equal(false, d.instance.enable_rpc)
70
+ assert_equal('0.0.0.0', d.instance.rpc_bind)
71
+ assert_equal(24680, d.instance.rpc_port)
52
72
  end
53
73
  end
54
74
 
@@ -139,5 +159,54 @@ class GcloudPubSubInputTest < Test::Unit::TestCase
139
159
  assert_equal(0.5, d.instance.pull_interval)
140
160
  assert_equal(true, d.emits.empty?)
141
161
  end
162
+
163
+ test 'stop by http rpc' do
164
+ messages = Array.new(1, DummyMessage.new)
165
+ @subscriber.pull(immediate: true, max: 100).once { messages }
166
+ @subscriber.acknowledge(messages).once
167
+
168
+ d = create_driver("#{CONFIG}\npull_interval 1.0\nenable_rpc true")
169
+ assert_equal(false, d.instance.instance_variable_get(:@stop_pull))
170
+
171
+ d.run {
172
+ http_get('/api/in_gcloud_pubsub/pull/stop')
173
+ sleep 0.75
174
+ # d.run sleeps 0.5 sec
175
+ }
176
+ emits = d.emits
177
+
178
+ assert_equal(1, emits.length)
179
+ assert_equal(true, d.instance.instance_variable_get(:@stop_pull))
180
+
181
+ emits.each do |tag, time, record|
182
+ assert_equal("test", tag)
183
+ assert_equal({"foo" => "bar"}, record)
184
+ end
185
+ end
186
+
187
+ test 'start by http rpc' do
188
+ messages = Array.new(1, DummyMessage.new)
189
+ @subscriber.pull(immediate: true, max: 100).at_least(1) { messages }
190
+ @subscriber.acknowledge(messages).at_least(1)
191
+
192
+ d = create_driver("#{CONFIG}\npull_interval 1.0\nenable_rpc true")
193
+ d.instance.stop_pull
194
+ assert_equal(true, d.instance.instance_variable_get(:@stop_pull))
195
+
196
+ d.run {
197
+ http_get('/api/in_gcloud_pubsub/pull/start')
198
+ sleep 0.75
199
+ # d.run sleeps 0.5 sec
200
+ }
201
+ emits = d.emits
202
+
203
+ assert_equal(true, emits.length > 0)
204
+ assert_equal(false, d.instance.instance_variable_get(:@stop_pull))
205
+
206
+ emits.each do |tag, time, record|
207
+ assert_equal("test", tag)
208
+ assert_equal({"foo" => "bar"}, record)
209
+ end
210
+ end
142
211
  end
143
212
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-gcloud-pubsub-custom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshihiro MIYAI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-19 00:00:00.000000000 Z
11
+ date: 2016-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd