pd-blender 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 +7 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +10 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +14 -0
- data/README.md +342 -0
- data/Rakefile +21 -0
- data/bin/blend +20 -0
- data/blender.gemspec +36 -0
- data/lib/blender.rb +67 -0
- data/lib/blender/cli.rb +71 -0
- data/lib/blender/configuration.rb +45 -0
- data/lib/blender/discovery.rb +41 -0
- data/lib/blender/drivers/base.rb +40 -0
- data/lib/blender/drivers/compound.rb +29 -0
- data/lib/blender/drivers/ruby.rb +55 -0
- data/lib/blender/drivers/shellout.rb +63 -0
- data/lib/blender/drivers/ssh.rb +93 -0
- data/lib/blender/drivers/ssh_multi.rb +102 -0
- data/lib/blender/event_dispatcher.rb +45 -0
- data/lib/blender/exceptions.rb +26 -0
- data/lib/blender/handlers/base.rb +39 -0
- data/lib/blender/handlers/doc.rb +73 -0
- data/lib/blender/job.rb +73 -0
- data/lib/blender/lock/flock.rb +64 -0
- data/lib/blender/log.rb +24 -0
- data/lib/blender/rspec.rb +68 -0
- data/lib/blender/rspec/stub_registry.rb +45 -0
- data/lib/blender/scheduled_job.rb +66 -0
- data/lib/blender/scheduler.rb +114 -0
- data/lib/blender/scheduler/dsl.rb +160 -0
- data/lib/blender/scheduling_strategies/base.rb +30 -0
- data/lib/blender/scheduling_strategies/default.rb +37 -0
- data/lib/blender/scheduling_strategies/per_host.rb +38 -0
- data/lib/blender/scheduling_strategies/per_task.rb +37 -0
- data/lib/blender/tasks/base.rb +72 -0
- data/lib/blender/tasks/ruby.rb +31 -0
- data/lib/blender/tasks/shell_out.rb +30 -0
- data/lib/blender/tasks/ssh.rb +25 -0
- data/lib/blender/timer.rb +54 -0
- data/lib/blender/utils/refinements.rb +45 -0
- data/lib/blender/utils/thread_pool.rb +54 -0
- data/lib/blender/utils/ui.rb +51 -0
- data/lib/blender/version.rb +20 -0
- data/spec/blender/blender_rspec.rb +31 -0
- data/spec/blender/discovery_spec.rb +16 -0
- data/spec/blender/drivers/ssh_multi_spec.rb +16 -0
- data/spec/blender/drivers/ssh_spec.rb +17 -0
- data/spec/blender/dsl_spec.rb +19 -0
- data/spec/blender/event_dispatcher_spec.rb +17 -0
- data/spec/blender/job_spec.rb +42 -0
- data/spec/blender/lock_spec.rb +129 -0
- data/spec/blender/scheduled_job_spec.rb +30 -0
- data/spec/blender/scheduler_spec.rb +140 -0
- data/spec/blender/scheduling_strategies/default_spec.rb +75 -0
- data/spec/blender/utils/refinements_spec.rb +16 -0
- data/spec/blender/utils/thread_pool_spec.rb +16 -0
- data/spec/blender_spec.rb +37 -0
- data/spec/data/example.rb +12 -0
- data/spec/spec_helper.rb +35 -0
- metadata +304 -0
@@ -0,0 +1,64 @@
|
|
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 'timeout'
|
19
|
+
require 'fcntl'
|
20
|
+
|
21
|
+
module Blender
|
22
|
+
module Lock
|
23
|
+
class Flock
|
24
|
+
|
25
|
+
def initialize(name, options)
|
26
|
+
@path = options['path'] || File.join('/tmp', name)
|
27
|
+
@timeout = options[:timeout] || 0
|
28
|
+
@job_name = name
|
29
|
+
@lock_fd = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def acquire
|
33
|
+
@lock_fd = File.open(@path, File::CREAT|File::RDWR, 0644)
|
34
|
+
@lock_fd.fcntl( Fcntl::F_SETFD, @lock_fd.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC )
|
35
|
+
if @timeout > 0
|
36
|
+
Timeout.timeout(@timeout) do
|
37
|
+
@lock_fd.flock(File::LOCK_EX)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
locked = @lock_fd.flock(File::LOCK_NB | File::LOCK_EX)
|
41
|
+
raise LockAcquisitionError, 'Failed to lock file' if locked == false
|
42
|
+
end
|
43
|
+
@lock_fd.write({job: @job_name, pid: Process.pid }.inspect)
|
44
|
+
end
|
45
|
+
|
46
|
+
def release
|
47
|
+
@lock_fd
|
48
|
+
@lock_fd.flock(File::LOCK_UN)
|
49
|
+
@lock_fd.close
|
50
|
+
end
|
51
|
+
|
52
|
+
def with_lock
|
53
|
+
acquire
|
54
|
+
yield if block_given?
|
55
|
+
rescue Timeout::Error => e
|
56
|
+
raise LockAcquisitionError, 'Timeout while waiting for lock acquisition'
|
57
|
+
rescue LockAcquisitionError => e
|
58
|
+
raise e
|
59
|
+
ensure
|
60
|
+
release
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/blender/log.rb
ADDED
@@ -0,0 +1,24 @@
|
|
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 'mixlib/log'
|
19
|
+
|
20
|
+
module Blender
|
21
|
+
class Log
|
22
|
+
extend Mixlib::Log
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,68 @@
|
|
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
|
+
begin
|
19
|
+
require 'rspec'
|
20
|
+
require 'rspec/mocks'
|
21
|
+
rescue LoadError
|
22
|
+
abort 'Blender::RSpec requires RSpec, RSpec::Mocks'
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'blender'
|
26
|
+
require 'blender/rspec/stub_registry'
|
27
|
+
|
28
|
+
module Blender
|
29
|
+
module Discovery
|
30
|
+
alias_method :old_search, :search
|
31
|
+
def search(type, options = nil)
|
32
|
+
stub = Blender::RSpec::StubRegistry.instance.data.detect do |st|
|
33
|
+
st.type == type && st.opts == options
|
34
|
+
end
|
35
|
+
if stub
|
36
|
+
stub.return_value
|
37
|
+
else
|
38
|
+
old_search(type, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
class Utils::UI
|
43
|
+
def puts(string)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module RSpec
|
48
|
+
extend self
|
49
|
+
include Blender::Utils::Refinements
|
50
|
+
def stub_search(type, options = nil)
|
51
|
+
StubRegistry.add(type, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def noop_scheduler_from_file(file)
|
55
|
+
Blender::Configuration[:noop] = true
|
56
|
+
des = File.read(file)
|
57
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(file), 'lib')))
|
58
|
+
Blender.blend(file) do |sch|
|
59
|
+
sch.lock_options(nil)
|
60
|
+
sch.instance_eval(des, __FILE__, __LINE__)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
RSpec.configure do |config|
|
67
|
+
config.include Blender::RSpec
|
68
|
+
end
|
@@ -0,0 +1,45 @@
|
|
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 'singleton'
|
19
|
+
|
20
|
+
module Blender
|
21
|
+
module RSpec
|
22
|
+
class SearchStub
|
23
|
+
attr_reader :type, :opts, :return_value
|
24
|
+
def initialize(type, opts)
|
25
|
+
@type = type
|
26
|
+
@opts = opts
|
27
|
+
end
|
28
|
+
def and_return(value)
|
29
|
+
@return_value = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
class StubRegistry
|
33
|
+
include Singleton
|
34
|
+
attr_reader :data
|
35
|
+
def initialize
|
36
|
+
@data = []
|
37
|
+
end
|
38
|
+
def self.add(type, opts)
|
39
|
+
obj = SearchStub.new(type, opts)
|
40
|
+
instance.data << obj
|
41
|
+
obj
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,66 @@
|
|
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
|
+
module Blender
|
19
|
+
# A scheduled job encapsulates a blender based job to be executed
|
20
|
+
# at certain interval. Job is specified as a file path, where
|
21
|
+
# the file contains job written in blender's DSL. Job interval can be
|
22
|
+
# specified either via +cron+ or +every+ method
|
23
|
+
#
|
24
|
+
# +Blender::Timer+ object uses +ScheduledJob+ and to execute the job
|
25
|
+
# and Rufus::Scheduler to schedule it
|
26
|
+
class ScheduledJob
|
27
|
+
attr_reader :schedule, :file
|
28
|
+
# create a new instance
|
29
|
+
# @param name [String] name of the job
|
30
|
+
def initialize(name)
|
31
|
+
@name = name
|
32
|
+
@file = name
|
33
|
+
end
|
34
|
+
|
35
|
+
# set the path of the file holding blender job
|
36
|
+
#
|
37
|
+
# @param file [String] path of the blender file
|
38
|
+
def blender_file(file)
|
39
|
+
@file = file
|
40
|
+
end
|
41
|
+
|
42
|
+
# set the job inteval via cron syntax. The value is passed as it is
|
43
|
+
# to rufus scheduler.
|
44
|
+
#
|
45
|
+
# @param line [String] job interval in cron syntax e.g (*/5 * * * *)
|
46
|
+
def cron(line)
|
47
|
+
@schedule = [ __method__, line]
|
48
|
+
end
|
49
|
+
|
50
|
+
# set the job inteval after every specified seconds
|
51
|
+
# to rufus scheduler.
|
52
|
+
#
|
53
|
+
# @param interval [Fixnum] job interval in seconds
|
54
|
+
def every(interval)
|
55
|
+
@schedule = [ __method__, interval]
|
56
|
+
end
|
57
|
+
|
58
|
+
# invoke a blender run based on the +blender_file+
|
59
|
+
def run
|
60
|
+
des = File.read(file)
|
61
|
+
Blender.blend(file) do |sch|
|
62
|
+
sch.instance_eval(des, __FILE__, __LINE__)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,114 @@
|
|
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/log'
|
19
|
+
require 'blender/configuration'
|
20
|
+
require 'blender/utils/thread_pool'
|
21
|
+
require 'blender/exceptions'
|
22
|
+
require 'blender/scheduling_strategies/default'
|
23
|
+
require 'blender/scheduling_strategies/per_host'
|
24
|
+
require 'blender/scheduling_strategies/per_task'
|
25
|
+
require 'blender/utils/thread_pool'
|
26
|
+
require 'blender/scheduler/dsl'
|
27
|
+
require 'blender/event_dispatcher'
|
28
|
+
require 'blender/handlers/doc'
|
29
|
+
require 'blender/tasks/base'
|
30
|
+
|
31
|
+
module Blender
|
32
|
+
class Scheduler
|
33
|
+
|
34
|
+
include SchedulerDSL
|
35
|
+
include Lock
|
36
|
+
|
37
|
+
attr_reader :metadata, :name
|
38
|
+
attr_reader :scheduling_strategy
|
39
|
+
attr_reader :events, :tasks
|
40
|
+
attr_reader :lock_properties
|
41
|
+
|
42
|
+
def initialize(name, tasks = [], metadata = {})
|
43
|
+
@name = name
|
44
|
+
@tasks = tasks
|
45
|
+
@metadata = default_metadata.merge(metadata)
|
46
|
+
@events = Blender::EventDispatcher.new
|
47
|
+
events.register(Blender::Handlers::Doc.new)
|
48
|
+
@scheduling_strategy = nil
|
49
|
+
@lock_properties = {driver: 'flock', driver_options: {}}
|
50
|
+
end
|
51
|
+
|
52
|
+
def run
|
53
|
+
@scheduling_strategy ||= SchedulingStrategy::Default.new
|
54
|
+
events.run_started(self)
|
55
|
+
events.job_computation_started(scheduling_strategy)
|
56
|
+
jobs = scheduling_strategy.compute_jobs(@tasks)
|
57
|
+
events.job_computation_finished(self, jobs)
|
58
|
+
lock do
|
59
|
+
if metadata[:concurrency] > 1
|
60
|
+
concurrent_run(jobs)
|
61
|
+
else
|
62
|
+
serial_run(jobs)
|
63
|
+
end
|
64
|
+
events.run_finished(self)
|
65
|
+
jobs
|
66
|
+
end
|
67
|
+
rescue StandardError => e
|
68
|
+
events.run_failed(self, e)
|
69
|
+
raise e
|
70
|
+
end
|
71
|
+
|
72
|
+
def serial_run(jobs)
|
73
|
+
Log.debug('Invoking serial run')
|
74
|
+
jobs.each do |job|
|
75
|
+
run_job(job)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def concurrent_run(jobs)
|
80
|
+
c = metadata[:concurrency]
|
81
|
+
Log.debug("Invoking concurrent run with concurrency:#{c}")
|
82
|
+
pool = Utils::ThreadPool.new(c)
|
83
|
+
jobs.each do |job|
|
84
|
+
pool.add_job do
|
85
|
+
run_job(job)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
pool.run_till_done
|
89
|
+
end
|
90
|
+
|
91
|
+
def run_job(job)
|
92
|
+
events.job_started(job)
|
93
|
+
Log.debug("Running job #{job.name}")
|
94
|
+
job.run
|
95
|
+
events.job_finished(job)
|
96
|
+
rescue StandardError => e
|
97
|
+
events.job_failed(job, e)
|
98
|
+
if metadata[:ignore_failure]
|
99
|
+
Log.warn("Exception: #{e.inspect} was suppressed, ignoring failure")
|
100
|
+
else
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def default_metadata
|
106
|
+
{
|
107
|
+
ignore_failure: false,
|
108
|
+
concurrency: 0,
|
109
|
+
handlers: [],
|
110
|
+
members: []
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,160 @@
|
|
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/scheduling_strategies/default'
|
20
|
+
require 'blender/tasks/base'
|
21
|
+
require 'blender/tasks/ruby'
|
22
|
+
require 'blender/tasks/ssh'
|
23
|
+
require 'blender/tasks/shell_out'
|
24
|
+
require 'highline'
|
25
|
+
require 'blender/utils/refinements'
|
26
|
+
require 'blender/drivers/ssh'
|
27
|
+
require 'blender/drivers/ssh_multi'
|
28
|
+
require 'blender/drivers/shellout'
|
29
|
+
require 'blender/drivers/ruby'
|
30
|
+
require 'blender/discovery'
|
31
|
+
require 'blender/handlers/base'
|
32
|
+
require 'blender/lock/flock'
|
33
|
+
|
34
|
+
module Blender
|
35
|
+
module SchedulerDSL
|
36
|
+
include Blender::Utils::Refinements
|
37
|
+
include Blender::Discovery
|
38
|
+
|
39
|
+
def config(type, opts = {})
|
40
|
+
Blender::Configuration[type].merge!(opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
alias :init :config
|
44
|
+
|
45
|
+
def log_level(level)
|
46
|
+
Blender::Log.level = level
|
47
|
+
end
|
48
|
+
|
49
|
+
def ask(msg, echo = false)
|
50
|
+
HighLine.new.ask(msg){|q| q.echo = echo}
|
51
|
+
end
|
52
|
+
|
53
|
+
def driver(type, opts = {})
|
54
|
+
klass_name = camelcase(type.to_s).to_sym
|
55
|
+
config = symbolize(opts.merge(events: events))
|
56
|
+
yield config if block_given?
|
57
|
+
begin
|
58
|
+
Blender::Driver.const_get(klass_name).new(config)
|
59
|
+
rescue NameError => e
|
60
|
+
raise UnknownDriver, e.message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_handler(handler)
|
65
|
+
events.register(handler)
|
66
|
+
end
|
67
|
+
|
68
|
+
alias :register_handler :add_handler
|
69
|
+
|
70
|
+
def on(event_type, &block)
|
71
|
+
add_handler(
|
72
|
+
Class.new(Handlers::Base) do
|
73
|
+
define_method(event_type) do |*args|
|
74
|
+
block.call(args)
|
75
|
+
end
|
76
|
+
end.new
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_task(name, type)
|
81
|
+
task_klass = Blender::Task.const_get(camelcase(type.to_s).to_sym)
|
82
|
+
driver_klass = Blender::Driver.const_get(camelcase(type.to_s).to_sym)
|
83
|
+
task = task_klass.new(name)
|
84
|
+
task.members(metadata[:members]) unless metadata[:members].empty?
|
85
|
+
task
|
86
|
+
end
|
87
|
+
|
88
|
+
def append_task(type, task)
|
89
|
+
Log.debug("Appended task:#{task.name}")
|
90
|
+
klass = Blender::Driver.const_get(camelcase(type.to_s).to_sym)
|
91
|
+
if task.driver.nil?
|
92
|
+
opts = {}
|
93
|
+
opts.merge!(Blender::Configuration[type]) unless Blender::Configuration[type].empty?
|
94
|
+
opts.merge!(task.driver_opts)
|
95
|
+
task.use_driver(driver(type, opts))
|
96
|
+
end
|
97
|
+
@tasks << task
|
98
|
+
end
|
99
|
+
|
100
|
+
def shell_task(name, &block)
|
101
|
+
task = build_task(name, :shell_out)
|
102
|
+
task.members(['localhost'])
|
103
|
+
task.instance_eval(&block) if block_given?
|
104
|
+
append_task(:shell_out, task)
|
105
|
+
end
|
106
|
+
|
107
|
+
def ruby_task(name, &block)
|
108
|
+
task = build_task(name, :ruby)
|
109
|
+
task.instance_eval(&block) if block_given?
|
110
|
+
append_task(:ruby, task)
|
111
|
+
end
|
112
|
+
|
113
|
+
def ssh_task(name, &block)
|
114
|
+
task = build_task(name, :ssh)
|
115
|
+
task.instance_eval(&block) if block_given?
|
116
|
+
append_task(:ssh, task)
|
117
|
+
end
|
118
|
+
|
119
|
+
def strategy(strategy)
|
120
|
+
klass_name = camelcase(strategy.to_s).to_sym
|
121
|
+
begin
|
122
|
+
@scheduling_strategy = Blender::SchedulingStrategy.const_get(klass_name).new
|
123
|
+
@scheduling_strategy.freeze
|
124
|
+
rescue NameError => e
|
125
|
+
raise UnknownSchedulingStrategy, e.message
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def concurrency(value)
|
130
|
+
@metadata[:concurrency] = value
|
131
|
+
end
|
132
|
+
|
133
|
+
def ignore_failure(value)
|
134
|
+
@metadata[:ignore_failure] = value
|
135
|
+
end
|
136
|
+
|
137
|
+
def members(hosts)
|
138
|
+
@metadata[:members] = hosts
|
139
|
+
end
|
140
|
+
|
141
|
+
def lock_options(driver, opts = {})
|
142
|
+
@lock_properties[:driver] = driver
|
143
|
+
@lock_properties[:driver_options].merge!(opts.dup)
|
144
|
+
end
|
145
|
+
|
146
|
+
def lock(opts = {})
|
147
|
+
options = lock_properties.dup.merge(opts)
|
148
|
+
if options[:driver]
|
149
|
+
lock_klass = Lock.const_get(camelcase(options[:driver]).to_sym)
|
150
|
+
lock_klass.new(name, options[:driver_options]).with_lock do
|
151
|
+
yield if block_given?
|
152
|
+
end
|
153
|
+
else
|
154
|
+
yield if block_given?
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
alias_method :task, :shell_task
|
159
|
+
end
|
160
|
+
end
|