Source code for dyn.tm.services.active_failover

# -*- coding: utf-8 -*-
from dyn.compat import force_unicode
from dyn.tm.utils import Active
from dyn.tm.errors import DynectInvalidArgumentError
from dyn.tm.session import DynectSession
from dyn.tm.task import Task

__author__ = 'jnappi'
__all__ = ['HealthMonitor', 'ActiveFailover']


[docs]class HealthMonitor(object): """A health monitor for an :class:`ActiveFailover` service"""
[docs] def __init__(self, protocol, interval, retries=None, timeout=None, port=None, path=None, host=None, header=None, expected=None): """Create a :class:`HealthMonitor` object :param protocol: The protocol to monitor. Must be either HTTP, HTTPS, PING, SMTP, or TCP :param interval: How often (in minutes) to run this :class:`HealthMonitor`. Must be 1, 5, 10, or 15, :param retries: The number of retries the monitor attempts on failure before giving up :param timeout: The amount of time in seconds before the connection attempt times out :param port: For HTTP(S)/SMTP/TCP probes, an alternate connection port :param path: For HTTP(S) probes, a specific path to request :param host: For HTTP(S) probes, a value to pass in to the Host :param header: For HTTP(S) probes, additional header fields/values to pass in, separated by a newline character. :param expected: For HTTP(S) probes, a string to search for in the response. For SMTP probes, a string to compare the banner against. Failure to find this string means the monitor will report a down status. """ super(HealthMonitor, self).__init__() self._protocol = protocol self._interval = interval self._retries = retries self._timeout = timeout self._port = port self._path = path self._host = host self._header = header self._expected = expected self.zone = None self.fqdn = None self.valid_protocols = ('HTTP', 'HTTPS', 'PING', 'SMTP', 'TCP') self.valid_intervals = (1, 5, 10, 15) self.valid_timeouts = (10, 15, 25, 30)
[docs] def to_json(self): """Convert this :class:`HealthMonitor` object to a JSON blob""" json_blob = {'protocol': self.protocol, 'interval': self.interval} for key, val in self.__dict__.items(): if val is not None and not hasattr(val, '__call__') and \ key.startswith('_'): json_blob[key[1:]] = val return json_blob
def __eq__(self, other): """eq override for comparing :class:`HealthMonitor` objects to JSON response hashes or other :class:`DNSSECKey` instances :param other: the value to compare this :class:`HealthMonitor` to. Valid input types: `dict`, :class:`HealthMonitor` """ if isinstance(other, dict): return False elif isinstance(other, HealthMonitor): return False else: return False @property def status(self): """Get the current status of this :class:`HealthMonitor` from the DynECT System """ api_args = {} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) respnose = DynectSession.get_session().execute(uri, 'GET', api_args) return respnose['data']['status'] @property def protocol(self): """The protocol to monitor""" return self._protocol @protocol.setter def protocol(self, value): if value not in self.valid_protocols: raise Exception self._protocol = value api_args = {'monitor': {'protocol': self._protocol}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def interval(self): """How often to run this monitor""" return self._interval @interval.setter def interval(self, value): if value not in self.valid_intervals: raise Exception self._interval = value api_args = {'monitor': {'interval': self._interval}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def retries(self): """The number of retries the monitor attempts on failure before giving up """ return self._retries @retries.setter def retries(self, value): self._retries = value api_args = {'monitor': {'retries': self._retries}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def timeout(self): """The amount of time in seconds before the connection attempt times out """ return self._timeout @timeout.setter def timeout(self, value): self._timeout = value api_args = {'monitor': {'timeout': self._timeout}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def port(self): """For HTTP(S)/SMTP/TCP probes, an alternate connection port""" return self._port @port.setter def port(self, value): self._port = value api_args = {'monitor': {'port': self._port}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def path(self): """For HTTP(S) probes, a specific path to request""" return self._path @path.setter def path(self, value): self._path = value api_args = {'monitor': {'path': self._path}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def host(self): """For HTTP(S) probes, a value to pass in to the Host""" return self._host @host.setter def host(self, value): self._host = value api_args = {'monitor': {'host': self._host}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def header(self): """For HTTP(S) probes, additional header fields/values to pass in, separated by a newline character """ return self._header @header.setter def header(self, value): self._header = value api_args = {'monitor': {'header': self._header}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) @property def expected(self): """For HTTP(S) probes, a string to search for in the response. For SMTP probes, a string to compare the banner against. Failure to find this string means the monitor will report a down status """ return self._expected @expected.setter def expected(self, value): self._expected = value api_args = {'monitor': {'expected': self._expected}} uri = '/Failover/{}/{}/'.format(self.zone, self.fqdn) DynectSession.get_session().execute(uri, 'PUT', api_args) def __str__(self): """str override""" return force_unicode('<HealthMonitor>: {}').format(self._protocol) __repr__ = __unicode__ = __str__ def __bytes__(self): """bytes override""" return bytes(self.__str__())
[docs]class ActiveFailover(object): """With Active Failover, we monitor your Primary IP. If a failover event is detected, our system auto switches (hot swaps) to your dedicated back-up IP """
[docs] def __init__(self, zone, fqdn, *args, **kwargs): """Create a new :class:`ActiveFailover` object :param zone: The zone to attach this :class:`ActiveFailover` service to :param fqdn: The FQDN where this :class:`ActiveFailover` service will be attached :param address: IPv4 Address or FQDN being monitored by this :class:`ActiveFailover` service :param failover_mode: Indicates the target failover resource type. :param failover_data: The IPv4 Address or CNAME data for the failover target :param auto_recover: Indicates whether this service should restore its original state when the source IPs resume online status :param notify_events: A comma separated list of what events trigger notifications :param syslog_server: The Hostname or IP address of a server to receive syslog notifications on monitoring events :param syslog_port: The port where the remote syslog server listens :param syslog_ident: The ident to use when sending syslog notifications :param syslog_facility: The syslog facility to use when sending syslog notifications :param syslog_delivery: The syslog delivery action type. 'all' will deliver notifications no matter what the endpoint state. 'change' (default) will deliver only on change in the detected endpoint state :param monitor: The :class:`HealthMonitor` for this :class:`ActiveFailover` service :param contact_nickname: Name of contact to receive notifications from this :class:`ActiveFailover` service :param ttl: Time To Live in seconds of records in the service. Must be less than 1/2 of the Health Probe's monitoring interval :param syslog_probe_fmt: see below for format: :param syslog_status_fmt: see below for format: Use the following format for syslog_xxxx_fmt paramaters. %hos hostname %tim current timestamp or monitored interval %reg region code %sta status %ser record serial %rda rdata %sit monitoring site %rti response time %msg message from monitoring %adr address of monitored node %med median value %rts response times (RTTM) :param recovery_delay: number of up status polling intervals to consider service up """ super(ActiveFailover, self).__init__() self.valid_notify_events = ('ip', 'svc', 'nosrv') self._zone = zone self._fqdn = fqdn self._address = self._failover_mode = self._failover_data = None self._monitor = self._active = None self._contact_nickname = self._auto_recover = None self._notify_events = self._syslog_server = self._syslog_port = None self._syslog_ident = self._syslog_probe_fmt = None self._syslog_status_fmt = self._syslog_facility = self._ttl = None self._syslog_delivery = self._recovery_delay = None self.uri = '/Failover/{}/{}/'.format(self._zone, self._fqdn) self.api_args = {} if 'api' in kwargs: del kwargs['api'] self._build(kwargs) elif len(args) == 0 and len(kwargs) == 0: self._get() else: self._post(*args, **kwargs)
def _get(self): """Build an object around an existing DynECT Active Failover Service""" api_args = {} response = DynectSession.get_session().execute(self.uri, 'GET', api_args) self._build(response['data']) def _post(self, address, failover_mode, failover_data, monitor, contact_nickname, auto_recover=None, notify_events=None, syslog_server=None, syslog_port=None, syslog_ident=None, syslog_facility=None, ttl=None, syslog_probe_fmt=None, syslog_status_fmt=None, syslog_delivery=None, recovery_delay=None): """Create a new Active Failover Service on the DynECT System""" self._address = address self._failover_mode = failover_mode self._failover_data = failover_data self._monitor = monitor self._monitor.zone = self._zone self._monitor.fqdn = self._fqdn self._contact_nickname = contact_nickname self._auto_recover = auto_recover self._notify_events = notify_events self._syslog_server = syslog_server self._syslog_port = syslog_port self._syslog_ident = syslog_ident self._syslog_facility = syslog_facility self._syslog_delivery = syslog_delivery self._syslog_probe_fmt = syslog_probe_fmt self._syslog_status_fmt = syslog_status_fmt self._recovery_delay = recovery_delay self._ttl = ttl self.api_args = {'address': self._address, 'failover_mode': self._failover_mode, 'failover_data': self._failover_data, 'monitor': self.monitor.to_json(), 'contact_nickname': self._contact_nickname} if syslog_probe_fmt: self.api_args['syslog_probe_fmt'] = self._syslog_probe_fmt if syslog_status_fmt: self.api_args['syslog_status_fmt'] = self._syslog_status_fmt if recovery_delay: self.api_args['recovery_delay'] = self._recovery_delay if syslog_facility: self.api_args['syslog_facility'] = self._syslog_facility if syslog_delivery: self.api_args['syslog_delivery'] = self._syslog_delivery if syslog_ident: self.api_args['syslog_ident'] = self._syslog_ident if notify_events: self.api_args['notify_events'] = self._notify_events if syslog_server: self.api_args['syslog_server'] = self._syslog_server if syslog_port: self.api_args['syslog_port'] = self._syslog_port response = DynectSession.get_session().execute(self.uri, 'POST', self.api_args) self._build(response['data']) def _build(self, data): """Build this object from the data returned in an API response""" self._task_id = None for key, val in data.items(): if key == 'monitor': self._monitor = HealthMonitor(**val) elif key == 'active': self._active = Active(val) elif key == "task_id" and not val: self._task_id = None elif key == "task_id": self._task_id = Task(val) else: setattr(self, '_' + key, val) def _update(self, api_args): """Update this :class:`ActiveFailover`, via the API, with the args in api_args """ response = DynectSession.get_session().execute(self.uri, 'PUT', api_args) self._build(response['data']) @property def task(self): """:class:`Task` for most recent system action on this :class:`ActiveFailover`.""" if self._task_id: self._task_id.refresh() return self._task_id @property def zone(self): """The zone to attach this :class:`ActiveFailover` service to""" return self._zone @zone.setter def zone(self, value): pass @property def fqdn(self): """The FQDN where this :class:`ActiveFailover` service will be attached """ return self._fqdn @fqdn.setter def fqdn(self, value): pass @property def active(self): """Return whether or not this :class:`ActiveFailover` service is active. When setting directly, rather than using activate/deactivate valid arguments are 'Y' or True to activate, or 'N' or False to deactivate. Note: If your service is already active and you try to activate it, nothing will happen. And vice versa for deactivation. :returns: An :class:`Active` object representing the current state of this :class:`ActiveFailover` Service """ self._get() return self._active @active.setter def active(self, value): deactivate = ('N', False) activate = ('Y', True) if value in deactivate and self.active: self.deactivate() elif value in activate and not self.active: self.activate() @property def address(self): """IPv4 Address or FQDN being monitored by this :class:`ActiveFailover` service """ return self._address @address.setter def address(self, value): self._address = value api_args = {'address': self._address, 'failover_mode': self._failover_mode, 'failover_data': self._failover_data, 'monitor': self.monitor.to_json(), 'contact_nickname': self._contact_nickname} self._update(api_args) @property def failover_mode(self): """Indicates the target failover resource type.""" return self._failover_mode @failover_mode.setter def failover_mode(self, value): self._failover_mode = value self.api_args['failover_mode'] = self._failover_mode self._update(self.api_args) @property def failover_data(self): """The IPv4 Address or CNAME data for the failover target""" return self._failover_data @failover_data.setter def failover_data(self, value): self._failover_data = value self.api_args['failover_data'] = self._failover_data self._update(self.api_args) @property def monitor(self): """The :class:`HealthMonitor` for this :class:`ActiveFailover` service """ return self._monitor @monitor.setter def monitor(self, value): self._monitor = value self.api_args['monitor'] = self._monitor.to_json() self._update(self.api_args) @property def contact_nickname(self): """Name of contact to receive notifications from this :class:`ActiveFailover` service """ return self._contact_nickname @contact_nickname.setter def contact_nickname(self, value): self._contact_nickname = value self.api_args['contact_nickname'] = self._contact_nickname self._update(self.api_args) @property def auto_recover(self): """Indicates whether this service should restore its original state when the source IPs resume online status """ return self._auto_recover @auto_recover.setter def auto_recover(self, value): self._auto_recover = value api_args = self.api_args api_args['auto_recover'] = self._auto_recover self._update(api_args) @property def notify_events(self): """A comma separated list of what events trigger notifications""" return self._notify_events @notify_events.setter def notify_events(self, value): for val in value: if val not in self.valid_notify_events: raise DynectInvalidArgumentError('notify_events', val, self.valid_notify_events) value = ','.join(value) api_args = self.api_args api_args['notify_events'] = value self._update(api_args)
[docs] def recover(self): """Recover this :class:`ActiveFailover` service""" api_args = {'recover': 'Y'} self._update(api_args)
@property def syslog_server(self): """The Hostname or IP address of a server to receive syslog notifications on monitoring events """ self._get() return self._syslog_server @syslog_server.setter def syslog_server(self, value): self._syslog_server = value api_args = self.api_args api_args['syslog_server'] = self._syslog_server self._update(api_args) @property def syslog_port(self): """The port where the remote syslog server listens""" self._get() return self._syslog_port @syslog_port.setter def syslog_port(self, value): self._syslog_port = value api_args = self.api_args api_args['syslog_port'] = self._syslog_port self._update(api_args) @property def syslog_ident(self): """The ident to use when sending syslog notifications""" self._get() return self._syslog_ident @syslog_ident.setter def syslog_ident(self, value): self._syslog_ident = value api_args = self.api_args api_args['syslog_ident'] = self._syslog_ident self._update(api_args) @property def syslog_facility(self): """The syslog facility to use when sending syslog notifications""" self._get() return self._syslog_facility @syslog_facility.setter def syslog_facility(self, value): self._syslog_facility = value api_args = self.api_args api_args['syslog_facility'] = self._syslog_facility self._update(api_args) @property def syslog_delivery(self): self._get() return self._syslog_delivery @syslog_delivery.setter def syslog_delivery(self, value): api_args = {'syslog_delivery': value} self._update(api_args) @property def syslog_probe_format(self): self._get() return self._syslog_probe_fmt @syslog_probe_format.setter def syslog_probe_format(self, value): api_args = {'syslog_probe_fmt': value} self._update(api_args) @property def syslog_status_format(self): self._get() return self._syslog_status_fmt @syslog_status_format.setter def syslog_status_format(self, value): api_args = {'syslog_status_fmt': value} self._update(api_args) @property def recovery_delay(self): self._get() return self._recovery_delay @recovery_delay.setter def recovery_delay(self, value): api_args = {'recovery_delay': value} self._update(api_args) @property def ttl(self): """Time To Live in seconds of records in the service. Must be less than 1/2 of the Health Probe's monitoring interval """ return self._ttl @ttl.setter def ttl(self, value): self._ttl = value api_args = self.api_args api_args['ttl'] = self._ttl self._update(api_args)
[docs] def activate(self): """Activate this :class:`ActiveFailover` service""" api_args = {'activate': True} self._update(api_args)
[docs] def deactivate(self): """Deactivate this :class:`ActiveFailover` service""" api_args = {'deactivate': True} self._update(api_args)
[docs] def delete(self): """Delete this :class:`ActiveFailover` service from the Dynect System """ api_args = {} DynectSession.get_session().execute(self.uri, 'DELETE', api_args)
def __str__(self): """str override""" return force_unicode('<ActiveFailover>: {}').format(self._fqdn) __repr__ = __unicode__ = __str__ def __bytes__(self): """bytes override""" return bytes(self.__str__())