rest_cherrypy

A REST API for Salt

New in version 2014.7.0.

depends:
  • CherryPy Python module. Version 3.2.3 is currently recommended when SSL is enabled, since this version worked the best with SSL in internal testing. Versions 3.2.3 - 4.x can be used if SSL is not enabled. Be aware that there is a known SSL error introduced in version 3.2.5. The issue was reportedly resolved with CherryPy milestone 3.3, but the patch was committed for version 3.6.1.
optdepends:
  • ws4py Python module for websockets support.
client_libraries:
 
configuration:

All authentication is done through Salt's external auth system which requires additional configuration not described here.

Example production-ready configuration; add to the Salt master config file and restart the salt-master and salt-api daemons:

rest_cherrypy:
  port: 8000
  ssl_crt: /etc/pki/tls/certs/localhost.crt
  ssl_key: /etc/pki/tls/certs/localhost.key

Using only a secure HTTPS connection is strongly recommended since Salt authentication credentials will be sent over the wire.

A self-signed certificate can be generated using the create_self_signed_cert() execution function. Running this function requires pyOpenSSL and the salt-call script is available in the salt-minion package.

salt-call --local tls.create_self_signed_cert

All available configuration options are detailed below. These settings configure the CherryPy HTTP server and do not apply when using an external server such as Apache or Nginx.

port

Required

The port for the webserver to listen on.

host : 0.0.0.0

The socket interface for the HTTP server to listen on.

debug : False

Starts the web server in development mode. It will reload itself when the underlying code is changed and will output more debugging info.

ssl_crt

The path to a SSL certificate. (See below)

ssl_key

The path to the private key for your SSL certificate. (See below)

disable_ssl

A flag to disable SSL. Warning: your Salt authentication credentials will be sent in the clear!

webhook_disable_auth : False

The Webhook URL requires authentication by default but external services cannot always be configured to send authentication. See the Webhook documentation for suggestions on securing this interface.

webhook_url : /hook

Configure the URL endpoint for the Webhook entry point.

thread_pool : 100

The number of worker threads to start up in the pool.

socket_queue_size : 30

Specify the maximum number of HTTP connections to queue.

expire_responses : True

Whether to check for and kill HTTP responses that have exceeded the default timeout.

max_request_body_size : 1048576

Maximum size for the HTTP request body.

collect_stats : False

Collect and report statistics about the CherryPy server

Reports are available via the Stats URL.

static

A filesystem path to static HTML/JavaScript/CSS/image assets.

static_path : /static

The URL prefix to use when serving static assets out of the directory specified in the static setting.

app

A filesystem path to an HTML file that will be served as a static file. This is useful for bootstrapping a single-page JavaScript app.

app_path : /app

The URL prefix to use for serving the HTML file specified in the app setting. This should be a simple name containing no slashes.

Any path information after the specified path is ignored; this is useful for apps that utilize the HTML5 history API.

root_prefix : /

A URL path to the main entry point for the application. This is useful for serving multiple applications from the same URL.

Authentication

Authentication is performed by passing a session token with each request. Tokens are generated via the Login URL.

The token may be sent in one of two ways:

  • Include a custom header named X-Auth-Token.

    For example, using curl:

    curl -sSk https://localhost:8000/login \
        -H 'Accept: application/x-yaml' \
        -d username=saltdev \
        -d password=saltdev \
        -d eauth=auto
    

Copy the token value from the output and include it in subsequent requests:

curl -sSk https://localhost:8000 \
    -H 'Accept: application/x-yaml' \
    -H 'X-Auth-Token: 697adbdc8fe971d09ae4c2a3add7248859c87079'\
    -d client=local \
    -d tgt='*' \
    -d fun=test.ping
  • Sent via a cookie. This option is a convenience for HTTP clients that automatically handle cookie support (such as browsers).

    For example, using curl:

    # Write the cookie file:
    curl -sSk https://localhost:8000/login \
          -c ~/cookies.txt \
          -H 'Accept: application/x-yaml' \
          -d username=saltdev \
          -d password=saltdev \
          -d eauth=auto
    
    # Read the cookie file:
    curl -sSk https://localhost:8000 \
          -b ~/cookies.txt \
          -H 'Accept: application/x-yaml' \
          -d client=local \
          -d tgt='*' \
          -d fun=test.ping
    

See also

You can bypass the session handling via the Run URL.

Usage

Commands are sent to a running Salt master via this module by sending HTTP requests to the URLs detailed below.

Content negotiation

This REST interface is flexible in what data formats it will accept as well as what formats it will return (e.g., JSON, YAML, x-www-form-urlencoded).

  • Specify the format of data in the request body by including the Content-Type header.
  • Specify the desired data format for the response body with the Accept header.

Data sent in POST and PUT requests must be in the format of a list of lowstate dictionaries. This allows multiple commands to be executed in a single HTTP request. The order of commands in the request corresponds to the return for each command in the response.

Lowstate, broadly, is a dictionary of values that are mapped to a function call. This pattern is used pervasively throughout Salt. The functions called from netapi modules are described in Client Interfaces.

The following example (in JSON format) causes Salt to execute two commands, a command sent to minions as well as a runner function on the master:

[{
    "client": "local",
    "tgt": "*",
    "fun": "test.fib",
    "arg": ["10"]
},
{
    "client": "runner",
    "fun": "jobs.lookup_jid",
    "jid": "20130603122505459265"
}]

x-www-form-urlencoded

Sending JSON or YAML in the request body is simple and most flexible, however sending data in urlencoded format is also supported with the caveats below. It is the default format for HTML forms, many JavaScript libraries, and the curl command.

For example, the equivalent to running salt '*' test.ping is sending fun=test.ping&arg&client=local&tgt=* in the HTTP request body.

Caveats:

  • Only a single command may be sent per HTTP request.

  • Repeating the arg parameter multiple times will cause those parameters to be combined into a single list.

    Note, some popular frameworks and languages (notably jQuery, PHP, and Ruby on Rails) will automatically append empty brackets onto repeated parameters. E.g., arg=one, arg=two will be sent as arg[]=one, arg[]=two. This is not supported; send JSON or YAML instead.

Deployment

The rest_cherrypy netapi module is a standard Python WSGI app. It can be deployed one of two ways.

salt-api using the CherryPy server

The default configuration is to run this module using salt-api to start the Python-based CherryPy server. This server is lightweight, multi-threaded, encrypted with SSL, and should be considered production-ready.

Using a WSGI-compliant web server

This module may be deployed on any WSGI-compliant server such as Apache with mod_wsgi or Nginx with FastCGI, to name just two (there are many).

Note, external WSGI servers handle URLs, paths, and SSL certs directly. The rest_cherrypy configuration options are ignored and the salt-api daemon does not need to be running at all. Remember Salt authentication credentials are sent in the clear unless SSL is being enforced!

An example Apache virtual host configuration:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias *.example.com

    ServerAdmin [email protected]

    LogLevel warn
    ErrorLog /var/www/example.com/logs/error.log
    CustomLog /var/www/example.com/logs/access.log combined

    DocumentRoot /var/www/example.com/htdocs

    WSGIScriptAlias / /path/to/salt/netapi/rest_cherrypy/wsgi.py
</VirtualHost>

REST URI Reference

/

class salt.netapi.rest_cherrypy.app.LowDataAdapter

The primary entry point to Salt's REST API

GET()

An explanation of the API with links of where to go next

GET /
Request Headers:
 
  • Accept -- the desired response format.
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -i localhost:8000
GET / HTTP/1.1
Host: localhost:8000
Accept: application/json

Example response:

HTTP/1.1 200 OK
Content-Type: application/json
POST

Mock out specified imports

This allows autodoc to do its thing without having oodles of req'd installed libs. This doesn't work with import * imports.

http://read-the-docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules

/login

class salt.netapi.rest_cherrypy.app.Login(*args, **kwargs)

Log in to receive a session token

Authentication information.

GET()

Present the login interface

GET /login

An explanation of how to log in.

Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -i localhost:8000/login
GET /login HTTP/1.1
Host: localhost:8000
Accept: text/html

Example response:

HTTP/1.1 200 OK
Content-Type: text/html
POST(**kwargs)

Authenticate against Salt's eauth system

POST /login
Request Headers:
 
  • X-Auth-Token -- a session token from Login.
  • Accept -- the desired response format.
  • Content-Type -- the format of the request body.
Form Parameters:
 
  • eauth -- the eauth backend configured for the user
  • username -- username
  • password -- password
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -si localhost:8000/login \
        -H "Accept: application/json" \
        -d username='saltuser' \
        -d password='saltpass' \
        -d eauth='pam'
POST / HTTP/1.1
Host: localhost:8000
Content-Length: 42
Content-Type: application/x-www-form-urlencoded
Accept: application/json

username=saltuser&password=saltpass&eauth=pam

Example response:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 206
X-Auth-Token: 6d1b722e
Set-Cookie: session_id=6d1b722e; expires=Sat, 17 Nov 2012 03:23:52 GMT; Path=/

{"return": {
    "token": "6d1b722e",
    "start": 1363805943.776223,
    "expire": 1363849143.776224,
    "user": "saltuser",
    "eauth": "pam",
    "perms": [
        "grains.*",
        "status.*",
        "sys.*",
        "test.*"
    ]
}}

/logout

class salt.netapi.rest_cherrypy.app.Logout

Class to remove or invalidate sessions

POST()

Destroy the currently active session and expire the session cookie

/minions

class salt.netapi.rest_cherrypy.app.Minions

Convenience URLs for working with minions

GET(mid=None)

A convenience URL for getting lists of minions or getting minion details

GET /minions/(mid)
Request Headers:
 
  • X-Auth-Token -- a session token from Login.
  • Accept -- the desired response format.
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -i localhost:8000/minions/ms-3
GET /minions/ms-3 HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml

Example response:

HTTP/1.1 200 OK
Content-Length: 129005
Content-Type: application/x-yaml

return:
- ms-3:
    grains.items:
        ...
POST(**kwargs)

Start an execution command and immediately return the job id

POST /minions
Request Headers:
 
  • X-Auth-Token -- a session token from Login.
  • Accept -- the desired response format.
  • Content-Type -- the format of the request body.
Response Headers:
 
  • Content-Type -- the format of the response body; depends on the Accept request header.
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

lowstate data describing Salt commands must be sent in the request body. The client option will be set to local_async().

Example request:

curl -sSi localhost:8000/minions \
    -H "Accept: application/x-yaml" \
    -d tgt='*' \
    -d fun='status.diskusage'
POST /minions HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml
Content-Length: 26
Content-Type: application/x-www-form-urlencoded

tgt=*&fun=status.diskusage

Example response:

HTTP/1.1 202 Accepted
Content-Length: 86
Content-Type: application/x-yaml

return:
- jid: '20130603122505459265'
  minions: [ms-4, ms-3, ms-2, ms-1, ms-0]
_links:
  jobs:
    - href: /jobs/20130603122505459265

/jobs

class salt.netapi.rest_cherrypy.app.Jobs
GET(jid=None)

A convenience URL for getting lists of previously run jobs or getting the return from a single job

GET /jobs/(jid)

List jobs or show a single job from the job cache.

Request Headers:
 
  • X-Auth-Token -- a session token from Login.
  • Accept -- the desired response format.
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -i localhost:8000/jobs
GET /jobs HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml

Example response:

HTTP/1.1 200 OK
Content-Length: 165
Content-Type: application/x-yaml

return:
- '20121130104633606931':
    Arguments:
    - '3'
    Function: test.fib
    Start Time: 2012, Nov 30 10:46:33.606931
    Target: jerry
    Target-type: glob

Example request:

curl -i localhost:8000/jobs/20121130104633606931
GET /jobs/20121130104633606931 HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml

Example response:

HTTP/1.1 200 OK
Content-Length: 73
Content-Type: application/x-yaml

info:
- Arguments:
    - '3'
    Function: test.fib
    Minions:
    - jerry
    Start Time: 2012, Nov 30 10:46:33.606931
    Target: '*'
    Target-type: glob
    User: saltdev
    jid: '20121130104633606931'
return:
- jerry:
    - - 0
    - 1
    - 1
    - 2
    - 6.9141387939453125e-06

/run

class salt.netapi.rest_cherrypy.app.Run

Class to run commands without normal session handling

POST(**kwargs)

Run commands bypassing the normal session handling

POST /run

This entry point is primarily for "one-off" commands. Each request must pass full Salt authentication credentials. Otherwise this URL is identical to the root URL (/).

lowstate data describing Salt commands must be sent in the request body.

Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -sS localhost:8000/run \
    -H 'Accept: application/x-yaml' \
    -d client='local' \
    -d tgt='*' \
    -d fun='test.ping' \
    -d username='saltdev' \
    -d password='saltdev' \
    -d eauth='pam'
POST /run HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml
Content-Length: 75
Content-Type: application/x-www-form-urlencoded

client=local&tgt=*&fun=test.ping&username=saltdev&password=saltdev&eauth=pam

Example response:

HTTP/1.1 200 OK
Content-Length: 73
Content-Type: application/x-yaml

return:
- ms-0: true
    ms-1: true
    ms-2: true
    ms-3: true
    ms-4: true

The /run enpoint can also be used to issue commands using the salt-ssh subsystem.

When using salt-ssh, eauth credentials should not be supplied. Instad, authentication should be handled by the SSH layer itself. The use of the salt-ssh client does not require a salt master to be running. Instead, only a roster file must be present in the salt configuration directory.

All SSH client requests are synchronous.

** Example SSH client request:**

curl -sS localhost:8000/run \
    -H 'Accept: application/x-yaml' \
    -d client='ssh' \
    -d tgt='*' \
    -d fun='test.ping'
POST /run HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml
Content-Length: 75
Content-Type: application/x-www-form-urlencoded

client=ssh&tgt=*&fun=test.ping

Example SSH response:

return:
- silver:
  fun: test.ping
  fun_args: []
  id: silver
  jid: '20141203103525666185'
  retcode: 0
  return: true
  success: true

/events

class salt.netapi.rest_cherrypy.app.Events

Expose the Salt event bus

The event bus on the Salt master exposes a large variety of things, notably when executions are started on the master and also when minions ultimately return their results. This URL provides a real-time window into a running Salt infrastructure.

See also

events

GET(token=None, salt_token=None)

An HTTP stream of the Salt master event bus

This stream is formatted per the Server Sent Events (SSE) spec. Each event is formatted as JSON.

GET /events
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available
Query Parameters:
 
  • token -- optional parameter containing the token ordinarily supplied via the X-Auth-Token header in order to allow cross-domain requests in browsers that do not include CORS support in the EventSource API. E.g., curl -NsS localhost:8000/events?token=308650d
  • salt_token -- optional parameter containing a raw Salt eauth token (not to be confused with the token returned from the /login URL). E.g., curl -NsS localhost:8000/events?salt_token=30742765

Example request:

curl -NsS localhost:8000/events
GET /events HTTP/1.1
Host: localhost:8000

Example response:

Note, the tag field is not part of the spec. SSE compliant clients should ignore unknown fields. This addition allows non-compliant clients to only watch for certain tags without having to deserialze the JSON object each time.

HTTP/1.1 200 OK
Connection: keep-alive
Cache-Control: no-cache
Content-Type: text/event-stream;charset=utf-8

retry: 400

tag: salt/job/20130802115730568475/new
data: {'tag': 'salt/job/20130802115730568475/new', 'data': {'minions': ['ms-4', 'ms-3', 'ms-2', 'ms-1', 'ms-0']}}

tag: salt/job/20130802115730568475/ret/jerry
data: {'tag': 'salt/job/20130802115730568475/ret/jerry', 'data': {'jid': '20130802115730568475', 'return': True, 'retcode': 0, 'success': True, 'cmd': '_return', 'fun': 'test.ping', 'id': 'ms-1'}}

The event stream can be easily consumed via JavaScript:

var source = new EventSource('/events');
source.onopen = function() { console.debug('opening') };
source.onerror = function(e) { console.debug('error!', e) };
source.onmessage = function(e) {
    console.debug('Tag: ', e.data.tag)
    console.debug('Data: ', e.data.data)
};

Or using CORS:

var source = new EventSource('/events?token=ecd589e4e01912cf3c4035afad73426dbb8dba75', {withCredentials: true});

It is also possible to consume the stream via the shell.

Records are separated by blank lines; the data: and tag: prefixes will need to be removed manually before attempting to unserialize the JSON.

curl's -N flag turns off input buffering which is required to process the stream incrementally.

Here is a basic example of printing each event as it comes in:

curl -NsS localhost:8000/events |\
        while IFS= read -r line ; do
            echo $line
        done

Here is an example of using awk to filter events based on tag:

curl -NsS localhost:8000/events |\
        awk '
            BEGIN { RS=""; FS="\\n" }
            $1 ~ /^tag: salt\/job\/[0-9]+\/new$/ { print $0 }
        '
tag: salt/job/20140112010149808995/new
data: {"tag": "salt/job/20140112010149808995/new", "data": {"tgt_type": "glob", "jid": "20140112010149808995", "tgt": "jerry", "_stamp": "2014-01-12_01:01:49.809617", "user": "shouse", "arg": [], "fun": "test.ping", "minions": ["jerry"]}}
tag: 20140112010149808995
data: {"tag": "20140112010149808995", "data": {"fun_args": [], "jid": "20140112010149808995", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2014-01-12_01:01:49.819316", "fun": "test.ping", "id": "jerry"}}

/hook

class salt.netapi.rest_cherrypy.app.Webhook

A generic web hook entry point that fires an event on Salt's event bus

External services can POST data to this URL to trigger an event in Salt. For example, Amazon SNS, Jenkins-CI or Travis-CI, or GitHub web hooks.

Note

Be mindful of security

Salt's Reactor can run any code. A Reactor SLS that responds to a hook event is responsible for validating that the event came from a trusted source and contains valid data.

This is a generic interface and securing it is up to you!

This URL requires authentication however not all external services can be configured to authenticate. For this reason authentication can be selectively disabled for this URL. Follow best practices -- always use SSL, pass a secret key, configure the firewall to only allow traffic from a known source, etc.

The event data is taken from the request body. The Content-Type header is respected for the payload.

The event tag is prefixed with salt/netapi/hook and the URL path is appended to the end. For example, a POST request sent to /hook/mycompany/myapp/mydata will produce a Salt event with the tag salt/netapi/hook/mycompany/myapp/mydata.

The following is an example .travis.yml file to send notifications to Salt of successful test runs:

language: python
script: python -m unittest tests
after_success:
    - |
        curl -sSk https://saltapi-url.example.com:8000/hook/travis/build/success                         -d branch="${TRAVIS_BRANCH}"                         -d commit="${TRAVIS_COMMIT}"

See also

events, reactor

POST(*args, **kwargs)

Fire an event in Salt with a custom event tag and data

POST /hook
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available
  • 413 -- request body is too large

Example request:

curl -sS localhost:8000/hook -d foo='Foo!' -d bar='Bar!'
POST /hook HTTP/1.1
Host: localhost:8000
Content-Length: 16
Content-Type: application/x-www-form-urlencoded

foo=Foo&bar=Bar!

Example response:

HTTP/1.1 200 OK
Content-Length: 14
Content-Type: application/json

{"success": true}

As a practical example, an internal continuous-integration build server could send an HTTP POST request to the URL https://localhost:8000/hook/mycompany/build/success which contains the result of a build and the SHA of the version that was built as JSON. That would then produce the following event in Salt that could be used to kick off a deployment via Salt's Reactor:

Event fired at Fri Feb 14 17:40:11 2014
*************************
Tag: salt/netapi/hook/mycompany/build/success
Data:
{'_stamp': '2014-02-14_17:40:11.440996',
    'headers': {
        'X-My-Secret-Key': 'F0fAgoQjIT@W',
        'Content-Length': '37',
        'Content-Type': 'application/json',
        'Host': 'localhost:8000',
        'Remote-Addr': '127.0.0.1'},
    'post': {'revision': 'aa22a3c4b2e7', 'result': True}}

Salt's Reactor could listen for the event:

reactor:
  - 'salt/netapi/hook/mycompany/build/*':
    - /srv/reactor/react_ci_builds.sls

And finally deploy the new build:

{% set secret_key = data.get('headers', {}).get('X-My-Secret-Key') %}
{% set build = data.get('post', {}) %}

{% if secret_key == 'F0fAgoQjIT@W' and build.result == True %}
deploy_my_app:
  cmd.state.sls:
    - tgt: 'application*'
    - arg:
      - myapp.deploy
    - kwarg:
        pillar:
          revision: {{ revision }}
{% endif %}

/keys

class salt.netapi.rest_cherrypy.app.Keys

Convenience URLs for working with minion keys

New in version 2014.7.0.

These URLs wrap the functionality provided by the key wheel module functions.

GET(mid=None)

Show the list of minion keys or detail on a specific key

New in version 2014.7.0.

GET /keys/(mid)

List all keys or show a specific key

Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -i localhost:8000/keys
GET /keys HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml

Example response:

HTTP/1.1 200 OK
Content-Length: 165
Content-Type: application/x-yaml

return:
  local:
  - master.pem
  - master.pub
  minions:
  - jerry
  minions_pre: []
  minions_rejected: []

Example request:

curl -i localhost:8000/keys/jerry
GET /keys/jerry HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml

Example response:

HTTP/1.1 200 OK
Content-Length: 73
Content-Type: application/x-yaml

return:
  minions:
    jerry: 51:93:b3:d0:9f:3a:6d:e5:28:67:c2:4b:27:d6:cd:2b
POST(**kwargs)

Easily generate keys for a minion and auto-accept the new key

Accepts all the same parameters as the key.gen_accept.

Example partial kickstart script to bootstrap a new minion:

%post
mkdir -p /etc/salt/pki/minion
curl -sSk https://localhost:8000/keys \
        -d mid=jerry \
        -d username=kickstart \
        -d password=kickstart \
        -d eauth=pam \
    | tar -C /etc/salt/pki/minion -xf -

mkdir -p /etc/salt/minion.d
printf 'master: 10.0.0.5\nid: jerry' > /etc/salt/minion.d/id.conf
%end
POST /keys

Generate a public and private key and return both as a tarball

Authentication credentials must be passed in the request.

Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -sSk https://localhost:8000/keys \
        -d mid=jerry \
        -d username=kickstart \
        -d password=kickstart \
        -d eauth=pam \
        -o jerry-salt-keys.tar
POST /keys HTTP/1.1
Host: localhost:8000

Example response:

HTTP/1.1 200 OK
Content-Length: 10240
Content-Disposition: attachment; filename="saltkeys-jerry.tar"
Content-Type: application/x-tar

jerry.pub0000644000000000000000000000070300000000000010730 0ustar  00000000000000

/ws

class salt.netapi.rest_cherrypy.app.WebsocketEndpoint

Open a WebSocket connection to Salt's event bus

The event bus on the Salt master exposes a large variety of things, notably when executions are started on the master and also when minions ultimately return their results. This URL provides a real-time window into a running Salt infrastructure. Uses websocket as the transport mechanism.

See also

events

GET(token=None, **kwargs)

Return a websocket connection of Salt's event stream

GET /ws/(token)
Query Parameters:
 
  • format_events --

    The event stream will undergo server-side formatting if the format_events URL parameter is included in the request. This can be useful to avoid formatting on the client-side:

    curl -NsS <...snip...> localhost:8000/ws?format_events
    
Request Headers:
 
  • X-Auth-Token -- an authentication token from Login.
Status Codes:
  • 101 -- switching to the websockets protocol
  • 401 -- authentication required
  • 406 -- requested Content-Type not available

Example request:

curl -NsSk
-H 'X-Auth-Token: ffedf49d' -H 'Host: localhost:8000' -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Origin: https://localhost:8000' -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: '"$(echo -n $RANDOM | base64)" localhost:8000/ws
GET /ws HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Host: localhost:8000
Origin: https://localhost:8000
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: s65VsgHigh7v/Jcf4nXHnA==
X-Auth-Token: ffedf49d

Example response:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: mWZjBV9FCglzn1rIKJAxrTFlnJE=
Sec-WebSocket-Version: 13

An authentication token may optionally be passed as part of the URL for browsers that cannot be configured to send the authentication header or cookie:

curl -NsS <...snip...> localhost:8000/ws/ffedf49d

The event stream can be easily consumed via JavaScript:

// Note, you must be authenticated!
var source = new Websocket('ws://localhost:8000/ws/d0ce6c1a');
source.onerror = function(e) { console.debug('error!', e); };
source.onmessage = function(e) { console.debug(e.data); };

source.send('websocket client ready')

source.close();

Or via Python, using the Python module websocket-client for example.

# Note, you must be authenticated!

from websocket import create_connection

ws = create_connection('ws://localhost:8000/ws/d0ce6c1a')
ws.send('websocket client ready')

# Look at https://pypi.python.org/pypi/websocket-client/ for more
# examples.
while listening_to_events:
    print ws.recv()

ws.close()

Above examples show how to establish a websocket connection to Salt and activating real time updates from Salt's event stream by signaling websocket client ready.

/stats

class salt.netapi.rest_cherrypy.app.Stats

Expose statistics on the running CherryPy server

GET()

Return a dump of statistics collected from the CherryPy server

GET /stats
Request Headers:
 
  • X-Auth-Token -- a session token from Login.
  • Accept -- the desired response format.
Response Headers:
 
  • Content-Type -- the format of the response body; depends on the Accept request header.
Status Codes:
  • 200 -- success
  • 401 -- authentication required
  • 406 -- requested Content-Type not available