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.
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