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,205 @@
1
+ require 'timeout'
2
+ require 'open3'
3
+
4
+ module Hookit
5
+ module Resource
6
+ class Execute < Base
7
+
8
+ field :command
9
+ field :cwd
10
+ field :environment
11
+ field :user
12
+ field :path
13
+ field :returns
14
+ field :timeout
15
+ field :stream
16
+ field :on_data
17
+ field :on_stdout
18
+ field :on_stderr
19
+ field :on_exit
20
+ field :validator
21
+ field :ignore_exit
22
+
23
+ actions :run
24
+ default_action :run
25
+
26
+ def initialize(name)
27
+ command name unless command
28
+ returns 0
29
+ super
30
+ end
31
+
32
+ def run(action)
33
+ case action
34
+ when :run
35
+ if stream
36
+ stream!
37
+ else
38
+ run!
39
+ end
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ def validate!(res)
46
+ if validator.is_a? Proc
47
+ if validator.call(res)
48
+ res
49
+ else
50
+ print_error(name, {
51
+ command: cmd,
52
+ failure: "failed validation"
53
+ })
54
+ end
55
+ else
56
+ res
57
+ end
58
+ end
59
+
60
+ def run!
61
+ timeout = timeout || 3600
62
+ stream!
63
+ end
64
+
65
+ def stream!
66
+ exit_status = 0
67
+ result = ""
68
+
69
+ # don't buffer /stdin/stdout/stderr
70
+ STDIN.sync = true
71
+ STDOUT.sync = true
72
+ STDERR.sync = true
73
+
74
+ Open3.popen3 cmd do |stdin, stdout, stderr, wait_thr|
75
+ begin
76
+ Timeout::timeout(timeout) do
77
+ stdout_eof = false
78
+ stderr_eof = false
79
+
80
+ until stdout_eof and stderr_eof do
81
+ (ready_pipes, dummy, dummy) = IO.select([STDIN, stdout, stderr])
82
+ ready_pipes.each_with_index do |socket|
83
+ if socket == stdout
84
+ begin
85
+ chunk = socket.readpartial(4096)
86
+ if on_data and on_data.respond_to? :call
87
+ on_data.call(chunk)
88
+ end
89
+ if on_stdout and on_stdout.respond_to? :call
90
+ on_stdout.call(chunk)
91
+ end
92
+ rescue EOFError
93
+ stdout_eof = true
94
+ end
95
+ result << chunk.to_s
96
+ elsif socket == stderr
97
+ begin
98
+ chunk = socket.readpartial(4096)
99
+ if on_data and on_data.respond_to? :call
100
+ on_data.call(chunk)
101
+ end
102
+ if on_stderr and on_stderr.respond_to? :call
103
+ on_stderr.call(chunk)
104
+ end
105
+ rescue EOFError
106
+ stderr_eof = true
107
+ end
108
+ result << chunk.to_s
109
+ elsif socket == STDIN
110
+ # write what we got on STDIN right into the process' stdin
111
+ chunk = socket.readpartial(4096)
112
+ stdin.write(chunk)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ rescue Timeout::Error => e
118
+ Process.kill 9, wait_thr[:pid]
119
+
120
+ print_error(name, {
121
+ command: cmd,
122
+ failure: "failed to return within #{timeout} seconds"
123
+ })
124
+ exit 1
125
+ end
126
+
127
+
128
+ exit_status = wait_thr.value.to_s.match(/exit (\d+)/)[1].to_i
129
+ end
130
+
131
+ if on_exit and on_exit.respond_to? :call
132
+ on_exit.call(exit_status)
133
+ else
134
+ unexpected_exit(exit_status, result) unless exit_status == returns
135
+ end
136
+
137
+ validate! result
138
+ end
139
+
140
+ def cmd
141
+ com = command
142
+
143
+ if environment
144
+ com = "#{env}#{com}"
145
+ end
146
+
147
+ if path
148
+ com = "export PATH=\"#{path}\"; #{com}"
149
+ end
150
+
151
+ if cwd
152
+ com = "cd #{cwd}; #{com}"
153
+ end
154
+
155
+ if user
156
+ com = su(user, com)
157
+ end
158
+
159
+ com
160
+ end
161
+
162
+ # strategy:
163
+ # 1- escape the escapes
164
+ # 2- escape quotes
165
+ # 3- escape dollar signs
166
+ def escape(cmd)
167
+ cmd.gsub!(/\\/, "\\\\\\")
168
+ cmd.gsub!(/"/, "\\\"")
169
+ cmd.gsub!(/\$/, "\\$")
170
+ cmd
171
+ end
172
+
173
+ def su(user, cmd)
174
+ "su - #{user} -c \"#{escape(cmd)}\""
175
+ end
176
+
177
+ def env
178
+ vars = environment || {}
179
+ env = ''
180
+ vars.each do |key, val|
181
+ env += " " if not env == ''
182
+ env += env_string(key, val)
183
+ end
184
+ (env == '')? env : "#{env} "
185
+ end
186
+
187
+ def env_string(key, val)
188
+ key = key.to_s if not key.is_a? String
189
+ val = val.to_s if not val.is_a? String
190
+ %Q{export #{key.upcase}="#{escape(val)}";}
191
+ end
192
+
193
+ def unexpected_exit(res, output="")
194
+ return if ignore_exit
195
+
196
+ print_error(name, {
197
+ exit: "#{res}",
198
+ command: cmd,
199
+ output: output
200
+ })
201
+ end
202
+
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,89 @@
1
+ module Hookit
2
+ module Resource
3
+ class File < Base
4
+
5
+ field :path
6
+ field :content
7
+ field :mode
8
+ field :owner
9
+ field :group
10
+
11
+ actions :create, :create_if_missing, :delete, :touch
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 :create_if_missing
26
+ create_if_missing!
27
+ chown!
28
+ chmod!
29
+ when :delete
30
+ delete!
31
+ when :touch
32
+ touch!
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ def create!
39
+ begin
40
+ ::File.write path, (content || "")
41
+ rescue Exception => e
42
+ unexpected_failure("create file", e.message)
43
+ end
44
+ end
45
+
46
+ def create_if_missing!
47
+ if not ::File.exists? path
48
+ create!
49
+ end
50
+ end
51
+
52
+ def delete!
53
+ begin
54
+ ::File.delete path
55
+ rescue Exception => e
56
+ unexpected_failure("delete file", e.message)
57
+ end
58
+ end
59
+
60
+ def chown!
61
+ return unless owner or group
62
+ if ::File.exists? path
63
+ run_command! "chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}"
64
+ end
65
+ end
66
+
67
+ def chmod!
68
+ if ::File.exists? path and mode
69
+ begin
70
+ ::File.chmod(mode, path)
71
+ rescue Exception => e
72
+ unexpected_failure("chmod file", e.message)
73
+ end
74
+ end
75
+ end
76
+
77
+ def touch!
78
+ run_command! "touch -c #{path}"
79
+ end
80
+
81
+ def unexpected_failure(message, reason)
82
+ print_error(message, {
83
+ path: path,
84
+ reason: reason
85
+ })
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,109 @@
1
+ module Hookit
2
+ module Resource
3
+ class HookFile < Base
4
+
5
+ field :path
6
+ field :source
7
+ field :mode
8
+ field :owner
9
+ field :group
10
+
11
+ actions :create, :create_if_missing, :delete, :touch
12
+ default_action :create
13
+
14
+ def initialize(name)
15
+ path name unless path
16
+ source ::File.basename(name)
17
+ super
18
+ end
19
+
20
+ def run(action)
21
+ case action
22
+ when :create
23
+ create!
24
+ chown!
25
+ chmod!
26
+ when :create_if_missing
27
+ create_if_missing!
28
+ chown!
29
+ chmod!
30
+ when :delete
31
+ delete!
32
+ when :touch
33
+ touch!
34
+ end
35
+ end
36
+
37
+ protected
38
+
39
+ def create!
40
+ begin
41
+ ::File.write path, render
42
+ rescue Exception => e
43
+ unexpected_failure("create file", e.message)
44
+ end
45
+ end
46
+
47
+ def create_if_missing!
48
+ if not ::File.exists? path
49
+ create!
50
+ end
51
+ end
52
+
53
+ def delete!
54
+ begin
55
+ ::File.delete path
56
+ rescue Exception => e
57
+ unexpected_failure("delete file", e.message)
58
+ end
59
+ end
60
+
61
+ def chown!
62
+ return unless owner or group
63
+ if ::File.exists? path
64
+ run_command! "chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}"
65
+ end
66
+ end
67
+
68
+ def chmod!
69
+ if ::File.exists? path and mode
70
+ begin
71
+ ::File.chmod(mode, path)
72
+ rescue Exception => e
73
+ unexpected_failure("chmod file", e.message)
74
+ end
75
+ end
76
+ end
77
+
78
+ def touch!
79
+ run_command! "touch -c #{path}"
80
+ end
81
+
82
+ def render
83
+ begin
84
+ ::File.read("#{file_dir}/#{source}")
85
+ rescue Exception => e
86
+ print_error("read hook_file", {
87
+ path: "#{file_dir}/#{source}",
88
+ reason: e.message
89
+ })
90
+ end
91
+ end
92
+
93
+ def file_dir
94
+ "#{module_root}/files"
95
+ end
96
+
97
+ def module_root
98
+ dict[:module_root]
99
+ end
100
+
101
+ def unexpected_failure(message, reason)
102
+ print_error(message, {
103
+ path: path,
104
+ reason: reason
105
+ })
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,50 @@
1
+ module Hookit
2
+ module Resource
3
+ class Link < Base
4
+
5
+ field :owner
6
+ field :group
7
+ field :link_type
8
+ field :target_file
9
+ field :to
10
+
11
+ actions :create, :delete
12
+ default_action :create
13
+
14
+ def initialize(name)
15
+ target_file name unless target_file
16
+ link_type :symbolic
17
+ super
18
+ end
19
+
20
+ def run(action)
21
+ case action
22
+ when :create
23
+ create!
24
+ chown!
25
+ when :delete
26
+ delete!
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def create!
33
+ args = ['f']
34
+ args << 'sn' if link_type == :symbolic
35
+ run_command! "ln -#{args.join} #{to} #{target_file}"
36
+ end
37
+
38
+ def delete!
39
+ run_command! "rm -f #{target_file}"
40
+ end
41
+
42
+ def chown!
43
+ return unless owner or group
44
+ if ::File.exists? target_file
45
+ run_command! "chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{target_file}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,36 @@
1
+ module Hookit
2
+ module Resource
3
+ class Logrotate < Base
4
+
5
+ field :path
6
+ field :filesize
7
+ field :max_size
8
+ field :count
9
+
10
+ actions :create
11
+ default_action :create
12
+
13
+ def initialize(name)
14
+ path name unless path
15
+ super
16
+ end
17
+
18
+ def run(action)
19
+ case action
20
+ when :create
21
+ create!
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def create!
28
+ case platform.os
29
+ when 'sun'
30
+ run_command! `logadm -c -w #{path} -s #{filesize ||= '10m'} -S #{max_size ||= '500m'} -C #{count ||= '10'} -N`
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,85 @@
1
+ module Hookit
2
+ module Resource
3
+ class Mount < Base
4
+
5
+ field :device
6
+ # field :device_type
7
+ # field :dump
8
+ field :fstype
9
+ field :mount_point
10
+ field :options
11
+ field :pass
12
+ field :supports
13
+
14
+ actions :mount, :umount, :remount, :enable, :disable
15
+ default_action :mount
16
+
17
+ def initialize(name)
18
+ mount_point(name) unless mount_point
19
+ pass('-') unless pass
20
+ super
21
+ end
22
+
23
+ def run(action)
24
+ case action
25
+ when :mount
26
+ mount!
27
+ when :umount
28
+ umount!
29
+ when :remount
30
+ umount!
31
+ mount!
32
+ when :enable
33
+ disable!
34
+ enable!
35
+ when :disable
36
+ disable!
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def mount!
43
+ ::FileUtils.mkdir_p(mount_point)
44
+ case platform.os
45
+ when 'sun'
46
+ run_command! "mount -O -F #{fstype} -o retry=5,timeo=300 #{options!(as_arg=true)} #{device} #{mount_point}"
47
+ when 'linux'
48
+ run_command! "mount -t #{fstype} -o retry=5,timeo=300 #{options!(as_arg=true)} #{device} #{mount_point}"
49
+ end
50
+ end
51
+
52
+ def umount!
53
+ run_command! "umount #{mount_point}"
54
+ end
55
+
56
+ def enable!
57
+ entry = "#{device}\t#{device =~ /^\/dev/ ? device : "-"}\t#{mount_point}\t#{fstype}\t#{pass}\tyes\t#{options!}"
58
+ case platform.os
59
+ when 'sun'
60
+ run_command! `echo "#{entry}" >> /etc/vfstab`
61
+ when 'linux'
62
+ run_command! `echo "#{entry}" >> /etc/fstab`
63
+ end
64
+ end
65
+
66
+ def disable!
67
+ case platform.os
68
+ when 'sun'
69
+ run_command! `egrep -v "#{device}.*#{mount_point}" /etc/vfstab > /tmp/vfstab.tmp; mv -f /tmp/vfstab.tmp /etc/vfstab`
70
+ when 'linux'
71
+ run_command! `egrep -v "#{device}.*#{mount_point}" /etc/fstab > /tmp/vfstab.tmp; mv -f /tmp/vfstab.tmp /etc/vfstab`
72
+ end
73
+ end
74
+
75
+ def options!(as_arg=false)
76
+ options = self.options.kind_of?(Array) ? self.options.join(',') : self.options
77
+ if as_arg
78
+ options ? (return "-o #{options}") : (return "")
79
+ end
80
+ options != "" ? (return "#{options}") : (return "-")
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,57 @@
1
+ module Hookit
2
+ module Resource
3
+ class Package < Base
4
+
5
+ field :package_name
6
+ field :source
7
+ field :version
8
+ field :scope
9
+
10
+ actions :install, :update
11
+ default_action :install
12
+
13
+ def initialize(name)
14
+ package_name(name) unless source
15
+ scope :default unless scope
16
+ super
17
+ end
18
+
19
+ def run(action)
20
+ case action
21
+ when :install
22
+ install!
23
+ when :update
24
+ update!
25
+ end
26
+ end
27
+
28
+ def install!
29
+ run_command! "#{pkgin} -y in #{package}"
30
+ end
31
+
32
+ def update!
33
+ run_command! `#{pkgin} -y up`
34
+ end
35
+
36
+ protected
37
+
38
+ def package
39
+ if version
40
+ "#{package_name}-#{version}"
41
+ else
42
+ package_name
43
+ end
44
+ end
45
+
46
+ def pkgin
47
+ case scope
48
+ when :default
49
+ "/opt/local/bin/pkgin"
50
+ when :gomicro
51
+ "/opt/gomicro/bin/pkgin"
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ module Hookit
2
+ module Resource
3
+ class Rsync < Base
4
+
5
+ field :source
6
+ field :destination
7
+ field :wrapper
8
+ field :archive
9
+ field :recursive
10
+ field :checksum
11
+ field :compress
12
+
13
+ actions :sync
14
+ default_action :sync
15
+
16
+ def initialize(name)
17
+ source name unless source
18
+ super
19
+ end
20
+
21
+ def run(action)
22
+ case action
23
+ when :sync
24
+ sync!
25
+ end
26
+ end
27
+
28
+ def sync!
29
+ run_command! "rsync -q#{archive!}#{recursive!}#{checksum!}#{compress!} #{wrapper!} #{source} #{destination}"
30
+ end
31
+
32
+ def archive!
33
+ (return "a") if archive
34
+ ""
35
+ end
36
+
37
+ def recursive!
38
+ (return "r") if archive
39
+ ""
40
+ end
41
+
42
+ def checksum!
43
+ (return "c") if archive
44
+ ""
45
+ end
46
+
47
+ def compress!
48
+ (return "z") if archive
49
+ ""
50
+ end
51
+
52
+ def wrapper!
53
+ (return "-e '#{wrapper}'") if wrapper
54
+ ""
55
+ end
56
+ end
57
+ end
58
+ end