hookit 0.7.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +3 -0
  6. data/Rakefile +10 -0
  7. data/bin/hookit +41 -0
  8. data/hookit.gemspec +30 -0
  9. data/lib/hookit/converginator.rb +141 -0
  10. data/lib/hookit/db.rb +37 -0
  11. data/lib/hookit/error.rb +8 -0
  12. data/lib/hookit/exit.rb +23 -0
  13. data/lib/hookit/helper/cron.rb +42 -0
  14. data/lib/hookit/helper/nfs.rb +113 -0
  15. data/lib/hookit/helper/shell.rb +35 -0
  16. data/lib/hookit/helper/xml.rb +25 -0
  17. data/lib/hookit/helper.rb +9 -0
  18. data/lib/hookit/hook.rb +102 -0
  19. data/lib/hookit/logger.rb +58 -0
  20. data/lib/hookit/logvac.rb +34 -0
  21. data/lib/hookit/platform/base.rb +11 -0
  22. data/lib/hookit/platform/smartos.rb +19 -0
  23. data/lib/hookit/platform/ubuntu.rb +19 -0
  24. data/lib/hookit/platform.rb +9 -0
  25. data/lib/hookit/platforms.rb +2 -0
  26. data/lib/hookit/registry.rb +53 -0
  27. data/lib/hookit/resource/base.rb +105 -0
  28. data/lib/hookit/resource/cron.rb +26 -0
  29. data/lib/hookit/resource/directory.rb +67 -0
  30. data/lib/hookit/resource/execute.rb +148 -0
  31. data/lib/hookit/resource/file.rb +71 -0
  32. data/lib/hookit/resource/hook_file.rb +80 -0
  33. data/lib/hookit/resource/link.rb +61 -0
  34. data/lib/hookit/resource/logrotate.rb +38 -0
  35. data/lib/hookit/resource/mount.rb +77 -0
  36. data/lib/hookit/resource/package.rb +74 -0
  37. data/lib/hookit/resource/rsync.rb +67 -0
  38. data/lib/hookit/resource/scp.rb +87 -0
  39. data/lib/hookit/resource/service.rb +89 -0
  40. data/lib/hookit/resource/socket.rb +67 -0
  41. data/lib/hookit/resource/template.rb +87 -0
  42. data/lib/hookit/resource/warning.rb +87 -0
  43. data/lib/hookit/resource/zfs.rb +99 -0
  44. data/lib/hookit/resource.rb +21 -0
  45. data/lib/hookit/resources.rb +15 -0
  46. data/lib/hookit/version.rb +3 -0
  47. data/lib/hookit.rb +27 -0
  48. metadata +205 -0
@@ -0,0 +1,58 @@
1
+ module Hookit
2
+ class Logger
3
+
4
+ attr_reader :log_file, :log_level
5
+
6
+ def initialize(file, level)
7
+ @log_file = file || '/var/log/hookit/hookit.log'
8
+ @log_level = level || :error
9
+ end
10
+
11
+ def log(level, message)
12
+
13
+ if not message
14
+ message = level
15
+ level = :error
16
+ end
17
+
18
+ if level_to_int(level) <= level_to_int(log_level)
19
+ send(level, message)
20
+ end
21
+
22
+ end
23
+
24
+ def error(message)
25
+ log! "[error]: #{message}\n"
26
+ end
27
+
28
+ def warn(message)
29
+ log! "[warn]: #{message}\n"
30
+ end
31
+
32
+ def info(message)
33
+ log! "[info]: #{message}\n"
34
+ end
35
+
36
+ def debug(message)
37
+ log! "[debug]: #{message}\n"
38
+ end
39
+
40
+ protected
41
+
42
+ def log!(message)
43
+ File.open log_file, 'a' do |f|
44
+ f.write message
45
+ end
46
+ end
47
+
48
+ def level_to_int(level)
49
+ case level
50
+ when :error then 1
51
+ when :warn then 2
52
+ when :info then 3
53
+ when :debug then 4
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ require 'faraday'
2
+
3
+ module Hookit
4
+ class Logvac
5
+
6
+ def initialize(opts)
7
+ @app = opts[:app]
8
+ @deploy = opts[:deploy]
9
+ @token = opts[:token]
10
+ end
11
+
12
+ def post(message)
13
+ connection.post("/deploy/#{@app}") do |req|
14
+ req.headers[:x_auth_token] = @token
15
+ req.headers[:x_deploy_id] = @deploy
16
+ req.body = message
17
+ end
18
+ end
19
+ alias :print :post
20
+
21
+ def puts(message='')
22
+ post("#{message}\n")
23
+ end
24
+
25
+ protected
26
+
27
+ def connection
28
+ @connection ||= Faraday.new(url: 'http://logvac.admin.pagodabox.io:6361') do |faraday|
29
+ faraday.adapter :excon
30
+ end
31
+ end
32
+
33
+ end
34
+ 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,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,9 @@
1
+ require 'hookit/platform/base'
2
+ require 'hookit/platform/smartos'
3
+ require 'hookit/platform/ubuntu'
4
+
5
+ module Hookit
6
+ module Platform
7
+
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ Hookit.platforms.register(:smartos) { Hookit::Platform::Smartos }
2
+ 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,105 @@
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
+ `#{cmd}`
97
+ code = $?.exitstatus
98
+ if code != expect_code
99
+ raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
100
+ end
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,26 @@
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
+ $stderr.puts 'Timed out running cron! Consider using a worker.'
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,67 @@
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
+ cmd = "mkdir #{"-p " if recursive}#{path}"
35
+ `#{cmd}`
36
+ code = $?.exitstatus
37
+ if code != 0
38
+ raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
39
+ end
40
+ end
41
+
42
+ def delete!
43
+ return if not ::File.exists? path
44
+ cmd = "rm -rf #{path}"
45
+ `#{cmd}`
46
+ code = $?.exitstatus
47
+ if code != 0
48
+ raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
49
+ end
50
+ end
51
+
52
+ def chown!
53
+ return unless owner or group
54
+ if ::File.exists? path
55
+ `chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
56
+ end
57
+ end
58
+
59
+ def chmod!
60
+ if ::File.exists? path and mode
61
+ ::File.chmod(mode, path)
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,148 @@
1
+ require 'timeout'
2
+
3
+ module Hookit
4
+ module Resource
5
+ class Execute < Base
6
+
7
+ field :command
8
+ field :cwd
9
+ field :environment
10
+ field :user
11
+ field :path
12
+ field :returns
13
+ field :timeout
14
+ field :stream
15
+ field :on_data
16
+ field :validator
17
+ field :ignore_exit
18
+
19
+ actions :run
20
+ default_action :run
21
+
22
+ def initialize(name)
23
+ command name unless command
24
+ timeout 3600
25
+ returns 0
26
+ super
27
+ end
28
+
29
+ def run(action)
30
+ case action
31
+ when :run
32
+ if stream
33
+ stream!
34
+ else
35
+ run!
36
+ end
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def validate!(res)
43
+ if validator.is_a? Proc
44
+ if validator.call(res)
45
+ res
46
+ else
47
+ raise "ERROR: execute resource \"#{name}\" failed validation!"
48
+ end
49
+ else
50
+ res
51
+ end
52
+ end
53
+
54
+ def run!
55
+ Timeout::timeout(timeout) do
56
+ res = `#{cmd}`
57
+ code = $?.exitstatus
58
+ unexpected_exit(code) unless code == returns
59
+ validate! res
60
+ end
61
+ end
62
+
63
+ def stream!
64
+ result = ""
65
+
66
+ STDOUT.sync = STDERR.sync = true # don't buffer stdout/stderr
67
+
68
+ ::IO.popen(cmd, :err=>[:child, :out]) do |out|
69
+ eof = false
70
+ until eof do
71
+ begin
72
+ chunk = out.readpartial(4096)
73
+ if on_data and on_data.respond_to? :call
74
+ on_data.call(chunk)
75
+ end
76
+ rescue EOFError
77
+ eof = true
78
+ end
79
+ result << chunk.to_s
80
+ end
81
+ end
82
+
83
+ code = $?.exitstatus
84
+ unexpected_exit(code) unless code == returns
85
+
86
+ validate! result
87
+ end
88
+
89
+ def cmd
90
+ com = command
91
+
92
+ if environment
93
+ com = "#{env}#{com}"
94
+ end
95
+
96
+ if path
97
+ com = "export PATH=\"#{path}\"; #{com}"
98
+ end
99
+
100
+ if cwd
101
+ com = "cd #{cwd}; #{com}"
102
+ end
103
+
104
+ if user
105
+ com = su(user, com)
106
+ end
107
+
108
+ com
109
+ end
110
+
111
+ # strategy:
112
+ # 1- escape the escapes
113
+ # 2- escape quotes
114
+ # 3- escape dollar signs
115
+ def escape(cmd)
116
+ cmd.gsub!(/\\/, "\\\\\\")
117
+ cmd.gsub!(/"/, "\\\"")
118
+ cmd.gsub!(/\$/, "\\$")
119
+ cmd
120
+ end
121
+
122
+ def su(user, cmd)
123
+ "su - #{user} -c \"#{escape(cmd)}\""
124
+ end
125
+
126
+ def env
127
+ vars = environment || {}
128
+ env = ''
129
+ vars.each do |key, val|
130
+ env += " " if not env == ''
131
+ env += env_string(key, val)
132
+ end
133
+ (env == '')? env : "#{env}"
134
+ end
135
+
136
+ def env_string(key, val)
137
+ key = key.to_s if not key.is_a? String
138
+ val = val.to_s if not val.is_a? String
139
+ %Q{export #{key.upcase}="#{escape(val)}";}
140
+ end
141
+
142
+ def unexpected_exit(res)
143
+ raise Hookit::Error::UnexpectedExit, "'#{name}' exited with #{res}, expected #{returns}" unless ignore_exit
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,71 @@
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
+ ::File.write path, (content || "")
40
+ end
41
+
42
+ def create_if_missing!
43
+ if not ::File.exists? path
44
+ create!
45
+ end
46
+ end
47
+
48
+ def delete!
49
+ ::File.delete path
50
+ end
51
+
52
+ def chown!
53
+ return unless owner or group
54
+ if ::File.exists? path
55
+ `chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
56
+ end
57
+ end
58
+
59
+ def chmod!
60
+ if ::File.exists? path and mode
61
+ ::File.chmod(mode, path)
62
+ end
63
+ end
64
+
65
+ def touch!
66
+ `touch -c #{path}`
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,80 @@
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
+ ::File.write path, render
41
+ end
42
+
43
+ def create_if_missing!
44
+ if not ::File.exists? path
45
+ create!
46
+ end
47
+ end
48
+
49
+ def delete!
50
+ ::File.delete path
51
+ end
52
+
53
+ def chown!
54
+ return unless owner or group
55
+ `chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
56
+ end
57
+
58
+ def chmod!
59
+ ::File.chmod(mode, path) if mode
60
+ end
61
+
62
+ def touch!
63
+ `touch -c #{path}`
64
+ end
65
+
66
+ def render
67
+ ::File.read("#{file_dir}/#{source}")
68
+ end
69
+
70
+ def file_dir
71
+ "#{module_root}/files"
72
+ end
73
+
74
+ def module_root
75
+ dict[:module_root]
76
+ end
77
+
78
+ end
79
+ end
80
+ end