Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Add monitor and downtime APIs with integration tests. #115

Merged
merged 10 commits into from
Nov 17, 2014
15 changes: 15 additions & 0 deletions src/dogapi/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,18 @@ class MetricType(object):
Gauge = "gauge"
Counter = "counter"
Histogram = "histogram"


class MonitorType(object):
SERVICE_CHECK = 'service check'
METRIC_ALERT = 'metric alert'
QUERY_ALERT = 'query alert'
ALL = (SERVICE_CHECK, METRIC_ALERT, QUERY_ALERT)


class CheckStatus(object):
OK = 0
WARNING = 1
CRITICAL = 2
UNKNOWN = 3
ALL = (OK, WARNING, CRITICAL, UNKNOWN)
5 changes: 4 additions & 1 deletion src/dogapi/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
from dogapi.http.users import *
from dogapi.http.snapshot import *
from dogapi.http.screenboards import *
from dogapi.http.monitors import *
from dogapi.http.service_check import *

class DogHttpApi(BaseDatadog, HttpMetricApi, EventApi, DashApi, InfrastructureApi,
AlertApi, UserApi, SnapshotApi, ScreenboardApi):
AlertApi, UserApi, SnapshotApi, ScreenboardApi, MonitorApi, DowntimeApi,
ServiceCheckApi):
"""
A high-level client for interacting with the Datadog API.

Expand Down
1 change: 1 addition & 0 deletions src/dogapi/http/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
]

class AlertApi(object):
""" DEPRECATED: Used the methods in `MonitorApi` instead. """

def alert(self, query, name=None, message=None, silenced=False,
notify_no_data=None, timeout_h=None):
Expand Down
199 changes: 199 additions & 0 deletions src/dogapi/http/monitors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
__all__ = [
'DowntimeApi',
'MonitorApi',
'MonitorType',
]

from dogapi.constants import MonitorType
from dogapi.exceptions import ApiError

class MonitorApi(object):

def monitor(self, mtype, query, name=None, message=None, options=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we require name and message here because they're required in the backend?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not actually required in the backend anymore. That was a bug initially but I have changed the backend now so it has the same logic as the alert API (choosing the query as the name if no name is given, same for message).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! good to know

"""
Create a new monitor of type *mtype* with the given *name* and *query*.
The *message* will accompany any notifications sent for the alert and
can contain the same '@' notation as events to alert individual users.
The *options* argument is a dictionary of settings for the monitor.
See the Datadog API documentation for a break down of available options.

>>> dog_http_api.monitor("metric alert", "sum(last_1d):sum:system.net.bytes_rcvd{host:host0} > 100")
"""
mtype = mtype.lower()
if mtype not in MonitorType.ALL:
raise ApiError('Invalid monitor type, expected one of: %s' \
% ', '.join(MonitorType.ALL))

body = {
'type': mtype,
'query': query,
}

if name:
body['name'] = name
if message:
body['message'] = message
if options:
if not isinstance(options, dict):
raise ApiError('Invalid type for `options`, expected `dict`.')
body['options'] = options

return self.http_request('POST', '/monitor', body,
response_formatter=lambda x: x['id'],
)

def update_monitor(self, monitor_id, query, name=None, message=None,
options=None):
"""
Update the monitor identified by *monitor_id* with the given *query*.
The *message* will accompany any notifications sent for the alert and
can contain the same '@' notation as events to alert individual users.
The *options* argument is a dictionary of settings for the monitor.
See the Datadog API documentation for a break down of available options.

>>> dog_http_api.update_monitor(1234, "sum(last_1d):sum:system.net.bytes_rcvd{host:host0} > 200")
"""
body = {
'query': query
}
if name:
body['name'] = name
if message:
body['message'] = message
if options:
body['options'] = options

return self.http_request('PUT', '/monitor/%s' % monitor_id, body,
response_formatter=lambda x: x['id'],
)

def get_monitor(self, monitor_id, group_states=None):
"""
Get the details for the monitor identified by *monitor_id*.

*group_states* is optionally a list of statuses chosen from "all", "ok",
"warn", "alert", "no data". For example, if you want only the failing
groups then you would set it to ['alert', 'warn']. If no value is given
then no group states will be returned.

>>> dog_http_api.get_monitor(1234, group_states=['all'])
"""
params = {}

if group_states:
params['group_states'] = ','.join(group_states)

return self.http_request('GET', '/monitor/%s' % monitor_id, **params)

def delete_monitor(self, monitor_id):
"""
Delete the monitor identified by *monitor_id*.

>>> dog_http_api.delete_monitor(1234)
"""

return self.http_request('DELETE', '/monitor/%s' % monitor_id)

def get_all_monitors(self, group_states=None):
"""
Get the details for all monitors. If *include_state* is set to True then
the response will include the state of each active group in the alert.

*group_states* is optionally a list of statuses chosen from "all", "ok",
"warn", "alert", "no data". For example, if you want only the failing
groups then you would set it to ['alert', 'warn']. If no value is given
then no group states will be returned.

>>> dog_http_api.get_all_monitors(group_states=['alert'])
"""
params = {}

if group_states:
params['group_states'] = ','.join(group_states)

return self.http_request('GET', '/monitor', **params)

def mute_monitors(self):
"""
Mute all monitors.

>>> dog_http_api.mute_monitors()
"""

return self.http_request('POST', '/monitor/mute_all')

def unmute_monitors(self):
"""
Unmute all monitors.

>>> dog_http_api.unmute_monitors()
"""

return self.http_request('POST', '/monitor/unmute_all')

def mute_monitor(self, monitor_id, scope=None, end=None):
"""
Mute the monitor identified by *monitor_id*. If a *scope* is given your
mute will just apply to that scope. You can give an *end* argument that
is a POSIX timestamp of when the mute should stop.

>>> dog_http_api.mute_monitor(1234, scope='env:staging')
"""
body = {}
if scope:
body['scope'] = scope
if end:
body['end'] = end
return self.http_request('POST', '/monitor/%s/mute' % monitor_id, body)

def unmute_monitor(self, monitor_id, scope=None):
"""
Unmute the monitor identified by *monitor_id*. If a *scope* is given
your unmute will just apply to that scope.

>>> dog_http_api.unmute_monitors(1234, scope='env:staging')
"""
body = {}
if scope:
body['scope'] = scope
return self.http_request('POST', '/monitor/%s/unmute' % monitor_id, body)


class DowntimeApi(object):

def schedule_downtime(self, scope, start, end=None):
"""
Schedule downtime over *scope* from *start* to *end*, where *start* and
*end* are POSIX timestamps. If *end* is omitted then the downtime will
continue until cancelled.
"""
body = {
'scope': scope,
'start': start,
}
if end:
body['end'] = end
return self.http_request('POST', '/downtime', body,
response_formatter=lambda x: x['id'],
)

def get_downtime(self, downtime_id):
"""
Get the downtime identified by *downtime_id*
"""
return self.http_request('GET', '/downtime/%s' % downtime_id)

def cancel_downtime(self, downtime_id):
"""
Cancel the downtime identified by *downtime_id*
"""
return self.http_request('DELETE', '/downtime/%s' % downtime_id)

def get_all_downtimes(self, current_only=False):
"""
List all scheduled downtimes.
"""
params = {}
if current_only:
params['current_only'] = True
return self.http_request('GET', '/downtime', **params)
29 changes: 29 additions & 0 deletions src/dogapi/http/service_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
__all__ = [
'ServiceCheckApi',
]

import logging
import time
from dogapi.constants import CheckStatus
from dogapi.exceptions import ApiError

logger = logging.getLogger('dd.dogapi')


class ServiceCheckApi(object):
def service_check(self, check, host, status, timestamp=None, message=None, tags=None):
if status not in CheckStatus.ALL:
raise ApiError('Invalid status, expected one of: %s' \
% ', '.join(CheckStatus.ALL))

body = {
'check': check,
'host_name': host,
'timestamp': timestamp or time.time(),
'status': status
}
if message:
body['message'] = message
if tags:
body['tags'] = tags
return self.http_request('POST', '/check_run', body)
Loading