runbook 0.12.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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +5 -0
  7. data/CHANGELOG.md +46 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +6 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +999 -0
  12. data/Rakefile +6 -0
  13. data/TODO.md +38 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/exe/runbook +5 -0
  17. data/images/runbook_anatomy_diagram.png +0 -0
  18. data/images/runbook_example.gif +0 -0
  19. data/images/runbook_execution_modes.png +0 -0
  20. data/lib/hacks/ssh_kit.rb +58 -0
  21. data/lib/runbook/cli.rb +90 -0
  22. data/lib/runbook/configuration.rb +110 -0
  23. data/lib/runbook/dsl.rb +21 -0
  24. data/lib/runbook/entities/book.rb +17 -0
  25. data/lib/runbook/entities/section.rb +7 -0
  26. data/lib/runbook/entities/step.rb +7 -0
  27. data/lib/runbook/entity.rb +127 -0
  28. data/lib/runbook/errors.rb +7 -0
  29. data/lib/runbook/extensions/add.rb +13 -0
  30. data/lib/runbook/extensions/description.rb +14 -0
  31. data/lib/runbook/extensions/sections.rb +15 -0
  32. data/lib/runbook/extensions/shared_variables.rb +51 -0
  33. data/lib/runbook/extensions/ssh_config.rb +76 -0
  34. data/lib/runbook/extensions/statements.rb +26 -0
  35. data/lib/runbook/extensions/steps.rb +14 -0
  36. data/lib/runbook/extensions/tmux.rb +13 -0
  37. data/lib/runbook/helpers/format_helper.rb +11 -0
  38. data/lib/runbook/helpers/ssh_kit_helper.rb +143 -0
  39. data/lib/runbook/helpers/tmux_helper.rb +174 -0
  40. data/lib/runbook/hooks.rb +88 -0
  41. data/lib/runbook/node.rb +23 -0
  42. data/lib/runbook/run.rb +283 -0
  43. data/lib/runbook/runner.rb +64 -0
  44. data/lib/runbook/runs/ssh_kit.rb +186 -0
  45. data/lib/runbook/statement.rb +22 -0
  46. data/lib/runbook/statements/ask.rb +11 -0
  47. data/lib/runbook/statements/assert.rb +25 -0
  48. data/lib/runbook/statements/capture.rb +14 -0
  49. data/lib/runbook/statements/capture_all.rb +14 -0
  50. data/lib/runbook/statements/command.rb +11 -0
  51. data/lib/runbook/statements/confirm.rb +10 -0
  52. data/lib/runbook/statements/description.rb +9 -0
  53. data/lib/runbook/statements/download.rb +12 -0
  54. data/lib/runbook/statements/layout.rb +10 -0
  55. data/lib/runbook/statements/note.rb +10 -0
  56. data/lib/runbook/statements/notice.rb +10 -0
  57. data/lib/runbook/statements/ruby_command.rb +9 -0
  58. data/lib/runbook/statements/tmux_command.rb +11 -0
  59. data/lib/runbook/statements/upload.rb +12 -0
  60. data/lib/runbook/statements/wait.rb +10 -0
  61. data/lib/runbook/toolbox.rb +43 -0
  62. data/lib/runbook/util/repo.rb +56 -0
  63. data/lib/runbook/util/runbook.rb +25 -0
  64. data/lib/runbook/util/sticky_hash.rb +26 -0
  65. data/lib/runbook/util/stored_pose.rb +54 -0
  66. data/lib/runbook/version.rb +3 -0
  67. data/lib/runbook/view.rb +24 -0
  68. data/lib/runbook/viewer.rb +24 -0
  69. data/lib/runbook/views/markdown.rb +109 -0
  70. data/lib/runbook.rb +110 -0
  71. data/runbook.gemspec +48 -0
  72. data/samples/hooks_runbook.rb +72 -0
  73. data/samples/layout_runbook.rb +26 -0
  74. data/samples/restart_nginx.rb +26 -0
  75. data/samples/simple_runbook.rb +41 -0
  76. metadata +324 -0
@@ -0,0 +1,10 @@
1
+ module Runbook::Statements
2
+ class Notice < Runbook::Statement
3
+ attr_reader :msg
4
+
5
+ def initialize(msg)
6
+ @msg = msg
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,9 @@
1
+ module Runbook::Statements
2
+ class RubyCommand < Runbook::Statement
3
+ attr_reader :block
4
+
5
+ def initialize(&block)
6
+ @block = block
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Runbook::Statements
2
+ class TmuxCommand < Runbook::Statement
3
+ attr_reader :cmd, :pane
4
+
5
+ def initialize(cmd, pane)
6
+ @cmd = cmd
7
+ @pane = pane
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,12 @@
1
+ module Runbook::Statements
2
+ class Upload < Runbook::Statement
3
+ attr_reader :from, :to, :options, :ssh_config
4
+
5
+ def initialize(from, to:, ssh_config: nil, options: {})
6
+ @from = from
7
+ @to = to
8
+ @ssh_config = ssh_config
9
+ @options = options
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Runbook::Statements
2
+ class Wait < Runbook::Statement
3
+ attr_reader :time
4
+
5
+ def initialize(time)
6
+ @time = time
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,43 @@
1
+ module Runbook
2
+ class Toolbox
3
+ attr_reader :prompt
4
+
5
+ def initialize
6
+ @prompt = TTY::Prompt.new
7
+ end
8
+
9
+ def ask(msg, default: nil)
10
+ prompt.ask(msg, default: default)
11
+ end
12
+
13
+ def expand(msg, choices)
14
+ prompt.expand(msg, choices)
15
+ end
16
+
17
+ def yes?(msg)
18
+ begin
19
+ prompt.yes?(msg)
20
+ rescue TTY::Prompt::ConversionError
21
+ err_msg = "Unknown input: Please type 'y' or 'n'."
22
+ warn(err_msg)
23
+ retry
24
+ end
25
+ end
26
+
27
+ def output(msg)
28
+ prompt.say(msg)
29
+ end
30
+
31
+ def warn(msg)
32
+ prompt.warn(msg)
33
+ end
34
+
35
+ def error(msg)
36
+ prompt.error(msg)
37
+ end
38
+
39
+ def exit(return_value)
40
+ super(return_value)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,56 @@
1
+ module Runbook::Util
2
+ module Repo
3
+ FILE_ID = "data"
4
+
5
+ def self.load(metadata)
6
+ title = metadata[:book_title]
7
+ file = _file(title)
8
+ if File.exists?(file)
9
+ msg = "Repo file #{file} detected. Loading previous state..."
10
+ metadata[:toolbox].output(msg)
11
+ metadata[:repo] = ::YAML::load_file(file)
12
+ end
13
+ end
14
+
15
+ def self.save(repo, book_title:)
16
+ File.open(_file(book_title), 'w') do |f|
17
+ f.write(repo.to_yaml)
18
+ end
19
+ end
20
+
21
+ def self.delete(title)
22
+ FileUtils.rm_f(_file(title))
23
+ end
24
+
25
+ def self._file(book_title)
26
+ "#{Dir.tmpdir}/runbook_#{FILE_ID}_#{ENV["USER"]}_#{_slug(book_title)}.yml"
27
+ end
28
+
29
+ def self._slug(title)
30
+ title.titleize.gsub(/\s+/, "").underscore.dasherize
31
+ end
32
+
33
+ def self.register_save_repo_hook(base)
34
+ base.register_hook(
35
+ :save_repo_hook,
36
+ :after,
37
+ Object,
38
+ ) do |object, metadata|
39
+ repo = metadata[:repo]
40
+ title = metadata[:book_title]
41
+ Runbook::Util::Repo.save(repo, book_title: title)
42
+ end
43
+ end
44
+
45
+ def self.register_delete_stored_repo_hook(base)
46
+ base.register_hook(
47
+ :delete_stored_repo_hook,
48
+ :after,
49
+ Runbook::Entities::Book,
50
+ ) do |object, metadata|
51
+ title = metadata[:book_title]
52
+ Runbook::Util::Repo.delete(title)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
1
+ module Runbook
2
+ def self.entities
3
+ _child_classes(Runbook::Entities)
4
+ end
5
+
6
+ def self.statements
7
+ _child_classes(Runbook::Statements)
8
+ end
9
+
10
+ def self.runs
11
+ _child_modules(Runbook::Runs)
12
+ end
13
+
14
+ def self._child_classes(mod)
15
+ mod.constants.map { |const|
16
+ "#{mod.to_s}::#{const}".constantize
17
+ }.select { |const| const.is_a?(Class) }
18
+ end
19
+
20
+ def self._child_modules(mod)
21
+ mod.constants.map { |const|
22
+ "#{mod.to_s}::#{const}".constantize
23
+ }.select { |const| const.is_a?(Module) }
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module Runbook::Util
2
+ class StickyHash < Hash
3
+ def [](key)
4
+ value = super
5
+ value.is_a?(Glue) ? value.val : value
6
+ end
7
+
8
+ def []=(key, value)
9
+ assoc = self.assoc(key)
10
+ if assoc.nil? || ! assoc[1].is_a?(Glue)
11
+ super
12
+ else
13
+ assoc[1].val = value
14
+ end
15
+ end
16
+ end
17
+
18
+ class Glue
19
+ attr_accessor :val
20
+
21
+ def initialize(val)
22
+ @val = val
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,54 @@
1
+ module Runbook::Util
2
+ module StoredPose
3
+ FILE_ID = "current_position"
4
+
5
+ def self.load(metadata)
6
+ title = metadata[:book_title]
7
+ file = _file(title)
8
+ if File.exists?(file)
9
+ ::YAML::load_file(file)
10
+ end
11
+ end
12
+
13
+ def self.save(repo, book_title:)
14
+ File.open(_file(book_title), 'w') do |f|
15
+ f.write(repo.to_yaml)
16
+ end
17
+ end
18
+
19
+ def self.delete(title)
20
+ FileUtils.rm_f(_file(title))
21
+ end
22
+
23
+ def self._file(book_title)
24
+ "#{Dir.tmpdir}/runbook_#{FILE_ID}_#{ENV["USER"]}_#{_slug(book_title)}.yml"
25
+ end
26
+
27
+ def self._slug(title)
28
+ title.titleize.gsub(/\s+/, "").underscore.dasherize
29
+ end
30
+
31
+ def self.register_save_pose_hook(base)
32
+ base.register_hook(
33
+ :save_pose_hook,
34
+ :before,
35
+ Object,
36
+ ) do |object, metadata|
37
+ position = metadata[:position]
38
+ title = metadata[:book_title]
39
+ Runbook::Util::StoredPose.save(position, book_title: title)
40
+ end
41
+ end
42
+
43
+ def self.register_delete_stored_pose_hook(base)
44
+ base.register_hook(
45
+ :delete_stored_pose_hook,
46
+ :after,
47
+ Runbook::Entities::Book,
48
+ ) do |object, metadata|
49
+ title = metadata[:book_title]
50
+ Runbook::Util::StoredPose.delete(title)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module Runbook
2
+ VERSION = "0.12.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ module Runbook
2
+ module View
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ include Runbook::Hooks
9
+
10
+ def render(object, output, metadata)
11
+ method = _method_name(object)
12
+ if respond_to?(method)
13
+ send(method, object, output, metadata)
14
+ else
15
+ $stderr.puts("WARNING! No render rule for #{object.class} (#{_method_name(object)}) in #{self.to_s}")
16
+ end
17
+ end
18
+
19
+ def _method_name(object)
20
+ object.class.to_s.underscore.gsub("/", "__")
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Runbook
2
+ class Viewer
3
+ attr_reader :book
4
+
5
+ def initialize(book)
6
+ @book = book
7
+ end
8
+
9
+ def generate(view: :markdown)
10
+ view = "Runbook::Views::#{view.to_s.camelize}".constantize
11
+ metadata = Util::StickyHash.new.
12
+ merge(Runbook::Entities::Book.initial_render_metadata).
13
+ merge(additional_metadata)
14
+
15
+ StringIO.new.tap do |output|
16
+ book.render(view, output, metadata)
17
+ end.string
18
+ end
19
+
20
+ def additional_metadata
21
+ {}
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,109 @@
1
+ module Runbook::Views
2
+ module Markdown
3
+ include Runbook::View
4
+ extend Runbook::Helpers::FormatHelper
5
+ extend Runbook::Helpers::SSHKitHelper
6
+
7
+ def self.runbook__entities__book(object, output, metadata)
8
+ output << "# #{object.title}\n\n"
9
+ end
10
+
11
+ def self.runbook__entities__section(object, output, metadata)
12
+ heading = "#"*metadata[:depth]
13
+ output << "#{heading} #{metadata[:index]+1}. #{object.title}\n\n"
14
+ end
15
+
16
+ def self.runbook__entities__step(object, output, metadata)
17
+ output << "#{metadata[:index]+1}. [] #{object.title}\n\n"
18
+
19
+ ssh_config = find_ssh_config(object)
20
+ ssh_config_output = render_ssh_config_output(ssh_config)
21
+ output << "#{ssh_config_output}\n" unless ssh_config_output.empty?
22
+ end
23
+
24
+ def self.runbook__statements__ask(object, output, metadata)
25
+ default_msg = object.default ? " (default: #{object.default})" : ""
26
+ output << " #{object.prompt} into #{object.into}#{default_msg}\n\n"
27
+ end
28
+
29
+ def self.runbook__statements__assert(object, output, metadata)
30
+ output << " run: `#{object.cmd}` every #{object.interval} seconds until it returns 0\n\n"
31
+ if object.timeout > 0 || object.attempts > 0
32
+ timeout_msg = object.timeout > 0 ? "#{object.timeout} second(s)" : nil
33
+ attempts_msg = object.attempts > 0 ? "#{object.attempts} attempts" : nil
34
+ giveup_msg = "after #{[timeout_msg, attempts_msg].compact.join(" or ")}, give up..."
35
+ output << " #{giveup_msg}\n\n"
36
+ if object.timeout_statement
37
+ object.timeout_statement.render(self, output, metadata.dup)
38
+ end
39
+ output << " and exit\n\n"
40
+ end
41
+ end
42
+
43
+ def self.runbook__statements__capture(object, output, metadata)
44
+ output << " capture: `#{object.cmd}` into #{object.into}\n\n"
45
+ end
46
+
47
+ def self.runbook__statements__capture_all(object, output, metadata)
48
+ output << " capture_all: `#{object.cmd}` into #{object.into}\n\n"
49
+ end
50
+
51
+ def self.runbook__statements__command(object, output, metadata)
52
+ output << " run: `#{object.cmd}`\n\n"
53
+ end
54
+
55
+ def self.runbook__statements__confirm(object, output, metadata)
56
+ output << " confirm: #{object.prompt}\n\n"
57
+ end
58
+
59
+ def self.runbook__statements__description(object, output, metadata)
60
+ output << "#{object.msg}\n"
61
+ end
62
+
63
+ def self.runbook__statements__download(object, output, metadata)
64
+ options = object.options
65
+ to = " to #{object.to}" if object.to
66
+ opts = " with options #{options}" unless options == {}
67
+ output << " download: #{object.from}#{to}#{opts}\n\n"
68
+ end
69
+
70
+ def self.runbook__statements__layout(object, output, metadata)
71
+ output << "layout:\n"
72
+ output << "#{object.structure.inspect}\n\n"
73
+ end
74
+
75
+ def self.runbook__statements__note(object, output, metadata)
76
+ output << " #{object.msg}\n\n"
77
+ end
78
+
79
+ def self.runbook__statements__notice(object, output, metadata)
80
+ output << " **#{object.msg}**\n\n"
81
+ end
82
+
83
+ def self.runbook__statements__ruby_command(object, output, metadata)
84
+ output << " run:\n"
85
+ output << " ```ruby\n"
86
+ begin
87
+ output << "#{deindent(object.block.source, padding: 3)}\n"
88
+ rescue ::MethodSource::SourceNotFoundError => e
89
+ output << " Unable to retrieve source code\n"
90
+ end
91
+ output << " ```\n\n"
92
+ end
93
+
94
+ def self.runbook__statements__tmux_command(object, output, metadata)
95
+ output << " run: `#{object.cmd}` in pane #{object.pane}\n\n"
96
+ end
97
+
98
+ def self.runbook__statements__upload(object, output, metadata)
99
+ options = object.options
100
+ to = " to #{object.to}" if object.to
101
+ opts = " with options #{options}" unless options == {}
102
+ output << " upload: #{object.from}#{to}#{opts}\n\n"
103
+ end
104
+
105
+ def self.runbook__statements__wait(object, output, metadata)
106
+ output << " wait: #{object.time} seconds\n\n"
107
+ end
108
+ end
109
+ end
data/lib/runbook.rb ADDED
@@ -0,0 +1,110 @@
1
+ require "tmpdir"
2
+ require "yaml"
3
+ require "thread"
4
+
5
+ require "active_support/inflector"
6
+ require "method_source"
7
+ require "pastel"
8
+ require "sshkit"
9
+ require "sshkit/sudo"
10
+ require "airbrussh"
11
+ require "tty-progressbar"
12
+ require "tty-prompt"
13
+
14
+ require "runbook/configuration"
15
+
16
+ require "hacks/ssh_kit"
17
+
18
+ require "runbook/dsl"
19
+ require "runbook/errors"
20
+ require "runbook/hooks"
21
+
22
+ require "runbook/util/repo"
23
+ require "runbook/util/runbook"
24
+ require "runbook/util/sticky_hash"
25
+ require "runbook/util/stored_pose"
26
+
27
+ require "runbook/node"
28
+
29
+ require "runbook/entity"
30
+ require "runbook/entities/book"
31
+ require "runbook/entities/section"
32
+ require "runbook/entities/step"
33
+
34
+ require "runbook/statement"
35
+ require "runbook/statements/ask"
36
+ require "runbook/statements/assert"
37
+ require "runbook/statements/capture"
38
+ require "runbook/statements/capture_all"
39
+ require "runbook/statements/command"
40
+ require "runbook/statements/confirm"
41
+ require "runbook/statements/description"
42
+ require "runbook/statements/download"
43
+ require "runbook/statements/layout"
44
+ require "runbook/statements/note"
45
+ require "runbook/statements/notice"
46
+ require "runbook/statements/ruby_command"
47
+ require "runbook/statements/tmux_command"
48
+ require "runbook/statements/upload"
49
+ require "runbook/statements/wait"
50
+
51
+ require "runbook/helpers/format_helper"
52
+ require "runbook/helpers/ssh_kit_helper"
53
+ require "runbook/helpers/tmux_helper"
54
+
55
+ require "runbook/runner"
56
+ require "runbook/run"
57
+ require "runbook/runs/ssh_kit"
58
+
59
+ require "runbook/toolbox"
60
+
61
+ require "runbook/viewer"
62
+ require "runbook/view"
63
+ require "runbook/views/markdown"
64
+
65
+ require "runbook/extensions/add"
66
+ require "runbook/extensions/description"
67
+ require "runbook/extensions/shared_variables"
68
+ require "runbook/extensions/sections"
69
+ require "runbook/extensions/ssh_config"
70
+ require "runbook/extensions/statements"
71
+ require "runbook/extensions/steps"
72
+ require "runbook/extensions/tmux"
73
+
74
+ require "runbook/version"
75
+
76
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
77
+ inflect.acronym 'SSH'
78
+ end
79
+
80
+ module Runbook
81
+ def self.book(title, &block)
82
+ Configuration.load_config
83
+ Entities::Book.new(title).tap do |book|
84
+ book.dsl.instance_eval(&block)
85
+ register(book)
86
+ end
87
+ end
88
+
89
+ def self.section(title, &block)
90
+ Configuration.load_config
91
+ Entities::Section.new(title).tap do |section|
92
+ section.dsl.instance_eval(&block)
93
+ end
94
+ end
95
+
96
+ def self.step(title=nil, &block)
97
+ Configuration.load_config
98
+ Entities::Step.new(title).tap do |step|
99
+ step.dsl.instance_eval(&block) if block
100
+ end
101
+ end
102
+
103
+ def self.register(book)
104
+ books << book
105
+ end
106
+
107
+ def self.books
108
+ @books ||= []
109
+ end
110
+ end
data/runbook.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "runbook/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "runbook"
8
+ spec.version = Runbook::VERSION
9
+ spec.authors = ["pblesi"]
10
+ spec.email = ["code@getbraintree.com"]
11
+
12
+ spec.summary = %q{Write beautiful, executable runbooks for conducting production operations.}
13
+ spec.description = %q{Runbook provides a DSL for specifying production operations. This DSL is used to generate formatted runbooks as well as interactive runbooks to be executed on the command line.}
14
+ spec.homepage = "https://github.com/braintree/runbook/"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_runtime_dependency 'activesupport', '~> 5.0', '>= 5.0.0.1'
34
+ spec.add_runtime_dependency "method_source", "~> 0.9.0"
35
+ spec.add_runtime_dependency "sshkit", "1.16"
36
+ spec.add_runtime_dependency "sshkit-sudo", "~> 0.1.0"
37
+ spec.add_runtime_dependency "airbrussh", "~> 1.3"
38
+ spec.add_runtime_dependency "thor", "~> 0.20.0"
39
+ spec.add_runtime_dependency "tty-progressbar", "~> 0.14.0"
40
+ spec.add_runtime_dependency "tty-prompt", "~> 0.16.0"
41
+
42
+ spec.add_development_dependency "aruba", "~> 0.14.5"
43
+ spec.add_development_dependency "bundler", "~> 1.15"
44
+ spec.add_development_dependency "pry", "~> 0.11.3"
45
+ spec.add_development_dependency "pry-byebug", "~> 3.6"
46
+ spec.add_development_dependency "rake", "~> 10.0"
47
+ spec.add_development_dependency "rspec", "~> 3.0"
48
+ end
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ require "runbook"
3
+
4
+ Runbook::Runs::SSHKit.register_hook(
5
+ :output_before_hook,
6
+ :before,
7
+ Object
8
+ ) do |object, metadata|
9
+ location = "#{object.class}: #{metadata[:position]}"
10
+ metadata[:toolbox].output " [Before: #{location}]\n"
11
+ end
12
+
13
+ Runbook::Runs::SSHKit.register_hook(
14
+ :output_around_hook,
15
+ :around,
16
+ Object
17
+ ) do |object, metadata, block|
18
+ location = "#{object.class}: #{metadata[:position]}"
19
+ metadata[:toolbox].output " [Around_before: #{location}]\n"
20
+ block.call(object, metadata)
21
+ metadata[:toolbox].output " [Around_after: #{location}]\n"
22
+ end
23
+
24
+ Runbook::Runs::SSHKit.register_hook(
25
+ :output_after_hook,
26
+ :after,
27
+ Object
28
+ ) do |object, metadata|
29
+ location = "#{object.class}: #{metadata[:position]}"
30
+ metadata[:toolbox].output " [After: #{location}]\n"
31
+ end
32
+
33
+ runbook = Runbook.book "Example Hooks Runbook" do
34
+ description <<-DESC
35
+ This is a runbook for playing with runbook hooks
36
+ DESC
37
+
38
+ layout [[
39
+ :runbook,
40
+ :bottom,
41
+ ]]
42
+
43
+ section "Hook" do
44
+ step do
45
+ note "Looky, Looky, I got a hooky"
46
+ end
47
+
48
+ step
49
+ end
50
+
51
+ section "Fishing Hooks" do
52
+ step do
53
+ note "Hooked, line, and sinker"
54
+ end
55
+
56
+ step
57
+ end
58
+
59
+ section "Hooked on Phonics" do
60
+ step do
61
+ note "Huked on Phoonics reely werx 4 mee"
62
+ end
63
+
64
+ step
65
+ end
66
+ end
67
+
68
+ if __FILE__ == $0
69
+ Runbook::Runner.new(runbook).run
70
+ else
71
+ runbook
72
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ require "runbook"
3
+
4
+ runbook = Runbook.book "Example Layout Book" do
5
+ description <<-DESC
6
+ This is a runbook for playing with the layout statement
7
+ DESC
8
+
9
+ layout [[
10
+ [:runbook, :deploy],
11
+ [:monitor_1, :monitor_2, :monitor_3],
12
+ ]]
13
+
14
+ section "Layout Testing" do
15
+ step do
16
+ tmux_command "echo 'Layouts Rock!'", :deploy
17
+ note "Layouts are cool!"
18
+ end
19
+ end
20
+ end
21
+
22
+ if __FILE__ == $0
23
+ Runbook::Runner.new(runbook).run
24
+ else
25
+ runbook
26
+ end