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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +24 -0
- data/Rakefile +18 -0
- data/bin/hookit +51 -0
- data/boxfile.yml +2 -0
- data/hookit.gemspec +30 -0
- data/lib/hookit/converginator.rb +165 -0
- data/lib/hookit/db.rb +37 -0
- data/lib/hookit/error.rb +9 -0
- data/lib/hookit/exit.rb +23 -0
- data/lib/hookit/helper/cron.rb +42 -0
- data/lib/hookit/helper/nfs.rb +113 -0
- data/lib/hookit/helper/shell.rb +35 -0
- data/lib/hookit/helper/xml.rb +25 -0
- data/lib/hookit/helper.rb +9 -0
- data/lib/hookit/hook.rb +96 -0
- data/lib/hookit/logger.rb +60 -0
- data/lib/hookit/platform/base.rb +11 -0
- data/lib/hookit/platform/docker.rb +22 -0
- data/lib/hookit/platform/smartos.rb +19 -0
- data/lib/hookit/platform/ubuntu.rb +19 -0
- data/lib/hookit/platform.rb +10 -0
- data/lib/hookit/platforms.rb +3 -0
- data/lib/hookit/registry.rb +53 -0
- data/lib/hookit/resource/base.rb +138 -0
- data/lib/hookit/resource/cron.rb +29 -0
- data/lib/hookit/resource/directory.rb +69 -0
- data/lib/hookit/resource/execute.rb +205 -0
- data/lib/hookit/resource/file.rb +89 -0
- data/lib/hookit/resource/hook_file.rb +109 -0
- data/lib/hookit/resource/link.rb +50 -0
- data/lib/hookit/resource/logrotate.rb +36 -0
- data/lib/hookit/resource/mount.rb +85 -0
- data/lib/hookit/resource/package.rb +57 -0
- data/lib/hookit/resource/rsync.rb +58 -0
- data/lib/hookit/resource/scp.rb +78 -0
- data/lib/hookit/resource/service.rb +117 -0
- data/lib/hookit/resource/socket.rb +79 -0
- data/lib/hookit/resource/template.rb +114 -0
- data/lib/hookit/resource/warning.rb +87 -0
- data/lib/hookit/resource/zfs.rb +77 -0
- data/lib/hookit/resource.rb +21 -0
- data/lib/hookit/resources.rb +15 -0
- data/lib/hookit/setup.rb +59 -0
- data/lib/hookit/version.rb +3 -0
- data/lib/hookit.rb +26 -0
- metadata +208 -0
data/lib/hookit/hook.rb
ADDED
@@ -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,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 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,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
|