foreman_hooks 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +37 -19
- data/examples/hook_functions.sh +28 -0
- data/examples/log.sh +19 -0
- data/foreman_hooks.gemspec +2 -2
- data/lib/foreman_hooks/engine.rb +1 -4
- data/lib/foreman_hooks/orchestration_hook.rb +1 -1
- data/lib/foreman_hooks/util.rb +14 -3
- metadata +4 -2
data/README.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# foreman_hooks
|
2
2
|
|
3
3
|
Allows you to trigger scripts and commands on the Foreman server at any point
|
4
|
-
in an object's lifecycle in Foreman. This lets you run
|
4
|
+
in an object's lifecycle in Foreman. This lets you run scripts when a host
|
5
5
|
is created, or finishes provisioning etc.
|
6
6
|
|
7
|
-
It
|
8
|
-
|
7
|
+
It enables extension of Foreman's host orchestration so additional tasks can
|
8
|
+
be executed, and can register hooks into standard Rails callbacks for any
|
9
|
+
Foreman object, all with shell scripts.
|
9
10
|
|
10
11
|
# Installation:
|
11
12
|
|
@@ -29,7 +30,8 @@ To upgrade to newest version of the plugin:
|
|
29
30
|
|
30
31
|
Hooks are stored in `/usr/share/foreman/config/hooks` (`~foreman/config/hooks`)
|
31
32
|
with a subdirectory for the object, then a subdirectory for the event name.
|
32
|
-
|
33
|
+
|
34
|
+
~foreman/config/hooks/$OBJECT/$EVENT/$HOOK_SCRIPT
|
33
35
|
|
34
36
|
Examples:
|
35
37
|
|
@@ -37,17 +39,15 @@ Examples:
|
|
37
39
|
~foreman/config/hooks/host/destroy/15_cleanup_database.sh
|
38
40
|
~foreman/config/hooks/smart_proxy/after_create/01_email_operations.sh
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
the hook directory becomes `host/base/` and `host/managed/` respectively.
|
42
|
+
In Foreman 1.1, all hosts are `host` but in Foreman 1.2, managed hosts will
|
43
|
+
become `host/managed` instead.
|
43
44
|
|
44
45
|
## Objects / Models
|
45
46
|
|
46
47
|
Every object (or model in Rails terms) in Foreman can have hooks. Check
|
47
48
|
`~foreman/app/models` for the full list, but these are the interesting ones:
|
48
49
|
|
49
|
-
* `host` (
|
50
|
-
* `host/discovered` (Foreman 1.2)
|
50
|
+
* `host` (or `host/managed` in Foreman 1.2)
|
51
51
|
* `report`
|
52
52
|
|
53
53
|
## Orchestration events
|
@@ -65,21 +65,22 @@ To add hooks to these, use these event names:
|
|
65
65
|
|
66
66
|
## Rails events
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
For hooks on anything apart from hosts (which support orchestration, as above)
|
69
|
+
then the standard Rails events will be needed. These are the most interesting
|
70
|
+
events provided:
|
70
71
|
|
71
|
-
* `after_create`
|
72
|
-
* `after_destroy`
|
72
|
+
* `after_create`, `before_create`
|
73
|
+
* `after_destroy`, `before_destroy`
|
73
74
|
|
74
75
|
Every event has a "before" and "after" hook. For the full list, see the
|
75
76
|
Constants section at the bottom of the
|
76
77
|
[ActiveRecord::Callbacks](http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html)
|
77
78
|
documentation.
|
78
79
|
|
79
|
-
The host object has two
|
80
|
+
The host object has two additional callbacks that you can use:
|
80
81
|
|
81
|
-
* `host/after_build` triggers when a host is put into
|
82
|
-
* `host/before_provision` triggers
|
82
|
+
* `host/after_build` triggers when a host is put into build mode
|
83
|
+
* `host/before_provision` triggers when a host completes the OS install
|
83
84
|
|
84
85
|
## Execution of hooks
|
85
86
|
|
@@ -89,16 +90,33 @@ Hooks are executed in the context of the Foreman server, so usually under the
|
|
89
90
|
The first argument is always the event name, enabling scripts to be symlinked
|
90
91
|
into multiple event directories. The second argument is the string
|
91
92
|
representation of the object that was hooked, e.g. the hostname for a host.
|
92
|
-
|
93
|
+
|
94
|
+
~foreman/config/hooks/host/create/50_register_system.sh create foo.example.com
|
95
|
+
|
96
|
+
A JSON representation of the hook object will be passed in on stdin. A utility
|
97
|
+
to read this with jgrep is provided in `examples/hook_functions.sh` and
|
98
|
+
sourcing this utility script will be enough for most users. Otherwise, you
|
99
|
+
may want to ensure stdin is closed.
|
100
|
+
|
101
|
+
echo '{"host"=>{"name"=>"foo.example.com"}}' \
|
102
|
+
| ~foreman/config/hooks/host/create/50_register_system.sh \
|
103
|
+
create foo.example.com
|
93
104
|
|
94
105
|
Every hook within the event directory is executed in alphabetical order. For
|
95
106
|
orchestration hooks, an integer prefix in the hook filename will be used as
|
96
107
|
the priority value, so influences where it's done in relation to DNS, DHCP, VM
|
97
108
|
creation and other tasks.
|
98
109
|
|
99
|
-
|
110
|
+
## Hook failures and rollback
|
111
|
+
|
112
|
+
If a hook fails (non-zero return code), the event is logged. For Rails events,
|
113
|
+
execution of other hooks will continue.
|
114
|
+
|
100
115
|
For orchestration events, a failure will halt the action and rollback will
|
101
|
-
occur.
|
116
|
+
occur. If another orchestration action fails, the hook might be called again
|
117
|
+
to rollback its action - in this case the first argument will change as
|
118
|
+
appropriate, so must be obeyed by the script (e.g. a "create" hook will be
|
119
|
+
called with "destroy" if it has to be rolled back later).
|
102
120
|
|
103
121
|
# Copyright
|
104
122
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Utilities for hook scripts, used with foreman_hooks
|
2
|
+
#
|
3
|
+
# Source this at the start of any bash hook script:
|
4
|
+
#
|
5
|
+
# . hook_functions.sh
|
6
|
+
#
|
7
|
+
# It reads in a JSON representation of the object and then provides a
|
8
|
+
# hook_data wrapper around jgrep to read fields from it, e.g.
|
9
|
+
#
|
10
|
+
# hostname=$(hook_data host.name)
|
11
|
+
# comment=$(hook_data host.comment)
|
12
|
+
|
13
|
+
# update, create, before_destroy etc.
|
14
|
+
HOOK_EVENT=$1
|
15
|
+
# to_s representation of the object, e.g. host's fqdn
|
16
|
+
HOOK_OBJECT=$2
|
17
|
+
|
18
|
+
HOOK_OBJECT_FILE=$(mktemp foreman_hooks.XXXXXXXXXX)
|
19
|
+
trap "rm -f $HOOK_OBJECT_FILE" EXIT
|
20
|
+
cat > $HOOK_OBJECT_FILE
|
21
|
+
|
22
|
+
hook_data() {
|
23
|
+
if [ $# -eq 1 ]; then
|
24
|
+
jgrep -s "$1" < $HOOK_OBJECT_FILE
|
25
|
+
else
|
26
|
+
jgrep "$*" < $HOOK_OBJECT_FILE
|
27
|
+
fi
|
28
|
+
}
|
data/examples/log.sh
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
. $(dirname $0)/hook_functions.sh
|
4
|
+
|
5
|
+
# event name (create, before_destroy etc.)
|
6
|
+
# orchestration hooks must obey this to support rollbacks (create/update/destroy)
|
7
|
+
event=${HOOK_EVENT}
|
8
|
+
|
9
|
+
# to_s representation of the object, e.g. host's fqdn
|
10
|
+
object=${HOOK_OBJECT}
|
11
|
+
|
12
|
+
# Example of using hook_data to query the JSON representation of the object
|
13
|
+
# passed by foreman_hooks. `cat $HOOK_OBJECT_FILE` to see the contents.
|
14
|
+
hostname=$(hook_data host.name)
|
15
|
+
|
16
|
+
echo "$(date): received ${event} on ${object}" >> /tmp/hook.log
|
17
|
+
|
18
|
+
# exit code is important on orchestration tasks
|
19
|
+
exit 0
|
data/foreman_hooks.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "foreman_hooks"
|
3
3
|
|
4
|
-
s.version = "0.
|
5
|
-
s.date = "2013-
|
4
|
+
s.version = "0.3.0"
|
5
|
+
s.date = "2013-04-06"
|
6
6
|
|
7
7
|
s.summary = "Run custom hook scripts on Foreman events"
|
8
8
|
s.description = "Plugin engine for Foreman that enables running custom hook scripts on Foreman events"
|
data/lib/foreman_hooks/engine.rb
CHANGED
@@ -13,10 +13,7 @@ module ForemanHooks
|
|
13
13
|
|
14
14
|
# Find any orchestration related hooks and register in those classes
|
15
15
|
ForemanHooks::HooksObserver.hooks.each do |klass,events|
|
16
|
-
orchestrate =
|
17
|
-
events.keys.each do |event|
|
18
|
-
orchestrate = true if ['create', 'update', 'destroy'].include? event
|
19
|
-
end
|
16
|
+
orchestrate = events.keys.detect { |event| ['create', 'update', 'destroy'].include? event }
|
20
17
|
klass.send(:include, ForemanHooks::OrchestrationHook) if orchestrate
|
21
18
|
end
|
22
19
|
end
|
data/lib/foreman_hooks/util.rb
CHANGED
@@ -63,14 +63,25 @@ module ForemanHooks::Util
|
|
63
63
|
def exec_hook(*args)
|
64
64
|
logger.debug "Running hook: #{args.join(' ')}"
|
65
65
|
success = if defined? Bundler && Bundler.responds_to(:with_clean_env)
|
66
|
-
Bundler.with_clean_env {
|
66
|
+
Bundler.with_clean_env { exec_hook_int(self.to_json, *args) }
|
67
67
|
else
|
68
|
-
|
69
|
-
end
|
68
|
+
exec_hook_int(self.to_json, *args)
|
69
|
+
end.success?
|
70
70
|
|
71
71
|
unless success
|
72
72
|
logger.warn "Hook failure running `#{args.join(' ')}`: #{$?}"
|
73
73
|
end
|
74
74
|
success
|
75
75
|
end
|
76
|
+
|
77
|
+
def exec_hook_int(stdin_data, *args)
|
78
|
+
output = nil
|
79
|
+
IO.popen(args.push(:err=>[:child, :out]), mode='r+') do |io|
|
80
|
+
io.write(stdin_data)
|
81
|
+
io.close_write
|
82
|
+
output = io.read
|
83
|
+
end
|
84
|
+
logger.debug "Hook output: #{output}" if output && !output.empty?
|
85
|
+
$?
|
86
|
+
end
|
76
87
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_hooks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Plugin engine for Foreman that enables running custom hook scripts on
|
15
15
|
Foreman events
|
@@ -28,6 +28,8 @@ files:
|
|
28
28
|
- README.md
|
29
29
|
- Rakefile
|
30
30
|
- TODO
|
31
|
+
- examples/hook_functions.sh
|
32
|
+
- examples/log.sh
|
31
33
|
- foreman_hooks.gemspec
|
32
34
|
- lib/foreman_hooks.rb
|
33
35
|
- lib/foreman_hooks/engine.rb
|