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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05defee2dbf9d0d71b7657d491ac8eebf3c87529d1de1077365a3a2e82cc48fe
4
- data.tar.gz: 845d410b10290129a233915600cf57ca7c89a855b2d504cb5593da885e5eef8c
3
+ metadata.gz: b631aba4dbfb2011eb6abea5d062777d8ac7c647036feab40a7ba5ba92e2c27c
4
+ data.tar.gz: 7376d389c06770904df9f37703e5be350dbf9c320e78c7939f6d3f76ce8e6887
5
5
  SHA512:
6
- metadata.gz: 153586d027c5c81d7ec5d0f0678d0c520879db7cef84cf3454134a4f7439601faa12463a3d227e7dd1ce6b561c18d4c95be781f39b2d0d787be742d5ea0b44fa
7
- data.tar.gz: 10e36a024704ab54f38bfbfeec7f91da08a294c9a3d0c1b3c103d0aa924719045197a4f62e49ef4e4add8397004fc8578186d3c50ec03d53501839ac716384a5
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
- - [Server Configuration](#server-configuration)
16
- - [SSL](#ssl)
17
- - [Logging](#logging)
18
- - [Admin Interface](#admin-interface)
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 the JSS, the core of [Jamf Pro](https://www.jamf.com/products/jamf-pro/),
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, sinatra-based HTTP server for handling those Events,
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 that comes with Chook can use "Event Handlers" written in
35
- any language. See _Event Handlers_ and _The Server_ below for more information.
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, and the two projects aren't dependent. However, ruby-jss
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 JSS webhooks API and the JSON data it passes, please see
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 creating webhooks from your JSS to be handled by the framework, you must
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 also install "sinatra" and "thin", and their dependencies.
50
+ It will automatically install "sinatra" and "thin", and their dependencies.
54
51
 
55
- Then fire up `irb` and `require 'chook'` to start playing around.
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
- OR
54
+ ## The Server
58
55
 
59
- run `/usr/local/bin/chook-server` and point some JSS webhooks at `http://my.computer.org/handle_webhook_event`
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
- ## The Framework
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
- The Chook framework abstracts webhook Events and their components as Ruby
64
- classes. When the JSON payload of a JSS webhook POST request is passed into the
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
- Each Event instance contains these important attributes:
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
- * **webhook_id:** A read-only instance of the webhook ID stored in the JSS
72
- which caused the POST request. This attribute matches the "webhook[:id]"
73
- dictionary of the POSTed JSON.
67
+ ### Server Configuration
74
68
 
75
- * **webhook_name:** A read-only instance of the webhook name stored in the JSS
76
- which caused the POST request. This attribute matches the "webhook[:name]"
77
- dictionary of the POSTed JSON.
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
- * **subject:** A read-only instance of a `Chook::Subject::<Class>`
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
- This is not full `JSS::Computer` object from the REST API, but rather a group
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
- * **event_json:** The JSON content from the POST request, parsed into
92
- a Ruby hash with symbolized keys (meaning the JSON key "deviceName" becomes
93
- the symbol :deviceName).
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
- * **raw_json:** A String containing the raw JSON from the POST
96
- request.
119
+ ### SSL
97
120
 
98
- * **handlers:** An Array of custom plug-ins for working with the
99
- event. See _Event Handlers_, below.
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 occurs. These
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 at runtime. It's up to the Jamf
107
- administrator to create these handlers to perform desired tasks. Each class of
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, followed by: nothing, a dot, a dash, or an underscore. Handler
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 in the context of the Chook Framework when
128
- called by an event.
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 Chook::ComputerAddedEvent
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, which will be a Chook::ComputerAddedEvent instance,
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
- It then extracts the "deviceName" and "realName" values from the subject
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
- @cname = @event.subject.deviceName
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 #{@cname}"
252
+ @event.logger.info "Adder Starting for computer #{@comp_name}"
173
253
  notify_admins
174
- @event.logger.info "Adder Finished for computer #{@cname}"
254
+ @event.logger.info "Adder Finished for computer #{@comp_name}"
175
255
  end
176
256
 
177
257
  def notify_admins
178
- SlackEm.send message: "Computer '#{@cname}' was just added to the JSS for user #{@event.subject.realName}.", channel: SLACK_CHANNEL
179
- @event.logger.debug "Admins notified about computer #{@cname}"
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 with the event,
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 framework is merely a conduit for passing
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 the same as the first ruby example above:
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
- ### Putting It Together
314
+ See the [Jamf Developer Site](https://developer.jamf.com/webhooks) for details about the JSON contents of webhook events.
232
315
 
233
- Here is a commented sample of ruby code that uses the framework to process a
234
- ComputerAdded Event:
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
- # load the framework
238
- require 'chook'
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
- # The framework comes with sample JSON files for each Event type.
241
- # In reality, a webserver would extract this from the data POSTed from the JSS
242
- posted_json = Chook.sample_jsons[:ComputerAdded]
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
- # Create Chook::HandledEvents::ComputerAddedEvent instance for the event
245
- event = Chook::HandledEvent.parse_event posted_json
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
- # Call the events #handle method, which will execute any ComputerAdded
248
- # handlers that were in the Handler directory when the framework was loaded.
249
- event.handle
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
- Of course, you can use the framework without using the built-in #handle method,
253
- and if you don't have any handlers in the directory, it won't do anything
254
- anyway. Instead you are welcome to use the objects as desired in your own
255
- Ruby code.
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
- ## The Server
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
- To write to the log file from within an internal handler, use the `#logger` method of the `event` object
399
- inside the handler block, like so:
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
- Chook.event_handler do |event|
403
- event.logger.debug "This line appears in the log if the level is debug"
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
- If your chook server is using Basic Authentication, it must be provided.
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
- Here's an example with curl, split to multi-line for clarity:
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
- Any info needed to connect a log entry to a specific event must be included in
438
- your log message.
439
-
440
- ### Admin Interface
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