chook 1.1.0 → 1.1.1
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.
- 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
|
|