foreman_hooks 0.2.0 → 0.3.0
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.
- 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
|