pd-blender 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rubocop.yml +2 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +342 -0
  8. data/Rakefile +21 -0
  9. data/bin/blend +20 -0
  10. data/blender.gemspec +36 -0
  11. data/lib/blender.rb +67 -0
  12. data/lib/blender/cli.rb +71 -0
  13. data/lib/blender/configuration.rb +45 -0
  14. data/lib/blender/discovery.rb +41 -0
  15. data/lib/blender/drivers/base.rb +40 -0
  16. data/lib/blender/drivers/compound.rb +29 -0
  17. data/lib/blender/drivers/ruby.rb +55 -0
  18. data/lib/blender/drivers/shellout.rb +63 -0
  19. data/lib/blender/drivers/ssh.rb +93 -0
  20. data/lib/blender/drivers/ssh_multi.rb +102 -0
  21. data/lib/blender/event_dispatcher.rb +45 -0
  22. data/lib/blender/exceptions.rb +26 -0
  23. data/lib/blender/handlers/base.rb +39 -0
  24. data/lib/blender/handlers/doc.rb +73 -0
  25. data/lib/blender/job.rb +73 -0
  26. data/lib/blender/lock/flock.rb +64 -0
  27. data/lib/blender/log.rb +24 -0
  28. data/lib/blender/rspec.rb +68 -0
  29. data/lib/blender/rspec/stub_registry.rb +45 -0
  30. data/lib/blender/scheduled_job.rb +66 -0
  31. data/lib/blender/scheduler.rb +114 -0
  32. data/lib/blender/scheduler/dsl.rb +160 -0
  33. data/lib/blender/scheduling_strategies/base.rb +30 -0
  34. data/lib/blender/scheduling_strategies/default.rb +37 -0
  35. data/lib/blender/scheduling_strategies/per_host.rb +38 -0
  36. data/lib/blender/scheduling_strategies/per_task.rb +37 -0
  37. data/lib/blender/tasks/base.rb +72 -0
  38. data/lib/blender/tasks/ruby.rb +31 -0
  39. data/lib/blender/tasks/shell_out.rb +30 -0
  40. data/lib/blender/tasks/ssh.rb +25 -0
  41. data/lib/blender/timer.rb +54 -0
  42. data/lib/blender/utils/refinements.rb +45 -0
  43. data/lib/blender/utils/thread_pool.rb +54 -0
  44. data/lib/blender/utils/ui.rb +51 -0
  45. data/lib/blender/version.rb +20 -0
  46. data/spec/blender/blender_rspec.rb +31 -0
  47. data/spec/blender/discovery_spec.rb +16 -0
  48. data/spec/blender/drivers/ssh_multi_spec.rb +16 -0
  49. data/spec/blender/drivers/ssh_spec.rb +17 -0
  50. data/spec/blender/dsl_spec.rb +19 -0
  51. data/spec/blender/event_dispatcher_spec.rb +17 -0
  52. data/spec/blender/job_spec.rb +42 -0
  53. data/spec/blender/lock_spec.rb +129 -0
  54. data/spec/blender/scheduled_job_spec.rb +30 -0
  55. data/spec/blender/scheduler_spec.rb +140 -0
  56. data/spec/blender/scheduling_strategies/default_spec.rb +75 -0
  57. data/spec/blender/utils/refinements_spec.rb +16 -0
  58. data/spec/blender/utils/thread_pool_spec.rb +16 -0
  59. data/spec/blender_spec.rb +37 -0
  60. data/spec/data/example.rb +12 -0
  61. data/spec/spec_helper.rb +35 -0
  62. metadata +304 -0
@@ -0,0 +1,30 @@
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
+
19
+ require 'blender/log'
20
+ require 'blender/job'
21
+
22
+ module Blender
23
+ module SchedulingStrategy
24
+ class Base
25
+ def compute_jobs(tasks)
26
+ raise RuntimeError, 'Must be overridden'
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,37 @@
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/scheduling_strategies/base'
19
+
20
+ module Blender
21
+ module SchedulingStrategy
22
+ class Default < Base
23
+ def compute_jobs(tasks)
24
+ Log.debug("Computing jobs from #{tasks.size} tasks")
25
+ pairs = tasks.map{|t| [t].product(t.hosts)}.flatten(1)
26
+ job_id = 0
27
+ jobs = pairs.map do |task, host|
28
+ Log.debug("Creating job (#{host}|#{task.name})")
29
+ job_id += 1
30
+ Job.new(job_id, task.driver, [task], [host])
31
+ end
32
+ Log.debug("Total jobs : #{jobs.size}")
33
+ jobs
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
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/drivers/compound'
19
+
20
+ module Blender
21
+ module SchedulingStrategy
22
+ class PerHost < Base
23
+ def compute_jobs(tasks)
24
+ Log.debug("Computing jobs from #{tasks.size} tasks")
25
+ hosts_list = tasks.map(&:hosts).uniq
26
+ if hosts_list.size != 1
27
+ raise UnsupportedFeature, 'PerHost strategy does not support scheduling tasks with different memebers'
28
+ end
29
+ job_id = 1
30
+ jobs = hosts_list.first.map do |host|
31
+ Job.new(job_id, Blender::Driver::Compound.new, tasks, [host])
32
+ end
33
+ Log.debug("Total jobs : #{jobs.size}")
34
+ jobs
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
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/scheduling_strategies/base'
19
+
20
+ module Blender
21
+ module SchedulingStrategy
22
+ class PerTask < Base
23
+ def compute_jobs(tasks)
24
+ Log.debug("Computing jobs from #{tasks.size} tasks")
25
+ job_id = 0
26
+ jobs = tasks.map do |task|
27
+ hosts = task.hosts
28
+ Log.debug("Creating job (#{hosts.size}|#{task.name})")
29
+ job_id += 1
30
+ Job.new(job_id, task.driver, [task] , hosts)
31
+ end
32
+ Log.debug("Total jobs : #{jobs.size}")
33
+ jobs
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,72 @@
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/discovery'
18
+
19
+ module Blender
20
+ module Task
21
+ class Base
22
+ include Blender::Discovery
23
+
24
+ attr_reader :guards
25
+ attr_reader :metadata
26
+ attr_reader :name
27
+ attr_reader :hosts
28
+ attr_reader :driver
29
+ attr_reader :command
30
+ attr_reader :driver_opts
31
+
32
+ def initialize(name, metadata = {})
33
+ @name = name
34
+ @metadata = default_metadata.merge(metadata)
35
+ @hosts = []
36
+ @command = name
37
+ @driver = nil
38
+ @driver_opts = {}
39
+ end
40
+
41
+ def use_driver(driver)
42
+ @driver = driver
43
+ end
44
+
45
+ def ignore_failure(value)
46
+ @metadata[:ignore_failure] = value
47
+ end
48
+
49
+ def driver_options(opts)
50
+ @driver_opts = opts
51
+ end
52
+
53
+ def execute(cmd)
54
+ @command = cmd
55
+ end
56
+
57
+ def members(hosts)
58
+ @hosts = hosts
59
+ end
60
+
61
+ def add_metadata(opts = {})
62
+ opts.keys.each do |k|
63
+ @metadata[k] = opts[k]
64
+ end
65
+ end
66
+
67
+ def default_metadata
68
+ { ignore_failure: false }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,31 @@
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/tasks/base'
19
+
20
+ module Blender
21
+ module Task
22
+ class Ruby < Blender::Task::Base
23
+
24
+ attr_reader :code_block
25
+
26
+ def execute(&block)
27
+ @command = block
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
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/tasks/base'
19
+
20
+ module Blender
21
+ module Task
22
+ class ShellOut < Base
23
+ def initialize(name, metadata ={})
24
+ super
25
+ @command = name
26
+ @members = ['localhost']
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
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/tasks/ssh'
19
+
20
+ module Blender
21
+ module Task
22
+ class Ssh < Blender::Task::Base
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
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 'rufus-scheduler'
19
+ require 'blender/scheduled_job'
20
+
21
+ module Blender
22
+ # Timer class provides a simple dsl for running blender jobs periodically.
23
+ # It uses Rufus::Scheduler for scheduling jobs
24
+ class Timer
25
+ def initialize
26
+ @scheduled_jobs = []
27
+ end
28
+
29
+ def schedule(name, &block)
30
+ job = Blender::ScheduledJob.new(name)
31
+ job.instance_eval(&block)
32
+ @scheduled_jobs << job
33
+ end
34
+
35
+ def join
36
+ scheduler = Rufus::Scheduler.new
37
+ @scheduled_jobs.each do |job|
38
+ case job.schedule.first
39
+ when :every
40
+ scheduler.every(job.schedule[1]) do
41
+ job.run
42
+ end
43
+ when :cron
44
+ scheduler.cron(job.schedule[1]) do
45
+ job.run
46
+ end
47
+ else
48
+ raise UnsupportedFeature, "Unsupported scheduling: '#{job.schedule.first}'"
49
+ end
50
+ end
51
+ scheduler.join
52
+ end
53
+ end
54
+ 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
+ module Blender
18
+ module Utils
19
+ module Refinements
20
+ def camelcase(string)
21
+ str = string.dup
22
+ str.gsub!(/[^A-Za-z0-9_]/,'_')
23
+ rname = nil
24
+ regexp = %r{^(.+?)(_(.+))?$}
25
+ mn = str.match(regexp)
26
+ if mn
27
+ rname = mn[1].capitalize
28
+ while mn && mn[3]
29
+ mn = mn[3].match(regexp)
30
+ rname << mn[1].capitalize if mn
31
+ end
32
+ end
33
+ rname
34
+ end
35
+
36
+ def symbolize(hash)
37
+ res = {}
38
+ hash.keys.each do |k|
39
+ res[k.to_sym] = hash[k]
40
+ end
41
+ res
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,54 @@
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 'thread'
18
+ require 'blender/log'
19
+
20
+ module Blender
21
+ module Utils
22
+ class ThreadPool
23
+
24
+ def initialize(size)
25
+ @size = size
26
+ @queue = Queue.new
27
+ end
28
+
29
+ def add_job(&blk)
30
+ @queue << blk
31
+ end
32
+
33
+ def run_till_done
34
+ num = @size > @queue.size ? @queue.size : @size
35
+ threads = Array.new(num) do
36
+ Thread.new do
37
+ Thread.current.abort_on_exception = true
38
+ @queue.pop.call while true
39
+ end
40
+ end
41
+ until @queue.empty?
42
+ sleep 0.2
43
+ end
44
+ until @queue.num_waiting == num
45
+ sleep 0.2
46
+ end
47
+ threads.each do |thread|
48
+ thread.join(0.02)
49
+ end
50
+ threads.map(&:kill)
51
+ end
52
+ end
53
+ end
54
+ end