chook 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +7 -4
- data/README.md +289 -264
- data/data/chook.conf.example +82 -3
- data/lib/chook/configuration.rb +8 -1
- data/lib/chook/event/handled_event.rb +2 -2
- data/lib/chook/server.rb +24 -47
- data/lib/chook/server/auth.rb +164 -0
- data/lib/chook/server/public/css/chook.css +4 -0
- data/lib/chook/server/public/js/chook.js +20 -0
- data/lib/chook/server/routes.rb +7 -25
- data/lib/chook/server/routes/handle_webhook_event.rb +1 -1
- data/lib/chook/server/routes/handlers.rb +0 -2
- data/lib/chook/server/routes/home.rb +0 -1
- data/lib/chook/server/routes/log.rb +2 -3
- data/lib/chook/server/routes/login_logout.rb +48 -0
- data/lib/chook/server/views/layout.haml +21 -1
- data/lib/chook/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b631aba4dbfb2011eb6abea5d062777d8ac7c647036feab40a7ba5ba92e2c27c
|
4
|
+
data.tar.gz: 7376d389c06770904df9f37703e5be350dbf9c320e78c7939f6d3f76ce8e6887
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07d7bfbe3723f6ce659b13e8cfcfe38b5d3fcc2e7b6ed2db6360ef087448a7eed36129f642efe58e845a73399e2227cabe8bd62e5ade6a9627068d65060af727
|
7
|
+
data.tar.gz: eb3b1fbf06ba0b915b9914bba71afbd81235bf77a8f5b8eed8f4e57f7c29490753e12eb0247bbe9572bbfa7ed7a79bf5fc96df1664f148246529346e400c1a49
|
data/CHANGES.md
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
# Chook Change Log
|
2
2
|
|
3
|
+
## v 1.1.1, 2018-10-18
|
4
|
+
|
5
|
+
- Admin web page authentication is now separated from Webhooks HTTP Basic Auth.
|
6
|
+
It can be turned off completely, set to a single username/password, or pointed
|
7
|
+
at a Jamf Pro server for admin authentication. See the Admin Interface section
|
8
|
+
of README.md, and/or chook.conf.example for details.
|
9
|
+
|
3
10
|
## v 1.1.0, 2018-10-15
|
4
11
|
|
5
12
|
For details about the new features, please see README.md
|
6
13
|
|
7
14
|
- Now requires 'thin' as the server engine.
|
8
15
|
|
9
|
-
|
10
16
|
- Supports SSL and HTTP Basic Authentication
|
11
17
|
|
12
|
-
|
13
18
|
- Server logging is now a thing, with access to logging from both internal and external handlers
|
14
19
|
|
15
|
-
|
16
20
|
- A simple admin interface is available by pointing your browser at the chook server
|
17
21
|
|
18
|
-
|
19
22
|
- Internal handlers are now stored as anonymous objects rather than Procs, and the handler code block
|
20
23
|
is stored as an instance method on the object. This means that either 'break' or 'return' will work
|
21
24
|
to exit a handler.
|
data/README.md
CHANGED
@@ -1,115 +1,189 @@
|
|
1
|
-
|
2
1
|
# Chook
|
3
2
|
|
4
3
|
Documentation is a work in progress. Please [get in touch](mailto:chook@pixar.com) for assistance. <3
|
5
4
|
|
6
5
|
- [Introduction](#introduction)
|
7
6
|
- [Installing Chook](#installing-chook)
|
8
|
-
- [The Framework](#the-framework)
|
9
|
-
- [Event Handlers](#event-handlers)
|
10
|
-
- [Internal Handlers](#internal-handlers)
|
11
|
-
- [External Handlers](#external-handlers)
|
12
|
-
- [Putting It Together](#putting-it-together)
|
13
|
-
- [Events and Subjects](#events-and-subjects)
|
14
7
|
- [The Server](#the-server)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
8
|
+
- [Server Configuration](#server-configuration)
|
9
|
+
- [SSL](#ssl)
|
10
|
+
- [Logging](#logging)
|
11
|
+
- [Admin Interface](#admin-interface)
|
12
|
+
- [Event Handlers](#event-handlers)
|
13
|
+
- [Internal Handlers - Ruby](#internal-handlers-ruby)
|
14
|
+
- [External Handlers - Any Language](#external-handlers-any-language)
|
15
|
+
- [Logging from handlers](#logging-from-handlers)
|
19
16
|
- [Pointing Jamf Pro at your Chook server](#pointing-jamf-pro-at-your-chook-server)
|
17
|
+
- [The Framework](#the-framework)
|
18
|
+
- [Events and Subjects](#events-and-subjects)
|
19
|
+
- [Putting It Together](#putting-it-together)
|
20
20
|
- [TODOs](#todos)
|
21
21
|
|
22
|
-
|
23
22
|
## Introduction
|
24
23
|
|
25
24
|
Chook is a Ruby module that implements a framework for working with webhook events
|
26
|
-
sent by
|
27
|
-
a management tool for Apple devices
|
25
|
+
sent by a [Jamf Pro](https://www.jamf.com/products/jamf-pro/) Server,
|
26
|
+
a management tool for Apple devices.
|
28
27
|
|
29
|
-
Chook also provides a simple
|
30
|
-
and classes for sending simulated TestEvents to a webhook handling server.
|
28
|
+
Chook also provides a simple [sinatra](http://sinatrarb.com/)-based HTTP server for receiving and processing those Events, and classes for sending simulated TestEvents to any Jamf webhook handling server.
|
31
29
|
|
32
30
|
**You do not need to be a Ruby developer to use Chook!**
|
33
31
|
|
34
|
-
The webhook handling server
|
35
|
-
any language. See
|
32
|
+
The Chook webhook handling server can use "Event Handlers" written in
|
33
|
+
any language. See below for more information.
|
36
34
|
|
37
|
-
Although Chook integrates well with [ruby-jss](http://pixaranimationstudios.github.io/ruby-jss/index.html),
|
38
|
-
it's a separate tool,
|
39
|
-
does become a requirement when using sampling features to generate TestEvents.
|
35
|
+
Although Chook integrates well with [ruby-jss](http://pixaranimationstudios.github.io/ruby-jss/index.html), especially for processing webjook events,
|
36
|
+
it's a separate tool. However, ruby-jss is required when using Jamf-based admin page authentication, or using sampling features to generate TestEvents.
|
40
37
|
|
41
|
-
For more detail about the
|
38
|
+
For more detail about the Jamf Pro Webhooks API and the JSON data it passes, please see
|
42
39
|
[JAMF's developer reference.](http://developer.jamf.com/webhooks)
|
43
40
|
|
44
|
-
**Note:** When
|
41
|
+
**Note:** When enabling webhooks from your Jamf Pro server to be handled by the framework, you must
|
45
42
|
specify JSON in the "Content Type" section. This framework does not support XML and
|
46
43
|
will only generate Test Events in JSON format.
|
47
44
|
|
48
45
|
|
49
46
|
## Installing Chook
|
50
47
|
|
51
|
-
`gem install chook -n /usr/local/bin`
|
48
|
+
As with most Ruby gems: `gem install chook -n /usr/local/bin`
|
52
49
|
|
53
|
-
It will
|
50
|
+
It will automatically install "sinatra" and "thin", and their dependencies.
|
54
51
|
|
55
|
-
|
52
|
+
If you'll be using a Jamf Pro server to authenticate access to Chook's admin web page, or if you'll be generating Chook TestEvents using data sampled from a Jamf Pro server you'll also need to `gem install ruby-jss`
|
56
53
|
|
57
|
-
|
54
|
+
## The Server
|
58
55
|
|
59
|
-
|
56
|
+
Chook comes with a simple HTTP(S) server that uses the Chook framework
|
57
|
+
to handle incoming webhook POST requests from a Jamf Pro server via a single URL `https://my.chookserver.org/handle_webhook_event`.
|
60
58
|
|
61
|
-
|
59
|
+
After Installing chook, just run `/usr/local/bin/chook-server` and then point your Jamf Pro webhooks at: http://my_hostname/handle_webhook_event
|
62
60
|
|
63
|
-
|
64
|
-
|
65
|
-
`Chook::Event.parse_event` method, an instance of the appropriate subclass of
|
66
|
-
`Chook::Event` is returned, for example
|
67
|
-
`Chook::Event::ComputerInventoryCompletedEvent`
|
61
|
+
It will then process incoming webhook POST requests using whatever handlers
|
62
|
+
you have installed.
|
68
63
|
|
69
|
-
|
64
|
+
To automate it on a dedicated Mac, just make a LaunchDaemon plist to run
|
65
|
+
that command and keep it running.
|
70
66
|
|
71
|
-
|
72
|
-
which caused the POST request. This attribute matches the "webhook[:id]"
|
73
|
-
dictionary of the POSTed JSON.
|
67
|
+
### Server Configuration
|
74
68
|
|
75
|
-
|
76
|
-
|
77
|
-
|
69
|
+
The Chook server looks for a config file at `/etc/chook.conf`. If not found, default
|
70
|
+
values are used. Full descriptions of the config values are provided in the sample
|
71
|
+
config file at:
|
72
|
+
/path/to/your/gem/folder/chook-<version>/data/chook.conf.example
|
78
73
|
|
79
|
-
|
80
|
-
representing the "subject" that accompanies the event that triggered the
|
81
|
-
webhook. It comes from the "event" dictionary of the POSTed JSON, and
|
82
|
-
different events come with different subjects attached. For example, the
|
83
|
-
ComputerInventoryCompleted event comes with a "computer" subject containing
|
84
|
-
data about the JSS computer that completed inventory.
|
74
|
+
Each config setting is on a single line like: `key: value`. Blank lines and those starting with # are ignored.
|
85
75
|
|
86
|
-
|
87
|
-
of named attributes about that computer. At the moment, only the Chook Samplers
|
88
|
-
module attempts to look up subject data from the API, but any
|
89
|
-
Handlers written for the event could easily do a similar operation.
|
76
|
+
Here's a summary of possible configuration keys:
|
90
77
|
|
91
|
-
|
92
|
-
|
93
|
-
|
78
|
+
- port: The server port
|
79
|
+
- default = 443 (SSL), or 80 (no SSL)
|
80
|
+
- concurrency: Should events be processed simultaneously? (otherwise, one at a time)
|
81
|
+
- default = true
|
82
|
+
- handler_dir: The directory holding the event handler files to load.
|
83
|
+
- default = /Library/Application Support/Chook
|
84
|
+
- use_ssl: Should the server use SSL (https)
|
85
|
+
- default = false
|
86
|
+
- ssl_cert_path: If SSL is used, the path to the server certificate
|
87
|
+
- no default
|
88
|
+
- ssl_private_key_path: If SSL is used, the path to the certificate key
|
89
|
+
- no default
|
90
|
+
- log_file: The path to the server log file
|
91
|
+
- default = /var/log/chook-server.log
|
92
|
+
- log_level: The severity level for log entries
|
93
|
+
- default = info
|
94
|
+
- logs_to_keep: How many old log files to keep when rotating
|
95
|
+
- default = 10
|
96
|
+
- log_max_megs: How big can a log file get before it's rotated.
|
97
|
+
- default = 10
|
98
|
+
- webhooks_user: The username for Basic Authentication
|
99
|
+
- no default, leave unset for no authentication
|
100
|
+
- webhooks_user_pw: The file path, or command, to get the password for the webhooks_user.
|
101
|
+
- no default
|
102
|
+
- admin_user: the username for access to the Chook admin web page, or 'use_jamf'
|
103
|
+
- no default, leave unset for no authentication
|
104
|
+
- admin_pw: if the admin user is NOT 'use_jamf', The file path, or command, to get the password for the admin_user.
|
105
|
+
- no default
|
106
|
+
- admin_session_expires: How many seconds is an admin login valid?
|
107
|
+
- default: 86400 (24 hours)
|
108
|
+
- jamf_server: if admin_user is 'use_jamf', the Jamf Pro server to use for admin authentication
|
109
|
+
- default: none, but /etc/ruby-jss.conf is honored.
|
110
|
+
- jamf_port: if admin_user is 'use_jamf', the Jamf Pro server port to use for admin authentication
|
111
|
+
- default: none, but /etc/ruby-jss.conf is honored.
|
112
|
+
- jamf_use_ssl: if admin_user is 'use_jamf', use SSL to talk to the Jamf Pro server? true/false
|
113
|
+
- default: none, but /etc/ruby-jss.conf is honored.
|
114
|
+
- jamf_verify_cert: if admin_user is 'use_jamf', verify the SSL certificate from the Jamf Pro server? true/false
|
115
|
+
- default: none, but /etc/ruby-jss.conf is honored.
|
116
|
+
-
|
117
|
+
See the sample config file for details about all of these settings.
|
94
118
|
|
95
|
-
|
96
|
-
request.
|
119
|
+
### SSL
|
97
120
|
|
98
|
-
|
99
|
-
|
121
|
+
It is recommended to use SSL (https) if possible for security, although its beyond the scope
|
122
|
+
of this document to go into a lot of detail about SSL and certificates. That said, here
|
123
|
+
are some pointers:
|
124
|
+
|
125
|
+
- The certificate and key files should be in .pem format
|
126
|
+
|
127
|
+
- Make sure you use a certificate that can be verified by the JSS.
|
128
|
+
- This might involved adding a CA to the JSS's Java Keystore.
|
129
|
+
|
130
|
+
- If running on macOS, the 'thin' webserver and it's underlying 'eventmachine' gem may not
|
131
|
+
like the OS's openssl replacement 'libressl'.
|
132
|
+
- One solution is to use [homebrew](https://brew.sh/) to install openssl and then
|
133
|
+
install eventmachine using that openssl, something like this:
|
134
|
+
|
135
|
+
`brew install openssl ; brew link openssl --force ; gem install eventmachine -- --with-ssl-dir=/usr/local/`
|
136
|
+
|
137
|
+
### Logging
|
138
|
+
|
139
|
+
The Chook server logs activity into the file defined in the `log_file` config setting,
|
140
|
+
`/var/log/chook-server.log` by default.
|
141
|
+
|
142
|
+
It uses a standard ruby [Logger](http://ruby-doc.org/stdlib-2.3.3/libdoc/logger/rdoc/index.html)
|
143
|
+
instance, which provides 5 severity levels: fatal (lowest), error, warn, info, and debug (highest).
|
144
|
+
|
145
|
+
The `log_level` config setting defines the level when the server starts up, and log
|
146
|
+
messages of that level or lower will be written to the log.
|
147
|
+
|
148
|
+
The log can automatically rotate when it reaches a certain size, as specified by the log_max_megs configuration setting, and the logs_to_keep settings tells chook how many it should keep in total - older log files will be deleted automatically.
|
149
|
+
|
150
|
+
If you want to manage the log rotation on your own, set logs_to_keep to zero, or leave it unset,
|
151
|
+
and the log will never automatically rotate.
|
152
|
+
|
153
|
+
See below for how to write to the Chook log from within a handler
|
154
|
+
|
155
|
+
### Admin Interface
|
100
156
|
|
157
|
+
If you point your web browser at your Chook server `http(s)://your.chookserver.org/` , you'll see a simple admin interface.
|
158
|
+
|
159
|
+
If an `admin_user` is set in the configuration, you'll need to provide that name and password, or if `admin_user` is `use_jamf` you'll need to provide the username and password of any Jamf Pro user on
|
160
|
+
the server indicated in the config.
|
161
|
+
|
162
|
+
The first section provides a live-stream of the server log file, and provides a way to
|
163
|
+
change the server's log level on the fly. Note that this change affects the server itself
|
164
|
+
not just the view in your browser. If you'd like to stop the stream temporarily (e.g. to
|
165
|
+
scroll back, or select some text), just pause and unpause with the checkbox.
|
166
|
+
|
167
|
+
The second section lets you see which handlers are currently loaded, and if they are
|
168
|
+
internal or external. The (view) button shows the contents of the handler file.
|
169
|
+
|
170
|
+
There's also a button to reload the handlers from the handler directory without restarting the server - useful when you add, delete, or modify them.
|
171
|
+
|
172
|
+
The final section just shows your current /etc/chook.conf file, or if there is none,
|
173
|
+
the sample config file is shown, since it shows the default values.
|
174
|
+
|
175
|
+
The admin page cannot be used to edit or upload handlers or change the config. For security
|
176
|
+
reasons, you must do that on the server machine itself though normal administrative methods.
|
101
177
|
|
102
178
|
### Event Handlers
|
103
179
|
|
104
|
-
A handler is a file containing code to run when a webhook event
|
180
|
+
A handler is a file containing code to run when a webhook event is received. These
|
105
181
|
files are located in a specified directory, `/Library/Application
|
106
|
-
Support/Chook/` by default, and are loaded
|
107
|
-
|
108
|
-
event can have as many handlers as desired, all will be executed when the event's
|
109
|
-
`handle` method is called.
|
182
|
+
Support/Chook/` by default, and are loaded when the server starts, or the (reload)
|
183
|
+
button is clicked on the admin web page.
|
110
184
|
|
111
185
|
Handler files must begin with the name of the event they handle, e.g.
|
112
|
-
ComputerAdded
|
186
|
+
`ComputerAdded`, followed by: nothing, a dot, a dash, or an underscore. Handler
|
113
187
|
filenames are case-insensitive.
|
114
188
|
|
115
189
|
All of these file names are valid handlers for ComputerAdded events:
|
@@ -119,18 +193,22 @@ All of these file names are valid handlers for ComputerAdded events:
|
|
119
193
|
- COMPUTERAdded_notify_team
|
120
194
|
- Computeradded-update-ldap
|
121
195
|
|
196
|
+
Each kind of event can have as many handlers as desired, all will be executed when webhook event
|
197
|
+
is recieved. If all four of the above files existed in the handler directory, every
|
198
|
+
ComputerAdded event would run all four of them.
|
199
|
+
|
122
200
|
There are two kinds of handlers, distinguished by their file-executability.
|
123
201
|
|
124
|
-
#### Internal Handlers
|
202
|
+
#### Internal Handlers - Ruby
|
125
203
|
|
126
204
|
These handlers are _non-executable_ files containing Ruby code. The code is
|
127
|
-
loaded at runtime and executed
|
128
|
-
|
205
|
+
loaded at runtime and executed as a thread in the Chook server process when
|
206
|
+
a matching event is received.
|
129
207
|
|
130
208
|
Internal handlers must be defined as a [ruby code block](http://rubylearning.com/satishtalim/ruby_blocks.html) passed to the
|
131
209
|
`Chook.event_handler` method. The block must take one parameter, the
|
132
210
|
Chook::Event subclass instance being handled. Here's a simple example of
|
133
|
-
a handler for a
|
211
|
+
a handler for a ComputerAdded webhook event.
|
134
212
|
|
135
213
|
```ruby
|
136
214
|
Chook.event_handler do |event|
|
@@ -140,18 +218,19 @@ Chook.event_handler do |event|
|
|
140
218
|
end
|
141
219
|
```
|
142
220
|
|
143
|
-
The code block takes one parameter
|
144
|
-
and in this example stores it in the variable "event."
|
221
|
+
The code block, between `do` and `end`, takes one parameter which will be a Chook::HandledEvents::ComputerAddedEvent object. In this example the object is stored in the variable "event" and used inside the block.
|
145
222
|
|
146
|
-
|
223
|
+
This handler then extracts the "deviceName" and "realName" values from the subject
|
147
224
|
contained in the event, and uses them to log a message in the chook log.
|
148
225
|
|
226
|
+
The subject of an event is the thing that the event affected. In the case of ComputerAdded events, the subject is a Computer. In Chook, it's an object of the class Chook::HandledSubjects::ComputerAdded.
|
227
|
+
|
149
228
|
**NameSpacing**
|
150
229
|
|
151
230
|
Be careful when writing internal handlers - they all run in the same Ruby process!
|
152
231
|
|
153
232
|
Not only do they have to be thread-safe, but be wary of cluttering the default
|
154
|
-
namespace with constants that might overwrite each other.
|
233
|
+
namespace with constants or methods that might overwrite each other.
|
155
234
|
|
156
235
|
A good, very ruby-like, practice is to put the guts of your code into a Module or a Class
|
157
236
|
and use that from inside the handler definition. Here's an example using a Class:
|
@@ -165,18 +244,20 @@ class ComputerAdder
|
|
165
244
|
|
166
245
|
def initialize(event)
|
167
246
|
@event = event
|
168
|
-
@
|
247
|
+
@comp_name = @event.subject.deviceName
|
248
|
+
@user_name = @event.subject.realName
|
169
249
|
end
|
170
250
|
|
171
251
|
def run
|
172
|
-
@event.logger.info "Adder Starting for computer #{@
|
252
|
+
@event.logger.info "Adder Starting for computer #{@comp_name}"
|
173
253
|
notify_admins
|
174
|
-
@event.logger.info "Adder Finished for computer #{@
|
254
|
+
@event.logger.info "Adder Finished for computer #{@comp_name}"
|
175
255
|
end
|
176
256
|
|
177
257
|
def notify_admins
|
178
|
-
|
179
|
-
|
258
|
+
msg = "Computer '#{@comp_name}' was just enrolled for user #{@user_name}."
|
259
|
+
SlackEm.send message: msg, channel: SLACK_CHANNEL
|
260
|
+
@event.logger.debug "Admins notified about computer #{@comp_name}"
|
180
261
|
end
|
181
262
|
|
182
263
|
end
|
@@ -187,7 +268,7 @@ end
|
|
187
268
|
```
|
188
269
|
|
189
270
|
Here, the handler file defines a 'ComputerAdder' class that does all the work.
|
190
|
-
The handler block merely creates an instance of ComputerAdder
|
271
|
+
The handler block merely creates an instance of ComputerAdder, passing it the event,
|
191
272
|
and tells the ComputerAdder instance to run. The instance's run method can
|
192
273
|
then perform any steps desired.
|
193
274
|
|
@@ -199,19 +280,21 @@ use ComputerAdder::SLACK_CHANNEL.
|
|
199
280
|
This way, similar handlers can have their own SLACK_CHANNEL constants and
|
200
281
|
there won't be any interference.
|
201
282
|
|
283
|
+
For more details about event and subject classes, see [The Framework](#the-framework)
|
284
|
+
|
202
285
|
NOTE: Internal handlers **must not** be executable files. Executability is how the
|
203
286
|
framework determines if a handler is internal or external.
|
204
287
|
|
205
|
-
#### External Handlers
|
288
|
+
#### External Handlers - Any Language
|
206
289
|
|
207
290
|
External handlers are _executable_ files that are executed when called by an
|
208
291
|
event. They can be written in any language, but they must accept raw JSON on
|
209
292
|
their standard input. It's up to them to parse that JSON and react to it as
|
210
|
-
desired. In this case the Chook
|
211
|
-
the Posted JSON to the executable program.
|
293
|
+
desired. In this case the Chook server is merely a conduit for passing
|
294
|
+
the Posted JSON from the Jamf Pro server to the executable program.
|
212
295
|
|
213
296
|
Here's a simple example using bash and [jq](https://stedolan.github.io/jq/) to
|
214
|
-
do
|
297
|
+
do something similar to the first ruby example above:
|
215
298
|
|
216
299
|
```bash
|
217
300
|
#!/bin/bash
|
@@ -228,31 +311,121 @@ framework determines if a handler is internal or external.
|
|
228
311
|
See `data/sample_handlers/RestAPIOperation-executable`
|
229
312
|
for a more detailed bash example that handles RestAPIOperation events.
|
230
313
|
|
231
|
-
|
314
|
+
See the [Jamf Developer Site](https://developer.jamf.com/webhooks) for details about the JSON contents of webhook events.
|
232
315
|
|
233
|
-
|
234
|
-
|
316
|
+
### Logging from handlers
|
317
|
+
|
318
|
+
**Internal handlers**
|
319
|
+
|
320
|
+
To write to the Chook log file from within an internal handler, use the `#logger` method of the `event` object
|
321
|
+
inside the handler block, like so:
|
235
322
|
|
236
323
|
```ruby
|
237
|
-
|
238
|
-
|
324
|
+
Chook.event_handler do |event|
|
325
|
+
event.logger.debug "This line appears in the log if the level is debug"
|
326
|
+
event.logger.info "This line appears in the log if the level is info or debug"
|
327
|
+
event.logger.error "This line appears in the log if the level is error, warn, info, or debug"
|
328
|
+
end
|
329
|
+
```
|
239
330
|
|
240
|
-
|
241
|
-
|
242
|
-
|
331
|
+
If you want to log a Ruby exception with its backtrace, you can pass the entire
|
332
|
+
exception to the event logger's 'log_exception' method like this:
|
333
|
+
```ruby
|
334
|
+
begin
|
335
|
+
# something horribly wrong happens here
|
336
|
+
rescue => execption
|
337
|
+
event.logger.log_exception exception
|
338
|
+
end
|
339
|
+
```
|
243
340
|
|
244
|
-
|
245
|
-
|
341
|
+
Log entries written through event objects are preceded with `Event xxxxxxxxx:` where xxxxxxxxx is
|
342
|
+
an internal ID number for the specific even that wrote the entry.
|
343
|
+
|
344
|
+
**External handlers**
|
345
|
+
|
346
|
+
External Handlers can use a URL to make log entries by POSTing to `https://my.chookserver/log`
|
347
|
+
|
348
|
+
The request body must be a JSON object wth 2 keys 'level' and 'message' where both values are strings.
|
349
|
+
|
350
|
+
The 'level' must be one of the known log levels: fatal, error, warn, info, or debug. The message is a single line of text to be added to the log.
|
351
|
+
|
352
|
+
If your chook server is using Basic Authentication for webhook events, it must be provided for logging also.
|
353
|
+
|
354
|
+
Here's an example with curl, split to multi-line for clarity:
|
246
355
|
|
247
|
-
|
248
|
-
|
249
|
-
|
356
|
+
```
|
357
|
+
curl -u 'auth-user:auth-pw' \
|
358
|
+
-H 'Content-Type: application/json' \
|
359
|
+
-X POST \
|
360
|
+
--data '{"level":"debug", "message":"It Worked"}' \
|
361
|
+
https://chookserver.myorg.org/log
|
250
362
|
```
|
251
363
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
364
|
+
Messages logged via this url show up in the log preceded by `ExternalEntry: `
|
365
|
+
|
366
|
+
Any info needed to indentify a log entry with a specific event must be included in
|
367
|
+
your log message.
|
368
|
+
|
369
|
+
### Pointing Jamf Pro at your Chook server
|
370
|
+
|
371
|
+
Once your server is up and running, and you have a handler or two in place, you can create webhooks in your Jamf Pro interface:
|
372
|
+
|
373
|
+
1. Navigate to Settings => Global Management => Webhooks
|
374
|
+
2. Click "New"
|
375
|
+
3. Give your webhook a display name
|
376
|
+
4. Enter the URL for your Chook server, ending with 'handle_webhook_event', e.g:
|
377
|
+
- `http://my.chookserver.edu/handle_webhook_event`
|
378
|
+
- `https://my.chookserver.edu:8443/handle_webhook_event`
|
379
|
+
5. If you use Basic Authentication, enter the name and password
|
380
|
+
6. The default timeouts should be OK, but raise them a bit if you're experiencing errors.
|
381
|
+
7. Set the content type to JSON
|
382
|
+
8. Select the event that triggers the webook
|
383
|
+
9. Click "Enabled" at the top.
|
384
|
+
10. Click "Save"
|
385
|
+
|
386
|
+
Watch the Chook log, with the level at info or debug, to see events come in.
|
387
|
+
|
388
|
+
## The Framework
|
389
|
+
|
390
|
+
The Chook framework abstracts webhook Events and their components as Ruby
|
391
|
+
classes. When the JSON payload of a JSS webhook POST request is passed into the
|
392
|
+
`Chook::Event.parse_event` method, an instance of the appropriate subclass of
|
393
|
+
`Chook::Event` is returned, for example
|
394
|
+
`Chook::Event::ComputerInventoryCompletedEvent`
|
395
|
+
|
396
|
+
Each Event instance contains these important attributes:
|
397
|
+
|
398
|
+
* **webhook_id:** A read-only instance of the webhook ID stored in the JSS
|
399
|
+
which caused the POST request. This attribute matches the "webhook[:id]"
|
400
|
+
dictionary of the POSTed JSON.
|
401
|
+
|
402
|
+
* **webhook_name:** A read-only instance of the webhook name stored in the JSS
|
403
|
+
which caused the POST request. This attribute matches the "webhook[:name]"
|
404
|
+
dictionary of the POSTed JSON.
|
405
|
+
|
406
|
+
* **subject:** A read-only instance of a `Chook::Subject::<Class>`
|
407
|
+
representing the "subject" that accompanies the event that triggered the
|
408
|
+
webhook. It comes from the "event" dictionary of the POSTed JSON, and
|
409
|
+
different events come with different subjects attached. For example, the
|
410
|
+
ComputerInventoryCompleted event comes with a "computer" subject containing
|
411
|
+
data about the JSS computer that completed inventory.
|
412
|
+
|
413
|
+
This is not full `JSS::Computer` object from the REST API, but rather a group
|
414
|
+
of named attributes about that computer. At the moment, only the Chook Samplers
|
415
|
+
module attempts to look up subject data from the API, but any
|
416
|
+
Handlers written for the event could easily do a similar operation.
|
417
|
+
|
418
|
+
* **event_json:** The JSON content from the POST request, parsed into
|
419
|
+
a Ruby hash with symbolized keys (meaning the JSON key "deviceName" becomes
|
420
|
+
the symbol :deviceName).
|
421
|
+
|
422
|
+
* **raw_json:** A String containing the raw JSON from the POST
|
423
|
+
request.
|
424
|
+
|
425
|
+
* **handlers:** An Array of custom plug-ins for working with the
|
426
|
+
event. See _Event Handlers_, below.
|
427
|
+
|
428
|
+
|
256
429
|
|
257
430
|
### Events and Subjects
|
258
431
|
|
@@ -302,179 +475,31 @@ the `Chook::Subjects` module.
|
|
302
475
|
| Chook::TestEvents::MobileDeviceUnenrolledEvent | Chook::TestSubjects::MobileDevice |
|
303
476
|
| Chook::TestEvents::PatchSoftwareTitleUpdateEvent | Chook::TestSubjects::PatchSoftwareTitleUpdate |
|
304
477
|
|
305
|
-
|
306
|
-
|
307
|
-
Chook comes with a simple HTTP(S) server that uses the Chook framework
|
308
|
-
to handle all incoming webhook POST requests from the JSS via a single URL.
|
309
|
-
|
310
|
-
To use it you'll need the [sinatra](http://www.sinatrarb.com/) web framework
|
311
|
-
and the [thin](http://code.macournoyer.com/thin/) web server.
|
312
|
-
Both will be installed automatically when you install chook as mentioned below.
|
313
|
-
|
314
|
-
After that, just run the `chook-server` command located in the bin directory
|
315
|
-
for chook and then point your webhooks at: http://my_hostname/handle_webhook_event
|
316
|
-
|
317
|
-
It will then process all incoming webhook POST requests using whatever handlers
|
318
|
-
you have installed.
|
319
|
-
|
320
|
-
To automate it on a dedicated machine, just make a LaunchDaemon plist to run
|
321
|
-
that command and keep it running.
|
322
|
-
|
323
|
-
### Server Configuration
|
324
|
-
|
325
|
-
The Chook server looks for a config file at `/etc/chook.conf`. If not found, default
|
326
|
-
values are used. Full descriptions of the config values are provided in the sample
|
327
|
-
config file at:
|
328
|
-
/path/to/your/gem/folder/chook-<version>/data/chook.conf.example
|
329
|
-
|
330
|
-
Each config setting is on a single line thus: `key: value`. Blank lines and those starting with # are ignored.
|
331
|
-
|
332
|
-
Here's a summary:
|
333
|
-
|
334
|
-
- port: The server port
|
335
|
-
- default = 80 or 443
|
336
|
-
- concurrency: Should events be processed simultaneously, or one-at-a time
|
337
|
-
- default = true
|
338
|
-
- handler_dir: The directory holding the andlers to load.
|
339
|
-
- default = /Library/Application Support/Chook
|
340
|
-
- use_ssl: Should the server use SSL (https)
|
341
|
-
- default = false
|
342
|
-
- ssl_cert_path: If SSL is used, the path to the server certificate
|
343
|
-
- no default
|
344
|
-
- ssl_private_key_path: If SSL is used, the path to the certificate key
|
345
|
-
- no default
|
346
|
-
- log_file: The path to the server log file
|
347
|
-
- default = /var/log/chook-server.log
|
348
|
-
- log_level: The severity level for log entries
|
349
|
-
- default = info
|
350
|
-
- logs_to_keep: How many old log files to keep when rotating
|
351
|
-
- default = 10
|
352
|
-
- log_max_megs: How big can a log file get before it's rotated.
|
353
|
-
- default = 10
|
354
|
-
- webhooks_user: The username for Basic Authentication
|
355
|
-
- no default, leave unset for no Authentication
|
356
|
-
- webhooks_user_pw: The file path, or command, to get the password for the webhooks_user.
|
357
|
-
- no default.
|
358
|
-
|
359
|
-
See the sample config file for details about all of these settings.
|
360
|
-
|
361
|
-
### SSL
|
362
|
-
|
363
|
-
It is recommended to use SSL (https) if possible for security, although its beyond the scope
|
364
|
-
of this document to go into a lot of detail about SSL and certificates. That said, here
|
365
|
-
are some pointers:
|
366
|
-
|
367
|
-
- The certificate and key files should be in .pem format
|
368
|
-
|
369
|
-
- Make sure you use a certificate that can be verified by the JSS.
|
370
|
-
- This might involved adding a CA to the JSS's Java Keystore.
|
371
|
-
|
372
|
-
- If running on macOS, the 'thin' webserver and it's underlying 'eventmachine' gem may not
|
373
|
-
like the OS's openssl replacement 'libressl'.
|
374
|
-
- One solution is to use [homebrew](https://brew.sh/) to install openssl and then
|
375
|
-
install eventmachine using that openssl, something like this:
|
376
|
-
|
377
|
-
`brew install openssl ; brew link openssl --force ; gem install eventmachine -- --with-ssl-dir=/usr/local/`
|
378
|
-
|
379
|
-
### Logging
|
380
|
-
|
381
|
-
The Chook server logs activity into the file defined in the `log_file` config setting,
|
382
|
-
`/var/log/chook-server.log` by default.
|
383
|
-
|
384
|
-
It uses a standard ruby [Logger](http://ruby-doc.org/stdlib-2.3.3/libdoc/logger/rdoc/index.html)
|
385
|
-
instance, which provides 5 severity levels: fatal (lowest), error, warn, info, and debug (highest).
|
386
|
-
|
387
|
-
The `log_level` config setting defines the level when the server starts up, and log
|
388
|
-
messages of that level or lower will be written to the log.
|
389
|
-
|
390
|
-
The logger is generally available via `Chook.logger`. If you want to log an exeption with its backtrace, you can use `Chook.log_exception exception` to get the Exception class, message, and backtrace in the log.
|
391
|
-
|
392
|
-
However, for logging from inside handlers, read on...
|
393
|
-
|
394
|
-
#### Logging from handlers
|
395
|
-
|
396
|
-
**Internal handlers**
|
478
|
+
### Putting It Together
|
397
479
|
|
398
|
-
|
399
|
-
|
480
|
+
Here is a commented sample of ruby code that uses the framework to process a
|
481
|
+
ComputerAdded Event:
|
400
482
|
|
401
483
|
```ruby
|
402
|
-
|
403
|
-
|
404
|
-
event.logger.info "This line appears in the log if the level is info or debug"
|
405
|
-
event.logger.error "This line appears in the log if the level is error, warn, info, or debug"
|
406
|
-
end
|
407
|
-
```
|
408
|
-
|
409
|
-
If you want to log an exeption with its backtrace, you can pass the entire exception to the
|
410
|
-
event loggers 'log_exception' method: `event.logger.log_exception exception`
|
411
|
-
|
412
|
-
Log entries written through event objects are preceded with 'Event *event_id*' where *event_id* is
|
413
|
-
an internal ID number for the specific even that wrote the entry.
|
414
|
-
|
415
|
-
|
416
|
-
**External handlers**
|
417
|
-
|
418
|
-
External Handlers can use a URL to make log entries by POSTing to `https://my.chookserver/log`
|
419
|
-
|
420
|
-
The request body must be a JSON object wth 2 keys 'level' and 'message' where both values are strings.
|
421
|
-
The 'level' must be one of the levels mentioned above, and the message is a single line of
|
422
|
-
text.
|
484
|
+
# load the framework
|
485
|
+
require 'chook'
|
423
486
|
|
424
|
-
|
487
|
+
# The framework comes with sample JSON files for each Event type.
|
488
|
+
# In reality, a webserver would extract this from the data POSTed from the JSS
|
489
|
+
posted_json = Chook.sample_jsons[:ComputerAdded]
|
425
490
|
|
426
|
-
|
491
|
+
# Create Chook::HandledEvents::ComputerAddedEvent instance for the event
|
492
|
+
event = Chook::HandledEvent.parse_event posted_json
|
427
493
|
|
494
|
+
# Call the events #handle method, which will execute any ComputerAdded
|
495
|
+
# handlers that were in the Handler directory when the framework was loaded.
|
496
|
+
event.handle
|
428
497
|
```
|
429
|
-
curl -H "Content-Type: application/json" \
|
430
|
-
-X POST \
|
431
|
-
--data '{"level":"debug", "message":"It Worked"}' \
|
432
|
-
https://user:passwd@chookserver.myorg.org/log
|
433
|
-
```
|
434
|
-
|
435
|
-
Messages logged via this url show up in the log preceded by 'ExternalEntry: '
|
436
498
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
If you point your web browser at your Chook server, you'll see a simple admin interface.
|
443
|
-
If your server uses Basic Authentication, you'll need to provide the name and password.
|
444
|
-
|
445
|
-
The first section provides a live-stream of the server log file, and provides a way to
|
446
|
-
change the server's log level on the fly. Note that this change affect the server itself
|
447
|
-
not just the view in your browser. If you'd like to stop the stream temporarily (e.g. to
|
448
|
-
select and copy some text from it), just pause and unpause with the checkbox.
|
449
|
-
|
450
|
-
The second section lets you see which handlers are currently loaded, and if they are
|
451
|
-
internal or external. There's also a button to reload the handlers from the handler
|
452
|
-
directory without restarting the server - useful when you add, delete, or modify them.
|
453
|
-
|
454
|
-
The final section just shows your current /etc/chook.conf file, or if there is none,
|
455
|
-
the sample config file is shown, since it shows the default values.
|
456
|
-
|
457
|
-
The admin page cannot be used to edit or upload handlers or change the config. For security
|
458
|
-
reasons, you must do that on the server itself though normal administrative methods.
|
459
|
-
|
460
|
-
### Pointing Jamf Pro at your Chook server
|
461
|
-
|
462
|
-
Once your server is up and running, you can create webhooks in your Jamf Pro interface.
|
463
|
-
|
464
|
-
1. Navigate to Settings => Global Management => Webhooks
|
465
|
-
2. Click "New"
|
466
|
-
3. Give your webhook a display name
|
467
|
-
4. Enter the URL for your Chook server, ending with 'handle_webhook_event', e.g:
|
468
|
-
- `http://my.chookserver.edu/handle_webhook_event`
|
469
|
-
- `https://my.chookserver.edu:8443/handle_webhook_event`
|
470
|
-
5. If you use Basic Authentication, enter the name and password
|
471
|
-
6. The default timeouts should be OK, but raise them a bit if you're experiencing errors.
|
472
|
-
7. Set the content type to JSON
|
473
|
-
8. Select the event that triggers the webook
|
474
|
-
9. Click "Enabled" at the top.
|
475
|
-
10. Click "Save"
|
476
|
-
|
477
|
-
Watch the Chook log, with the level at info or debug, to see events come in.
|
499
|
+
Of course, you can use the framework without using the built-in #handle method,
|
500
|
+
and if you don't have any handlers in the directory, it won't do anything
|
501
|
+
anyway. Instead you are welcome to use the objects as desired in your own
|
502
|
+
Ruby code.
|
478
503
|
|
479
504
|
## TODOs
|
480
505
|
|