def _getSession(self, content): traphost = content['action_destination'] port = content['port'] destination = '%s:%s' % (traphost, port) if not traphost or port <= 0: log.error("%s: SNMP trap host information %s is incorrect ", destination) return None community = content['community'] version = content['version'] session = self._sessions.get(destination, None) if session is None: log.debug("Creating SNMP trap session to %s", destination) # Test that the hostname and port are sane. try: getaddrinfo(traphost, port) except Exception: raise ActionExecutionException( "The destination %s is not resolvable." % destination) session = netsnmp.Session( ('-%s' % version, '-c', community, destination)) session.open() self._sessions[destination] = session return session
def executeBatch(self, notification, signal, targets): log.debug("Executing %s action for targets: %s", self.name, targets) self.setupAction(notification.dmd) data = _signalToContextDict(signal, self.options.get('zopeurl'), notification, self.guidManager) if signal.clear: log.debug('This is a clearing signal.') subject = processTalSource(notification.content['clear_subject_format'], **data) body = processTalSource(notification.content['clear_body_format'], **data) else: subject = processTalSource(notification.content['subject_format'], **data) body = processTalSource(notification.content['body_format'], **data) log.debug('Sending this subject: %s' % subject) log.debug('Sending this body: %s' % body) plain_body = MIMEText(self._stripTags(body)) email_message = plain_body if notification.content['body_content_type'] == 'html': email_message = MIMEMultipart('related') email_message_alternative = MIMEMultipart('alternative') email_message_alternative.attach(plain_body) html_body = MIMEText(body.replace('\n', '<br />\n')) html_body.set_type('text/html') email_message_alternative.attach(html_body) email_message.attach(email_message_alternative) host = notification.content['host'] port = notification.content['port'] user = notification.content['user'] password = notification.content['password'] useTls = notification.content['useTls'] email_from = notification.content['email_from'] email_message['Subject'] = subject email_message['From'] = email_from email_message['To'] = ','.join(targets) email_message['Date'] = formatdate(None, True) result, errorMsg = sendEmail( email_message, host, port, useTls, user, password ) if result: log.debug("Notification '%s' sent emails to: %s", notification.id, targets) else: raise ActionExecutionException( "Notification '%s' FAILED to send emails to %s: %s" % (notification.id, targets, errorMsg) )
def executeOnTarget(self, notification, signal, target): self.setupAction(notification.dmd) log.debug('Executing action: %s on %s', self.name, target) if signal.clear: command = notification.content['clear_body_format'] else: command = notification.content['body_format'] log.debug('Executing this command: %s', command) actor = signal.event.occurrence[0].actor device = None if actor.element_uuid: device = self.guidManager.getObject(actor.element_uuid) component = None if actor.element_sub_uuid: component = self.guidManager.getObject(actor.element_sub_uuid) user_env_format = notification.content['user_env_format'] env = dict( envvar.split('=') for envvar in user_env_format.split(';') if '=' in envvar) environ = {'dev': device, 'component': component, 'dmd': notification.dmd, 'env': env} data = _signalToContextDict(signal, self.options.get('zopeurl'), notification, self.guidManager) environ.update(data) if environ.get('evt', None): environ['evt'] = self._escapeEvent(environ['evt']) if environ.get('clearEvt', None): environ['clearEvt'] = self._escapeEvent(environ['clearEvt']) environ['user'] = getattr(self.dmd.ZenUsers, target, None) try: command = processTalSource(command, **environ) except Exception: raise ActionExecutionException('Unable to perform TALES evaluation on "%s" -- is there an unescaped $?' % command) log.debug('Executing this compiled command: "%s"' % command) _protocol = EventCommandProtocol(command) log.debug('Queueing up command action process.') self.processQueue.queueProcess( '/bin/sh', ('/bin/sh', '-c', command), env=environ['env'], processProtocol=_protocol, timeout=int(notification.content['action_timeout']), timeout_callback=_protocol.timedOut )
def _processTalExpression(self, value, environ): if type(value) is str or type(value) is unicode: if '${' not in value: return value try: return processTalSource(value, **environ) except Exception: raise ActionExecutionException( 'Unable to perform TALES evaluation on "%s" -- is there an unescaped $?' % value) else: return value
def processEventFields(self, data, content, name): log.debug('[research] process TAL expressions') try: content = processTalSource(content, **data) log.debug('[research] %s : %s' % (name, content)) except Exception: log.debug('[research] unable to process : %s' % (name)) raise ActionExecutionException( '[research] failed to process TAL in %s' % (name)) if (content == 'None'): content = '' return content
def _performRequest(self, body, environ): """ Actually performs the request to PagerDuty's Event API. Raises: ActionExecutionException: Some error occurred while contacting PagerDuty's Event API (e.g., API down, invalid service key). """ bodyWithProcessedTalesExpressions = self._processTalExpressions( body, environ) bodyWithProcessedTalesExpressions['payload'][ 'severity'] = EVENT_MAPPING[ bodyWithProcessedTalesExpressions['payload']['severity']] requestBody = json.dumps(bodyWithProcessedTalesExpressions) headers = {'Content-Type': 'application/json'} req = urllib2.Request(EVENT_API_URI, requestBody, headers) try: # bypass default handler SVC-1819 opener = urllib2.build_opener() f = opener.open(req, None, API_TIMEOUT_SECONDS) except urllib2.URLError as e: if hasattr(e, 'reason'): msg = 'Failed to contact the PagerDuty server: %s' % (e.reason) raise ActionExecutionException(msg) elif hasattr(e, 'code'): msg = 'The PagerDuty server couldn\'t fulfill the request: HTTP %d (%s)' % ( e.code, e.msg) raise ActionExecutionException(msg) else: raise ActionExecutionException('Unknown URLError occurred') response = f.read() log.debug('PagerDuty response: %s', response) f.close()
def execute(self, notification, signal): """ Sets up the execution environment and POSTs to PagerDuty's Event API. """ log.debug('Executing Pagerduty Events API action: %s', self.name) self.setupAction(notification.dmd) if signal.clear: eventType = EventType.RESOLVE elif signal.event.status == STATUS_ACKNOWLEDGED: eventType = EventType.ACKNOWLEDGE else: eventType = EventType.TRIGGER # Set up the TALES environment environ = {'dmd': notification.dmd, 'env': None} actor = signal.event.occurrence[0].actor device = None if actor.element_uuid: device = self.guidManager.getObject(actor.element_uuid) environ.update({'dev': device}) component = None if actor.element_sub_uuid: component = self.guidManager.getObject(actor.element_sub_uuid) environ.update({'component': component}) data = _signalToContextDict(signal, self.options.get('zopeurl'), notification, self.guidManager) environ.update(data) try: detailsList = json.loads(notification.content['details']) except ValueError: raise ActionExecutionException('Invalid JSON string in details') details = dict() for kv in detailsList: details[kv['key']] = kv['value'] details['zenoss'] = { 'version': ZENOSS_VERSION, 'zenpack_version': zenpack_version(), } payload = { 'severity': '${evt/severity}', 'class': '${evt/eventClass}', 'custom_details': details, } body = { 'event_action': eventType, 'dedup_key': data['evt'].evid, 'payload': payload } for prop in REQUIRED_PROPERTIES: if prop in notification.content: payload.update({prop: notification.content[prop]}) else: raise ActionExecutionException( "Required property '%s' not found" % prop) if NotificationProperties.SERVICE_KEY in notification.content: body.update({'routing_key': notification.content['serviceKey']}) else: raise ActionExecutionException( "API Key for PagerDuty service was not found. " "Did you configure a notification correctly?") self._performRequest(body, environ)