blender-serf 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cfaa34818e2ebbe4ed6327b625c5927d49291901
4
+ data.tar.gz: 167c55fac333e5205c4f1599aad75e68c50c2575
5
+ SHA512:
6
+ metadata.gz: 2cb10ede968b4329a18917e32e9ece5f974f4f1d3a7db8cdcef971641d6d2224014ad37bfe234670dd05cddd69b8294a8c8db597671c3cd48c9c62fc641f6ac7
7
+ data.tar.gz: ecab1c61c7e6c29c9906239558a8f81efcbb06360e6e4d88503b564d44b9eaf8fd07a26f3056659d6ce32292eb7e93df97a7ff6c179664f9f46d9e1c77853b5a
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ before_install:
2
+ - bundle install --path .bundle
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.1.0
6
+ - 2.1.2
7
+ branches:
8
+ only:
9
+ - master
10
+ script: "bundle exec rake spec"
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rubocop/rake_task'
3
+ require 'rspec/core/rake_task'
4
+ require 'yard'
5
+
6
+ YARD::Rake::YardocTask.new do |t|
7
+ t.files = ['lib/**/*.rb']
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new(:spec) do |t|
11
+ t.pattern = %w{spec/**/*_spec.rb}
12
+ end
13
+
14
+ RuboCop::RakeTask.new(:rubocop) do |t|
15
+ t.patterns = %w{Rakefile Gemfile lib/**/*.rb}
16
+ t.fail_on_error = true
17
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'blender-serf'
7
+ spec.version = '0.0.1'
8
+ spec.authors = ['Ranjib Dey']
9
+ spec.email = ['ranjib@pagerduty.com']
10
+ spec.summary = %q{Serf backend for blender}
11
+ spec.description = %q{Discover and execute tasks using serf}
12
+ spec.homepage = 'http://github.com/PagerDuty/blender-serf'
13
+ spec.license = 'Apache 2'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'pd-blender'
21
+ spec.add_dependency 'serfx'
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec'
26
+ spec.add_development_dependency 'rubocop'
27
+ spec.add_development_dependency 'simplecov'
28
+ spec.add_development_dependency 'yard'
29
+ spec.add_development_dependency 'pry'
30
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Author:: Ranjib Dey (<ranjib@pagerduty.com>)
3
+ # Copyright:: Copyright (c) 2014 PagerDuty, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'serfx'
19
+ require 'blender/log'
20
+
21
+ module Blender
22
+ module Discovery
23
+ class Serf
24
+ def initialize(opts = {})
25
+ @config = opts
26
+ end
27
+ def search(opts = {})
28
+ tags = opts[:tags] || {}
29
+ status = opts[:status] || 'alive'
30
+ name = opts[:name]
31
+ hosts = []
32
+ Blender::Log.debug("Serf memeber list call with arguments: Tags=#{tags}")
33
+ Blender::Log.debug("Serf memeber list call with arguments: status=#{status}")
34
+ Blender::Log.debug("Serf memeber list call with arguments: Name=#{name}")
35
+ Serfx.connect(@config) do |conn|
36
+ conn.members_filtered(tags, status, name).body['Members'].map do |m|
37
+ hosts << m['Name']
38
+ end
39
+ end
40
+ hosts
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,105 @@
1
+ #
2
+ # Author:: Ranjib Dey (<ranjib@pagerduty.com>)
3
+ # Copyright:: Copyright (c) 2014 PagerDuty, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'serfx'
19
+ require 'blender/exceptions'
20
+ require 'blender/log'
21
+ require 'blender/drivers/base'
22
+
23
+ module Blender
24
+ module Driver
25
+ class Serf < Base
26
+
27
+ attr_reader :filter_by, :concurrency, :filter_tag
28
+
29
+ def initialize(config = {})
30
+ cfg = config.dup
31
+ @filter_by = cfg.delete(:filter_by) || :host
32
+ @concurrency = cfg.delete(:concurrency) || 1
33
+ if @filter_by == :tag
34
+ @filter_tag = cfg.delete(:filter_tag)
35
+ raise ArgumentError, 'Must specify filter_tag when filter_by is set to :tag' unless @filter_tag
36
+ end
37
+ super(cfg)
38
+ end
39
+
40
+ def serf_query(command, host)
41
+ responses = []
42
+ Log.debug("Invoking serf query '#{command.query}' with payload '#{command.payload}' against #{@current_host}")
43
+ Log.debug("Serf RPC address #{config[:host]}:#{config[:port]}")
44
+ Serfx.connect(config) do |conn|
45
+ conn.query(*query_opts(command, host)) do |event|
46
+ responses << event
47
+ stdout.puts event.inspect
48
+ end
49
+ end
50
+ responses
51
+ end
52
+
53
+ def run_command(command, nodes)
54
+ begin
55
+ responses = serf_query(command, nodes)
56
+ if command.process
57
+ command.process.call(responses)
58
+ end
59
+ ExecOutput.new(exit_status(responses, nodes), responses.inspect, '')
60
+ rescue StandardError => e
61
+ ExecOutput.new( -1, '', e.message)
62
+ end
63
+ end
64
+
65
+ def exit_status(responses, nodes)
66
+ case filter_by
67
+ when :host
68
+ responses.size == nodes.size ? 0 : -1
69
+ when :tag, :none
70
+ 0
71
+ else
72
+ raise ArgumentError, "Unknown filter_by option: #{filter_by}"
73
+ end
74
+ end
75
+
76
+ def query_opts(command, nodes)
77
+ opts = { Timeout: (command.timeout || 15)*1e9.to_i}
78
+ case filter_by
79
+ when :host
80
+ opts.merge!(FilterNodes: nodes)
81
+ when :tag
82
+ raise 'filter by :tag only supports single tag' unless nodes.size == 1
83
+ opts.merge!(FilterTags: {filter_tag => nodes.first})
84
+ when :none
85
+ raise 'filter by :none only supported with localhost' unless nodes == ['localhost']
86
+ else
87
+ raise ArgumentError, "Unknown filter_by option: #{filter_by}"
88
+ end
89
+ [ command.query, command.payload, opts]
90
+ end
91
+
92
+ def execute(tasks, hosts)
93
+ Log.debug("Serf query on #{filter_by}s [#{hosts.inspect}]")
94
+ tasks.each do |task|
95
+ hosts.each_slice(concurrency) do |nodes|
96
+ cmd = run_command(task.command, nodes)
97
+ if cmd.exitstatus != 0 and !task.metadata[:ignore_failure]
98
+ raise ExecutionFailed, cmd.stderr
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,81 @@
1
+ #
2
+ # Author:: Ranjib Dey (<ranjib@pagerduty.com>)
3
+ # Copyright:: Copyright (c) 2014 PagerDuty, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'blender/exceptions'
19
+ require 'blender/log'
20
+ require 'blender/drivers/serf'
21
+ require 'json'
22
+ require 'blender/tasks/serf'
23
+
24
+ module Blender
25
+ module Driver
26
+ class SerfAsync < Serf
27
+
28
+ def dup_command(cmd, payload)
29
+ Blender::Task::Serf::SerfQuery.new(
30
+ cmd.query,
31
+ payload,
32
+ cmd.timeout,
33
+ cmd.noack
34
+ )
35
+ end
36
+
37
+ def start!(cmd, host)
38
+ resps = serf_query(dup_command(cmd, 'start'), host)
39
+ status = extract_status!(resps.first)
40
+ unless status == 'success'
41
+ raise RuntimeError, "Failed to start async serf job. Status = #{status}"
42
+ end
43
+ end
44
+
45
+ def finished?(cmd, host)
46
+ Blender::Log.debug("Checking for status")
47
+ resps = serf_query(dup_command(cmd, 'check'), host)
48
+ Blender::Log.debug("Responses: #{resps.inspect}")
49
+ Blender::Log.debug("Status:#{extract_status!(resps.first)}")
50
+ extract_status!(resps.first) == 'finished'
51
+ end
52
+
53
+ def reap!(cmd, host)
54
+ resps = serf_query(dup_command(cmd, 'reap'), host)
55
+ extract_status!(resps.first) == 'success'
56
+ end
57
+
58
+ def run_command(command, host)
59
+ begin
60
+ start!(command, host)
61
+ until finished?(command, host)
62
+ sleep 10
63
+ end
64
+ reap!(command, host)
65
+ ExecOutput.new(0, '', '')
66
+ rescue StandardError => e
67
+ ExecOutput.new( -1, '', e.message + e.backtrace.join("\n"))
68
+ end
69
+ end
70
+
71
+ def extract_status!(res)
72
+ payload = JSON.parse(res['Payload'])
73
+ unless payload['code'].zero?
74
+ raise RuntimeError, "non zero query response code: #{res}"
75
+ end
76
+ Blender::Log.debug("Payload: #{payload['result'].inspect}")
77
+ payload['result']['status']
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,4 @@
1
+ require 'blender/discoveries/serf'
2
+ require 'blender/drivers/serf'
3
+ require 'blender/tasks/serf'
4
+ require 'blender/serf_dsl'
@@ -0,0 +1,9 @@
1
+ module Blender
2
+ module SerfDSL
3
+ def serf_task(name, &block)
4
+ task = build_task(name, :serf)
5
+ task.instance_eval(&block) if block_given?
6
+ append_task(:serf, task)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Ranjib Dey (<ranjib@pagerduty.com>)
3
+ # Copyright:: Copyright (c) 2014 PagerDuty, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ require 'blender/tasks/base'
18
+
19
+ module Blender
20
+ module Task
21
+ class Serf < Blender::Task::Base
22
+
23
+ SerfQuery = Struct.new(:query, :payload, :timeout, :noack, :process)
24
+
25
+ def initialize(name, metadata = {})
26
+ super
27
+ @command = SerfQuery.new
28
+ @command.query = name
29
+ end
30
+
31
+ def execute(&block)
32
+ @command.instance_eval(&block)
33
+ end
34
+
35
+ def query(q)
36
+ @command.query = q
37
+ end
38
+
39
+ def timeout(t)
40
+ @command.timeout = t
41
+ end
42
+
43
+ def payload(pl)
44
+ @command.payload = pl
45
+ end
46
+
47
+ def no_ack(bool)
48
+ @command.noack = bool
49
+ end
50
+
51
+ def process(callback)
52
+ @command.process = callback
53
+ end
54
+
55
+ def command
56
+ @command
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'blender'
3
+ require 'blender/discoveries/serf'
4
+ require 'blender/serf_dsl'
5
+
6
+ describe Blender::Discovery::Serf do
7
+ let(:scheduler) do
8
+ Blender::Scheduler.new('test').extend Blender::SerfDSL
9
+ end
10
+ let(:discovery){described_class.new(host: '1.2.3.4')}
11
+
12
+ it '#search' do
13
+ conn = double('connection')
14
+ response = double('response', body: {'Members'=> [{'Name'=>'a'}]})
15
+ expect(conn).to receive(:members_filtered).with({}, "alive", "foo").and_return(response)
16
+ expect(Serfx).to receive(:connect).with(host: '1.2.3.4').and_yield(conn)
17
+ expect(discovery.search(name: 'foo')).to eq(['a'])
18
+ end
19
+ describe'#serf_task' do
20
+ subject(:task){scheduler.tasks.first}
21
+ before do
22
+ scheduler.serf_task('test') do
23
+ members ['b']
24
+ query 'foo'
25
+ payload 'bar'
26
+ no_ack true
27
+ end
28
+ end
29
+ it 'should have correct host list' do
30
+ expect(task.hosts).to eq(['b'])
31
+ end
32
+ it 'should use the serf task subclass' do
33
+ expect(task).to be_kind_of(Blender::Task::Serf)
34
+ end
35
+ it 'should use the serquery inner class for command' do
36
+ expect(task.command).to be_kind_of(Blender::Task::Serf::SerfQuery)
37
+ end
38
+ it 'should use serf driver subclass' do
39
+ expect(task.driver).to be_kind_of(Blender::Driver::Serf)
40
+ end
41
+ it 'should allow setting up serf query and payload' do
42
+ expect(task.command.query).to eq('foo')
43
+ expect(task.command.payload).to eq('bar')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'blender/handlers/base'
3
+
4
+ describe Blender::Driver::Serf do
5
+ let(:driver) do
6
+ described_class.new(
7
+ events: Blender::Handlers::Base.new,
8
+ host: 'foo',
9
+ port: 123,
10
+ authkey: 'xyz'
11
+ )
12
+ end
13
+ let(:tag_driver) do
14
+ described_class.new(
15
+ events: Blender::Handlers::Base.new,
16
+ host: 'foo',
17
+ port: 123,
18
+ authkey: 'xyz',
19
+ filter_by: :tag,
20
+ filter_tag: 'fake-tag'
21
+ )
22
+ end
23
+ let(:hosts) {['h1']}
24
+ let(:tasks){ Array.new(3){|n| create_serf_task("t#{n}")}}
25
+ it '#execute serf query' do
26
+ conn = double('connection')
27
+ conn_opts = { host: 'foo', port: 123, authkey: 'xyz'}
28
+ query_opts = [
29
+ 'test-query',
30
+ 'test-payload',
31
+ {:FilterNodes=>["h1"], :Timeout=>15000000000}
32
+ ]
33
+ expect(conn).to receive(:query).with(*query_opts).and_yield(Object.new).exactly(3).times
34
+ expect(Serfx).to receive(:connect).with(conn_opts).and_yield(conn).exactly(3).times
35
+ driver.execute(tasks, hosts)
36
+ end
37
+ it '#execute serf query based on tags' do
38
+ conn = double('connection')
39
+ conn_opts = { host: 'foo', port: 123, authkey: 'xyz'}
40
+ query_opts = [
41
+ 'test-query',
42
+ 'test-payload',
43
+ { FilterTags: {"fake-tag"=>"h1"}, :Timeout=>15000000000}
44
+ ]
45
+ expect(conn).to receive(:query).with(*query_opts).and_yield(Object.new).exactly(3).times
46
+ expect(Serfx).to receive(:connect).with(conn_opts).and_yield(conn).exactly(3).times
47
+ tag_driver.execute(tasks, hosts)
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ require 'blender/drivers/serf'
2
+ require 'blender/tasks/serf'
3
+
4
+ module Helper
5
+ def create_serf_task(name)
6
+ Blender::Task::Serf.new(name).tap do |t|
7
+ t.query 'test-query'
8
+ t.payload 'test-payload'
9
+ end
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.include Helper
15
+ config.mock_with :rspec do |mocks|
16
+ mocks.verify_doubled_constant_names = true
17
+ end
18
+ config.backtrace_exclusion_patterns = []
19
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blender-serf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ranjib Dey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pd-blender
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: serfx
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Discover and execute tasks using serf
140
+ email:
141
+ - ranjib@pagerduty.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - Rakefile
150
+ - blender-serf.gemspec
151
+ - lib/blender/discoveries/serf.rb
152
+ - lib/blender/drivers/serf.rb
153
+ - lib/blender/drivers/serf_async.rb
154
+ - lib/blender/serf.rb
155
+ - lib/blender/serf_dsl.rb
156
+ - lib/blender/tasks/serf.rb
157
+ - spec/blender/discoveries/serf_spec.rb
158
+ - spec/blender/drivers/serf_spec.rb
159
+ - spec/spec_helper.rb
160
+ homepage: http://github.com/PagerDuty/blender-serf
161
+ licenses:
162
+ - Apache 2
163
+ metadata: {}
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubyforge_project:
180
+ rubygems_version: 2.2.2
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: Serf backend for blender
184
+ test_files:
185
+ - spec/blender/discoveries/serf_spec.rb
186
+ - spec/blender/drivers/serf_spec.rb
187
+ - spec/spec_helper.rb
188
+ has_rdoc: