micro-hookit 0.12.11

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +21 -0
  6. data/README.md +24 -0
  7. data/Rakefile +18 -0
  8. data/bin/hookit +51 -0
  9. data/boxfile.yml +2 -0
  10. data/hookit.gemspec +30 -0
  11. data/lib/hookit/converginator.rb +165 -0
  12. data/lib/hookit/db.rb +37 -0
  13. data/lib/hookit/error.rb +9 -0
  14. data/lib/hookit/exit.rb +23 -0
  15. data/lib/hookit/helper/cron.rb +42 -0
  16. data/lib/hookit/helper/nfs.rb +113 -0
  17. data/lib/hookit/helper/shell.rb +35 -0
  18. data/lib/hookit/helper/xml.rb +25 -0
  19. data/lib/hookit/helper.rb +9 -0
  20. data/lib/hookit/hook.rb +96 -0
  21. data/lib/hookit/logger.rb +60 -0
  22. data/lib/hookit/platform/base.rb +11 -0
  23. data/lib/hookit/platform/docker.rb +22 -0
  24. data/lib/hookit/platform/smartos.rb +19 -0
  25. data/lib/hookit/platform/ubuntu.rb +19 -0
  26. data/lib/hookit/platform.rb +10 -0
  27. data/lib/hookit/platforms.rb +3 -0
  28. data/lib/hookit/registry.rb +53 -0
  29. data/lib/hookit/resource/base.rb +138 -0
  30. data/lib/hookit/resource/cron.rb +29 -0
  31. data/lib/hookit/resource/directory.rb +69 -0
  32. data/lib/hookit/resource/execute.rb +205 -0
  33. data/lib/hookit/resource/file.rb +89 -0
  34. data/lib/hookit/resource/hook_file.rb +109 -0
  35. data/lib/hookit/resource/link.rb +50 -0
  36. data/lib/hookit/resource/logrotate.rb +36 -0
  37. data/lib/hookit/resource/mount.rb +85 -0
  38. data/lib/hookit/resource/package.rb +57 -0
  39. data/lib/hookit/resource/rsync.rb +58 -0
  40. data/lib/hookit/resource/scp.rb +78 -0
  41. data/lib/hookit/resource/service.rb +117 -0
  42. data/lib/hookit/resource/socket.rb +79 -0
  43. data/lib/hookit/resource/template.rb +114 -0
  44. data/lib/hookit/resource/warning.rb +87 -0
  45. data/lib/hookit/resource/zfs.rb +77 -0
  46. data/lib/hookit/resource.rb +21 -0
  47. data/lib/hookit/resources.rb +15 -0
  48. data/lib/hookit/setup.rb +59 -0
  49. data/lib/hookit/version.rb +3 -0
  50. data/lib/hookit.rb +26 -0
  51. metadata +208 -0
@@ -0,0 +1,96 @@
1
+ require 'oj'
2
+ require 'multi_json'
3
+
4
+ module Hookit
5
+ module Hook
6
+
7
+ def payload
8
+ @payload ||= parse_payload
9
+ end
10
+
11
+ def parse_payload
12
+ if not ARGV.empty?
13
+ MultiJson.load ARGV.first, symbolize_keys: true
14
+ else
15
+ {}
16
+ end
17
+ end
18
+
19
+ def converge(map, list)
20
+ Converginator.new(map, list).converge!
21
+ end
22
+
23
+ def registry(key, value=nil)
24
+ # normalize the catalog with keys
25
+ key = key.to_sym
26
+ unless value.nil?
27
+ db.put(key, value)
28
+ else
29
+ db.fetch(key)
30
+ end
31
+ end
32
+
33
+ def db
34
+ @db ||= Hookit::DB.new
35
+ end
36
+
37
+ def dict
38
+ @dict ||= {}
39
+ end
40
+
41
+ def set(key, value)
42
+ dict[key] = value
43
+ end
44
+
45
+ def get(key)
46
+ dict[key]
47
+ end
48
+
49
+ def log(level, message)
50
+ logger.log level, message
51
+ end
52
+
53
+ def logger
54
+ @logger ||= Hookit::Logger.new(get(:logfile), get(:log_level))
55
+ end
56
+
57
+ def platform
58
+ @platform ||= detect_platform
59
+ end
60
+
61
+ def detect_platform
62
+ Hookit.platforms.each do |key, value|
63
+ platform = value.new
64
+ if platform.detect?
65
+ return platform
66
+ end
67
+ end
68
+ false
69
+ end
70
+
71
+ # awesome resource-backed dsl
72
+ def method_missing(method_symbol, *args, &block)
73
+ resource_klass = Hookit.resources.get(method_symbol)
74
+ if resource_klass
75
+ resource = resource_klass.new(*args)
76
+ resource.dict = dict
77
+ resource.instance_eval(&block) if block_given?
78
+ if resource.can_run?
79
+ actions = resource.action
80
+ if actions.length > 1
81
+ res = {}
82
+ actions.each do |action|
83
+ res[action] = resource.run action
84
+ end
85
+ res
86
+ else
87
+ resource.run actions.first
88
+ end
89
+ end
90
+ else
91
+ super
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,60 @@
1
+ module Hookit
2
+ class Logger
3
+ require 'fileutils'
4
+
5
+ attr_reader :log_file, :log_level
6
+
7
+ def initialize(file, level)
8
+ @log_file = file || '/var/log/hookit/hookit.log'
9
+ @log_level = level || :error
10
+ ::FileUtils.mkdir_p(File.dirname(@log_file))
11
+ end
12
+
13
+ def log(level, message)
14
+
15
+ if not message
16
+ message = level
17
+ level = :error
18
+ end
19
+
20
+ if level_to_int(level) <= level_to_int(log_level)
21
+ send(level, message)
22
+ end
23
+
24
+ end
25
+
26
+ def error(message)
27
+ log! "[error]: #{message}\n"
28
+ end
29
+
30
+ def warn(message)
31
+ log! "[warn]: #{message}\n"
32
+ end
33
+
34
+ def info(message)
35
+ log! "[info]: #{message}\n"
36
+ end
37
+
38
+ def debug(message)
39
+ log! "[debug]: #{message}\n"
40
+ end
41
+
42
+ protected
43
+
44
+ def log!(message)
45
+ File.open log_file, 'a' do |f|
46
+ f.write message
47
+ end
48
+ end
49
+
50
+ def level_to_int(level)
51
+ case level
52
+ when :error then 1
53
+ when :warn then 2
54
+ when :info then 3
55
+ when :debug then 4
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ module Hookit
2
+ module Platform
3
+ class Base
4
+
5
+ def detect?; end
6
+ def name; end
7
+ def os; end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Hookit
2
+ module Platform
3
+ class Docker < Base
4
+
5
+ def detect?
6
+ ! `if [ -f "/.dockerenv" ] || [ -f "/.dockerinit" ] || \
7
+ grep -qF /docker/ "/proc/self/cgroup" 2>/dev/null; then
8
+ echo docker
9
+ fi`.empty?
10
+ end
11
+
12
+ def name
13
+ 'docker'
14
+ end
15
+
16
+ def os
17
+ 'linux'
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Hookit
2
+ module Platform
3
+ class Smartos < Base
4
+
5
+ def detect?
6
+ ! `cat /etc/release 2>/dev/null | grep -i SmartOS`.empty?
7
+ end
8
+
9
+ def name
10
+ 'smartos'
11
+ end
12
+
13
+ def os
14
+ 'sun'
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Hookit
2
+ module Platform
3
+ class Ubuntu < Base
4
+
5
+ def detect?
6
+ ! `[ -x /usr/bin/lsb_release ] && /usr/bin/lsb_release -i 2>/dev/null | grep Ubuntu`.empty?
7
+ end
8
+
9
+ def name
10
+ 'ubuntu'
11
+ end
12
+
13
+ def os
14
+ 'linux'
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ require 'hookit/platform/base'
2
+ require 'hookit/platform/docker'
3
+ require 'hookit/platform/smartos'
4
+ require 'hookit/platform/ubuntu'
5
+
6
+ module Hookit
7
+ module Platform
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ Hookit.platforms.register(:docker) { Hookit::Platform::Docker }
2
+ Hookit.platforms.register(:smartos) { Hookit::Platform::Smartos }
3
+ Hookit.platforms.register(:ubuntu) { Hookit::Platform::Ubuntu }
@@ -0,0 +1,53 @@
1
+ module Hookit
2
+ # Register components in a single location that can be queried.
3
+ #
4
+ # This allows certain components (such as guest systems, configuration
5
+ # pieces, etc.) to be registered and queried.
6
+ class Registry
7
+ def initialize
8
+ @actions = {}
9
+ @results_cache = {}
10
+ end
11
+
12
+ # Register a callable by key.
13
+ #
14
+ # The callable should be given in a block which will be lazily evaluated
15
+ # when the action is needed.
16
+ #
17
+ # If an action by the given name already exists then it will be
18
+ # overwritten.
19
+ def register(key, value=nil, &block)
20
+ @results_cache.delete key
21
+ block = lambda { value } unless value.nil?
22
+ @actions[key] = block
23
+ end
24
+
25
+ # Get an action by the given key.
26
+ #
27
+ # This will evaluate the block given to `register` and return the resulting
28
+ # action stack.
29
+ def get(key)
30
+ return nil unless @actions.has_key?(key)
31
+ return @results_cache[key] if @results_cache.has_key?(key)
32
+ @results_cache[key] = @actions[key].call
33
+ end
34
+ alias :[] :get
35
+
36
+ # Iterate over the keyspace.
37
+ def each(&block)
38
+ @actions.each do |key, _|
39
+ yield key, get(key)
40
+ end
41
+ end
42
+
43
+ # Converts this registry to a hash
44
+ def to_hash
45
+ result = {}
46
+ self.each do |key, value|
47
+ result[key] = value
48
+ end
49
+
50
+ result
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,138 @@
1
+ module Hookit
2
+ module Resource
3
+ class Base
4
+
5
+ class << self
6
+
7
+ def field(key)
8
+ define_method key do |*args, &block|
9
+ if data = block || args[0]
10
+ instance_variable_set("@#{key}", data)
11
+ else
12
+ instance_variable_get("@#{key}")
13
+ end
14
+ end
15
+ end
16
+
17
+ def actions(*actions)
18
+ if actions.any?
19
+ @actions = *actions
20
+ else
21
+ @actions
22
+ end
23
+ end
24
+
25
+ def default_action(action=nil)
26
+ if action
27
+ @default_action = action
28
+ else
29
+ @default_action || :run
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ attr_accessor :dict
36
+
37
+ field :name
38
+
39
+ def initialize(name)
40
+ name(name)
41
+ end
42
+
43
+ def run(action); end
44
+
45
+ def can_run?
46
+ only_if_res = true
47
+ not_if_res = false
48
+
49
+ if only_if and only_if.respond_to? :call
50
+ only_if_res = only_if.call
51
+ end
52
+
53
+ if not_if and not_if.respond_to? :call
54
+ not_if_res = not_if.call
55
+ end
56
+
57
+ only_if_res and not not_if_res
58
+ end
59
+
60
+ def action(*actions)
61
+ if actions.any?
62
+ actions.each do |action|
63
+ if not self.class.actions.include? action
64
+ raise Hookit::Error::UnknownAction, "unknown action '#{action}'"
65
+ end
66
+ end
67
+ @actions = *actions
68
+ else
69
+ @actions || [default_action]
70
+ end
71
+ end
72
+
73
+ def default_action
74
+ self.class.default_action
75
+ end
76
+
77
+ def not_if(&block)
78
+ if block_given?
79
+ @not_if = block
80
+ else
81
+ @not_if
82
+ end
83
+ end
84
+
85
+ def only_if(&block)
86
+ if block_given?
87
+ @only_if = block
88
+ else
89
+ @only_if
90
+ end
91
+ end
92
+
93
+ protected
94
+
95
+ def run_command!(cmd, expect_code=0)
96
+ res = `#{cmd} 2>&1`
97
+ code = $?.exitstatus
98
+
99
+ # break early if the caller doesn't want to validate the exit code
100
+ if expect_code == false
101
+ return
102
+ end
103
+
104
+ if code != expect_code
105
+ print_error(name, {
106
+ exit: "#{code}",
107
+ command: cmd,
108
+ output: res
109
+ })
110
+ end
111
+ end
112
+
113
+ # print_error prints an error message to the user explaining
114
+ # what happened. This is intended to be a pleasant alternative
115
+ # to a ruby stack trace.
116
+ def print_error(message, opts={})
117
+ STDERR.puts
118
+ STDERR.puts "! FAILED TO #{message.upcase} !"
119
+ STDERR.puts
120
+
121
+ opts.each_pair do |k, v|
122
+ next if v.nil? || v == ""
123
+
124
+ STDERR.puts "#{k.capitalize}"
125
+
126
+ v.split("\n").each do |line|
127
+ STDERR.puts " #{line}"
128
+ end
129
+
130
+ STDERR.puts
131
+ end
132
+
133
+ exit 1
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,29 @@
1
+ module Hookit
2
+ module Resource
3
+ class Cron < Execute
4
+
5
+ def initialize(name)
6
+ super
7
+ timeout 60
8
+ cwd '/data'
9
+ end
10
+
11
+ protected
12
+
13
+ def run!
14
+ begin
15
+ Timeout::timeout(timeout) do
16
+ f = IO.popen("#{cmd} || exit 0", :err=>[:child, :out])
17
+ puts f.readline while true
18
+ end
19
+ rescue Timeout::Error
20
+ print_error(name, {
21
+ command: cmd,
22
+ failure: "failed to return within #{timeout} seconds"
23
+ })
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,69 @@
1
+ module Hookit
2
+ module Resource
3
+ class Directory < Base
4
+
5
+ field :path
6
+ field :recursive
7
+ field :mode
8
+ field :owner
9
+ field :group
10
+
11
+ actions :create, :delete
12
+ default_action :create
13
+
14
+ def initialize(name)
15
+ path name unless path
16
+ super
17
+ end
18
+
19
+ def run(action)
20
+ case action
21
+ when :create
22
+ create!
23
+ chown!
24
+ chmod!
25
+ when :delete
26
+ delete!
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def create!
33
+ return if ::File.exists? path
34
+ run_command! "mkdir #{"-p " if recursive}#{path}"
35
+ end
36
+
37
+ def delete!
38
+ return if not ::File.exists? path
39
+ run_command! "rm -rf #{path}"
40
+ end
41
+
42
+ def chown!
43
+ return unless owner or group
44
+ if ::File.exists? path
45
+ cmd = "chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}"
46
+ run_command! "chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}"
47
+ end
48
+ end
49
+
50
+ def chmod!
51
+ if ::File.exists? path and mode
52
+ begin
53
+ ::File.chmod(mode, path)
54
+ rescue Exception => e
55
+ unexpected_failure("chmod file", e.message)
56
+ end
57
+ end
58
+ end
59
+
60
+ def unexpected_failure(message, reason)
61
+ print_error(message, {
62
+ path: path,
63
+ reason: reason
64
+ })
65
+ end
66
+
67
+ end
68
+ end
69
+ end