Jackalope: a slacky Jamf Pro notification plugin

_images/jackalope.png

Welcome to Jackalope’s documentation (still a work-in-progress)!

Create the Slack App for Your Team

Before deploying the app on a server, you will need to create it for your Slack team at https://api.slack.com/apps .

_images/slack_create_app_1.png

You will need to enable Incoming Webhooks...

_images/slack_create_app_2.png

...and set a Redirect URL that points to:

https://jackalope.mydomain.org/install
_images/slack_create_app_3.png

With those two steps complete you will be able to copy the following values for use with the deployed application environment:

  • Basic Information/App Credentials/Client ID
  • Basic Information/App Credentials/Client Secret
_images/slack_create_app_4.png
  • Manage Distribution/Share Your App with Your Team/Shareable URL
_images/slack_create_app_5.png

Note

You will need to set these into environment variables details in the deployment documentation. See Environment Variables.

Deploying the Slack App

Jackalope is written in Python using the Flask framework. This gives a wide variety of options in deploying the application in your environment from installing onto a standalone server, a cloud instance, or within a container.

Note

If you are testing, skip to Run from application.py below.

You will need the following components to deploy the application:

  • A web server or load balancer to serve traffic over TLS
  • A WSGI server (uWSGI or Gunicorn for example) to run the application code
  • A MySQL server

The application will only connect to a MySQL server if all of the required Environment Variables have been provided. If not, a local SQLite database will be created within the application directory.

In a cloud instance deployments you can use services such as:

Run from application.py

This script creates the root application object from the jackalope.create_app() application factory function. If the script has been called from the command line an instance will be launched in a local development server.

$ python application.py

The development server will be accessible at:

http://localhost:5000

If the application is being deployed with a WSGI framework, configure the WSGI server to point to the application.py file and the application object.

Alternatively, the WSGI framework can instantiate and customize an application object using jackalope.create_app().

Testing with ngrok

For testing, you can use the ngrok secure tunneling service to expose the application to the internet and access it using both HTTP and HTTPS.

Note

ngrok will create randomized subdomains each time you execute the binary (e.g. 4951502d.ngrok.io). Custom subdomain names are a part of a paid subscription.

Once you have the ngrok binary you can create your tunnel.

Expose a local port on your client (5000 in this example):

$ ngrok http 5000 --bind-tls true

Expose a port on another host from your client (such as a running Docker host):

$ ngrok http 192.168.99.100:5000 --bind-tls true

When ngrok is running you will see the available public endpoints in the window and a stream of traffic logging. Going to http://127.0.0.1:4040 in your browser will show the web UI and additional details on the requests that are being made through the tunnel.

Environment Variables

Configuration settings are applied at runtime from the environment variables detailed below.

DEBUG

Run the application in debug mode (additional logging).

This setting will set to True if any value is provided. To leave this setting disabled do not set it in the environment.

SECRET_KEY

The secret key is a value used to secure sessions with the application.

If a value is not present the application will generate a 16-byte key using os.urandom().

SERVER_NAME

The domain name of the application server.

Example:

jackalope.mydomain.org
SLACK_CLIENT_ID

The client ID for the Slack application.

This is obtained during the app creation process at:

https://api.slack.com/apps
SLACK_CLIENT_SECRET

The client secret key for the Slack application.

This is obtained during the app creation process at:

https://api.slack.com/apps
SLACK_SHAREABLE_URL

The URL provided by Slack for installing the application to channels. This is used for the installation page’s “Add to Slack” button that is provided as a part of this application.

This is obtainted during the app create process at:

https://api.slack.com/apps

Note

The following database values are required when connecting Jackalope to a MySQL server. If they are omitted, a SQLite database will be created within the application directory. This is not recommended for production deployments.

DATABASE_URL

The URL to the MySQL server with the port.

Example:

localhost:3306
database.mydomain.org:3306
DATABASE_NAME

The name of the MySQL database residing on the server.

DATABASE_USER

The username to access the database with.

DATABASE_PASSWD

The password to the user accessing the database.

Using create_app()

jackalope.create_app()

Create the root application object, configure the database object, and register all blueprints from jackalope.routes.

Returns:Flask application
Return type:flask.Flask

Docker Example

The docker directory within the Github repository is an example of deploying Jackalope using Docker containers and the docker-compose utility.

Warning

This example is not configured for HTTPS traffic - only HTTP over port 80. A production deployment should be configured with a certificate to encrypt traffic using TLS.

docker-compose will start three containers (nginx, web - the application - and mysql) on the host. It will also create a volume attached to the mysql container to persist the database between container tear-downs (but be warned: if the volume is deleted the database will be lost!).

In your shell/Terminal, cd into the docker directory before continuing.

Connect to a Docker Host

$ eval $(docker-machine env yourhost)

Docker Environment Variables

Set the following environment variables within your shell/Terminal:

  • DEBUG
  • SECRET_KEY
  • SERVER_NAME
  • SLACK_CLIENT_ID
  • SLACK_CLIENT_SECRET
  • SLACK_SHAREABLE_URL
  • MYSQL_ROOT_PASSWORD
  • MYSQL_DATABASE
  • MYSQL_USER
  • MYSQL_PASSWORD

Build and Run the Containers

$ docker-compose build
$ docker-compose up -d

You will be able to access the application at the IP address of the Docker host.

Note

You can use ngrok to create a secure tunnel to the Docker host and expose it on the public internet to test with Slack. See Testing with ngrok for more details.

Routes

GET: /

jackalope.routes.install.root()

Renders the “Add to Slack” page.

GET: /install

jackalope.routes.install.install()

The installation endpoint as set in the “Redirect URLs” for the Slack application under “OAuth & Permissions”.

A code parameter will be provided by Slack to this URL once an installing user has authorized the application for a channel.

Using the code along with the application’s set SLACK_CLIENT_ID and SLACK_CLIENT_SECRET values, the application will make a POST to https://slack.com/api/oauth.access to obtain an access_token and other details for the channel installation.

Upon an ok response to the request, the details will be saved to the database, a UUID will be generated for receiving Jamf Pro webhooks, and a success message displayed in the Slack channel.

If the Slack channel already exists in the database its details will be updated with those from the response.

POST: /jamf/<uuid>

jackalope.routes.jamfpro.jamf_webhook(jamf_uuid)

The receiver endpoint where jamf_uuid is the auto-generated UUID for and installed Slack channel.

Inbound webhooks must be in JSON format or a 400 error will be returned.

If a supported webhook event has been received it will be formatted into a Slack message via jackalope.routes.jamfpro.webhooks.webhook_notification() and sent via jackalope.slack.send_notification().

Parameters:jamf_uuid (str) – The generated UUID for the installed Slack channel.
Raises:SlackChannelLookupError
Raises:JSONNotProvided
Returns:HTTP 204 success response.

Slack Notifications

These functions handle the processing of Jamf Pro webhook events to Slack notifications.

jackalope.routes.jamfpro.webhooks.webhook_notification(webhook)

Takes a Jamf Pro webhook event object and returns a formatted Slack message from the details if it is in the supported webhook events list.

If the webhook event is not supported None will be returned.

Parameters:webhook – Jamf Pro webhook JSON as dictionary.
Returns:Formatted Slack message.
Return type:dict or None
jackalope.routes.jamfpro.webhooks._message(text, title, title_link=None, color='gray', fallback_text=None, image=None, fields=None)

Create a Slack formatted message to use with jackalope.slack.send_notification().

Parameters:
  • text (str) – The main text to display in the message.
  • title (str) – The title of the message.
  • title_link (str) – An optional URL to pass that will convert the title into a clickable link.
  • color (str) – The color to display in the sidebar of the message. Must be of a value in the _colors dictionary or will default to gray.
  • fallback_text (str) – Alternative text to display in place of the provided text value. If not submitted this will be set to the value of text.
  • image (str) – The filename of an image located in /static/images/ to link to with the message. If not submitted this will be set to general_64.png.
  • fields (dict) – A dictionary of keyword values to populate the optional fields attribute of the Slack message.
jackalope.slack.send_notification(url, message)

Send a formatted Slack message to a channel’s inbound webhook.

Parameters:

Exceptions

class jackalope.routes.errors.JackalopeException

Base Jackalope Exception

class jackalope.routes.errors.JSONNotProvided

A valid JSON body was not provided with a request.

class jackalope.routes.errors.SlackChannelLookupError

Exception raised when performing a lookup of an installed Slack channel.