Mini Shell
"""
StatusPage
==========
Handle requests for the StatusPage_ API_.
.. _StatusPage: https://www.statuspage.io/
.. _API: http://doers.statuspage.io/api/v1/
In the minion configuration file, the following block is required:
.. code-block:: yaml
statuspage:
api_key: <API_KEY>
page_id: <PAGE_ID>
.. versionadded:: 2017.7.0
"""
import logging
# import third party
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
# ----------------------------------------------------------------------------------------------------------------------
# module properties
# ----------------------------------------------------------------------------------------------------------------------
__virtualname__ = "statuspage"
log = logging.getLogger(__file__)
BASE_URL = "https://api.statuspage.io"
DEFAULT_VERSION = 1
UPDATE_FORBIDDEN_FILEDS = [
"id", # can't rewrite this
"created_at",
"updated_at", # updated_at and created_at are handled by the backend framework of the API
"page_id", # can't move it to a different page
]
INSERT_FORBIDDEN_FILEDS = UPDATE_FORBIDDEN_FILEDS[:] # they are the same for the moment
METHOD_OK_STATUS = {"POST": 201, "DELETE": 204}
# ----------------------------------------------------------------------------------------------------------------------
# property functions
# ----------------------------------------------------------------------------------------------------------------------
def __virtual__():
"""
Return the execution module virtualname.
"""
if HAS_REQUESTS is False:
return False, "The requests python package is not installed"
return __virtualname__
def _default_ret():
"""
Default dictionary returned.
"""
return {"result": False, "comment": "", "out": None}
def _get_api_params(api_url=None, page_id=None, api_key=None, api_version=None):
"""
Retrieve the API params from the config file.
"""
statuspage_cfg = __salt__["config.get"]("statuspage")
if not statuspage_cfg:
statuspage_cfg = {}
return {
"api_url": api_url or statuspage_cfg.get("api_url") or BASE_URL, # optional
"api_page_id": page_id or statuspage_cfg.get("page_id"), # mandatory
"api_key": api_key or statuspage_cfg.get("api_key"), # mandatory
"api_version": api_version
or statuspage_cfg.get("api_version")
or DEFAULT_VERSION,
}
def _validate_api_params(params):
"""
Validate the API params as specified in the config file.
"""
# page_id and API key are mandatory and they must be string/unicode
return isinstance(params["api_page_id"], ((str,), str)) and isinstance(
params["api_key"], ((str,), str)
)
def _get_headers(params):
"""
Return HTTP headers required.
"""
return {"Authorization": "OAuth {oauth}".format(oauth=params["api_key"])}
def _http_request(url, method="GET", headers=None, data=None):
"""
Make the HTTP request and return the body as python object.
"""
req = requests.request(method, url, headers=headers, data=data, timeout=120)
ret = _default_ret()
ok_status = METHOD_OK_STATUS.get(method, 200)
if req.status_code != ok_status:
ret.update({"comment": req.json().get("error", "")})
return ret
ret.update(
{
"result": True,
"out": req.json() if method != "DELETE" else None, # no body when DELETE
}
)
return ret
# ----------------------------------------------------------------------------------------------------------------------
# callable functions
# ----------------------------------------------------------------------------------------------------------------------
def create(
endpoint="incidents",
api_url=None,
page_id=None,
api_key=None,
api_version=None,
**kwargs
):
"""
Insert a new entry under a specific endpoint.
endpoint: incidents
Insert under this specific endpoint.
page_id
Page ID. Can also be specified in the config file.
api_key
API key. Can also be specified in the config file.
api_version: 1
API version. Can also be specified in the config file.
api_url
Custom API URL in case the user has a StatusPage service running in a custom environment.
CLI Example:
.. code-block:: bash
salt 'minion' statuspage.create endpoint='components' name='my component' group_id='993vgplshj12'
Example output:
.. code-block:: bash
minion:
----------
comment:
out:
----------
created_at:
2017-01-05T19:35:27.135Z
description:
None
group_id:
993vgplshj12
id:
mjkmtt5lhdgc
name:
my component
page_id:
ksdhgfyiuhaa
position:
7
status:
operational
updated_at:
2017-01-05T19:35:27.135Z
result:
True
"""
params = _get_api_params(
api_url=api_url, page_id=page_id, api_key=api_key, api_version=api_version
)
if not _validate_api_params(params):
log.error("Invalid API params.")
log.error(params)
return {"result": False, "comment": "Invalid API params. See log for details"}
endpoint_sg = endpoint[:-1] # singular
headers = _get_headers(params)
create_url = "{base_url}/v{version}/pages/{page_id}/{endpoint}.json".format(
base_url=params["api_url"],
version=params["api_version"],
page_id=params["api_page_id"],
endpoint=endpoint,
)
change_request = {}
for karg, warg in kwargs.items():
if warg is None or karg.startswith("__") or karg in INSERT_FORBIDDEN_FILEDS:
continue
change_request_key = "{endpoint_sg}[{karg}]".format(
endpoint_sg=endpoint_sg, karg=karg
)
change_request[change_request_key] = warg
return _http_request(
create_url, method="POST", headers=headers, data=change_request
)
def retrieve(
endpoint="incidents", api_url=None, page_id=None, api_key=None, api_version=None
):
"""
Retrieve a specific endpoint from the Statuspage API.
endpoint: incidents
Request a specific endpoint.
page_id
Page ID. Can also be specified in the config file.
api_key
API key. Can also be specified in the config file.
api_version: 1
API version. Can also be specified in the config file.
api_url
Custom API URL in case the user has a StatusPage service running in a custom environment.
CLI Example:
.. code-block:: bash
salt 'minion' statuspage.retrieve components
Example output:
.. code-block:: bash
minion:
----------
comment:
out:
|_
----------
backfilled:
False
created_at:
2015-01-26T20:25:02.702Z
id:
kh2qwjbheqdc36
impact:
major
impact_override:
None
incident_updates:
|_
----------
affected_components:
None
body:
We are currently investigating this issue.
created_at:
2015-01-26T20:25:02.849Z
display_at:
2015-01-26T20:25:02.849Z
id:
zvx7xz2z5skr
incident_id:
kh2qwjbheqdc36
status:
investigating
twitter_updated_at:
None
updated_at:
2015-01-26T20:25:02.849Z
wants_twitter_update:
False
monitoring_at:
None
name:
just testing some stuff
page_id:
ksdhgfyiuhaa
postmortem_body:
None
postmortem_body_last_updated_at:
None
postmortem_ignored:
False
postmortem_notified_subscribers:
False
postmortem_notified_twitter:
False
postmortem_published_at:
None
resolved_at:
None
scheduled_auto_completed:
False
scheduled_auto_in_progress:
False
scheduled_for:
None
scheduled_remind_prior:
False
scheduled_reminded_at:
None
scheduled_until:
None
shortlink:
http://stspg.io/voY
status:
investigating
updated_at:
2015-01-26T20:25:13.379Z
result:
True
"""
params = _get_api_params(
api_url=api_url, page_id=page_id, api_key=api_key, api_version=api_version
)
if not _validate_api_params(params):
log.error("Invalid API params.")
log.error(params)
return {"result": False, "comment": "Invalid API params. See log for details"}
headers = _get_headers(params)
retrieve_url = "{base_url}/v{version}/pages/{page_id}/{endpoint}.json".format(
base_url=params["api_url"],
version=params["api_version"],
page_id=params["api_page_id"],
endpoint=endpoint,
)
return _http_request(retrieve_url, headers=headers)
def update(
endpoint="incidents",
id=None,
api_url=None,
page_id=None,
api_key=None,
api_version=None,
**kwargs
):
"""
Update attribute(s) of a specific endpoint.
id
The unique ID of the endpoint entry.
endpoint: incidents
Endpoint name.
page_id
Page ID. Can also be specified in the config file.
api_key
API key. Can also be specified in the config file.
api_version: 1
API version. Can also be specified in the config file.
api_url
Custom API URL in case the user has a StatusPage service running in a custom environment.
CLI Example:
.. code-block:: bash
salt 'minion' statuspage.update id=dz959yz2nd4l status=resolved
Example output:
.. code-block:: bash
minion:
----------
comment:
out:
----------
created_at:
2017-01-03T15:25:30.718Z
description:
None
group_id:
993vgplshj12
id:
dz959yz2nd4l
name:
Management Portal
page_id:
xzwjjdw87vpf
position:
11
status:
resolved
updated_at:
2017-01-05T15:34:27.676Z
result:
True
"""
endpoint_sg = endpoint[:-1] # singular
if not id:
log.error("Invalid %s ID", endpoint_sg)
return {
"result": False,
"comment": "Please specify a valid {endpoint} ID".format(
endpoint=endpoint_sg
),
}
params = _get_api_params(
api_url=api_url, page_id=page_id, api_key=api_key, api_version=api_version
)
if not _validate_api_params(params):
log.error("Invalid API params.")
log.error(params)
return {"result": False, "comment": "Invalid API params. See log for details"}
headers = _get_headers(params)
update_url = "{base_url}/v{version}/pages/{page_id}/{endpoint}/{id}.json".format(
base_url=params["api_url"],
version=params["api_version"],
page_id=params["api_page_id"],
endpoint=endpoint,
id=id,
)
change_request = {}
for karg, warg in kwargs.items():
if warg is None or karg.startswith("__") or karg in UPDATE_FORBIDDEN_FILEDS:
continue
change_request_key = "{endpoint_sg}[{karg}]".format(
endpoint_sg=endpoint_sg, karg=karg
)
change_request[change_request_key] = warg
return _http_request(
update_url, method="PATCH", headers=headers, data=change_request
)
def delete(
endpoint="incidents",
id=None,
api_url=None,
page_id=None,
api_key=None,
api_version=None,
):
"""
Remove an entry from an endpoint.
endpoint: incidents
Request a specific endpoint.
page_id
Page ID. Can also be specified in the config file.
api_key
API key. Can also be specified in the config file.
api_version: 1
API version. Can also be specified in the config file.
api_url
Custom API URL in case the user has a StatusPage service running in a custom environment.
CLI Example:
.. code-block:: bash
salt 'minion' statuspage.delete endpoint='components' id='ftgks51sfs2d'
Example output:
.. code-block:: bash
minion:
----------
comment:
out:
None
result:
True
"""
params = _get_api_params(
api_url=api_url, page_id=page_id, api_key=api_key, api_version=api_version
)
if not _validate_api_params(params):
log.error("Invalid API params.")
log.error(params)
return {"result": False, "comment": "Invalid API params. See log for details"}
endpoint_sg = endpoint[:-1] # singular
if not id:
log.error("Invalid %s ID", endpoint_sg)
return {
"result": False,
"comment": "Please specify a valid {endpoint} ID".format(
endpoint=endpoint_sg
),
}
headers = _get_headers(params)
delete_url = "{base_url}/v{version}/pages/{page_id}/{endpoint}/{id}.json".format(
base_url=params["api_url"],
version=params["api_version"],
page_id=params["api_page_id"],
endpoint=endpoint,
id=id,
)
return _http_request(delete_url, method="DELETE", headers=headers)
Zerion Mini Shell 1.0