def _eventit(self, agent, data): """Send a read-only password event failed/okay event if the user has done setup with a chance to configure one and appropriate.""" # user '0', likely 'palette' entry = UserProfile.get(self.server.environment.envid, 0) # Potentially send an event only after the user has # finished with the "Setup" page (the passowrd will then be # there). if not entry.hashed_password: return notification = self.server.notifications.get("dbreadonly") if success(data): if notification.color == 'red': adata = agent.todict() self.server.event_control.gen( EventControl.READONLY_DBPASSWORD_OKAY, adata) notification.modification_time = func.now() notification.color = 'green' notification.description = None meta.Session.commit() else: # Failed if notification.color != 'red': if data['error'].find( "A password is required for this connection.") != -1 or \ data['error'].find(agent.odbc.READONLY_ERROR_TEXT) \ != -1 or \ data['error'].find("password authentication failed") != -1: adata = agent.todict() self.server.event_control.gen( EventControl.READONLY_DBPASSWORD_FAILED, adata) notification.modification_time = func.now() notification.color = 'red' notification.description = None meta.Session.commit() return
def send(self, event_entry, data, recipient=None, eventid=None): """Send an alert. Arguments: key: The key to look up. data: A Dictionary with the event information. """ # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements # pylint: disable=too-many-return-statements subject = event_entry.email_subject if subject == None: subject = event_entry.subject if subject.find("%") != -1: # Use the data dict for template substitution. try: subject = subject % data except (ValueError, KeyError) as ex: subject = "Email Template subject conversion failure: " + \ str(ex) + \ "subject: " + subject + \ ", data: " + str(data) message = event_entry.email_message if message: try: mako_template = Template(message) message = mako_template.render(**data) except StandardError: message = "Email mako template message conversion failure: " + \ exceptions.text_error_template().render() + \ "\ntemplate: " + message + \ "\ndata: " + str(data) else: message = self.make_default_message(event_entry, subject, data) if not message: # message is empty, set it to be the subject message = subject if recipient: # Force to only one test recipient. # It is sent even if alerts are disabled. to_emails = [recipient] else: if not self.system[SystemKeys.ALERTS_ENABLED]: logger.info("Alerts disabled. Not sending: Subject: %s, %s", subject, message) return to_emails = [] if event_entry.publisher_visibility: to_emails = self.publisher_email(data) if event_entry.admin_visibility: to_emails += self.admin_emails(event_entry) # Remove any duplicates to_emails = list(set(to_emails)) bcc = None if self.system[SystemKeys.ALERTS_ADMIN_ENABLED] and not recipient: # Get the diagnostics email and bcc it there if it exists. entry = UserProfile.get(self.envid, 0) if entry and entry.email != None and entry.email != "": bcc = [entry.email] if not to_emails and not bcc: logger.debug( "No admin users exist with enabled email addresses. " "Not sending: Subject: %s, Message: %s", subject, message) return # Send only PHONE-HOME related events if their palette license # has expired. if event_entry.key not in [ EventControl.PHONE_HOME_FAILED, EventControl.PHONE_HOME_OK, EventControl.EMAIL_TEST ]: entry = Domain.getone() if entry.expiration_time and \ datetime.utcnow() > entry.expiration_time: logger.debug( "License expired. " + "Not sending: Subject: %s, Message: %s", subject, message) return if entry.contact_time: silence_time = (datetime.utcnow() - \ entry.contact_time).total_seconds() max_silence_time = self.system[SystemKeys.MAX_SILENCE_TIME] if silence_time > max_silence_time and max_silence_time != -1: logger.debug( "Phonehome contact time is %d > %d. " + "Not sending: Subject: %s, Message: %s", silence_time, max_silence_time, subject, message) return if self.email_limit_manager.email_limit_reached(event_entry, eventid): return sendit = True # print '\n------------event key is', event_entry.key if self.system[SystemKeys.EMAIL_MUTE_RECONNECT_SECONDS]: # Potentially mute the connect or reconnect emails. if event_entry.key == EventControl.AGENT_DISCONNECT: self._mute_dis_check(data, to_emails, bcc, subject, message) # If the event is emailed, it is done there, # after a delay return elif event_entry.key in [ EventControl.AGENT_COMMUNICATION, EventControl.INIT_STATE_STARTED, EventControl.INIT_STATE_STOPPED, EventControl.INIT_STATE_DEGRADED ]: sendit = self._mute_reconn_check(data) if sendit: self._do_send(to_emails, bcc, subject, message)
def gen(self, key, data=None, userid=None, site_id=None, timestamp=None): # pylint: disable=too-many-arguments # pylint: disable=too-many-locals # pylint: disable=too-many-statements # pylint: disable=too-many-branches """Generate an event. Arguments: key: The key to look up. data: A Dictionary with all of the event information. Recognized keys: - From http response: stdout stderr xid pid exit-status run-status timestamp - Sometimes added: error info - Available from AgentConnection: displayname agent_type uuid auth, which has: hostname ip-address version listen-port install-dir """ if data == None: data = {} if 'enabled' in data and not data['enabled']: logger.debug("Agent is disabled so no event will be " + \ "generated. key: %s, data: %s", key, data) return event_entry = self.get_event_control_entry(key) if event_entry: subject = event_entry.subject event_description = event_entry.event_description else: logger.error("No such event key: %s. data: %s\n", key, str(data)) return # add all system table entries to the data dictionary. data = dict(data.items() + \ self.system.todict(include_defaults=True).items()) logger.debug(key + " DATA: " + str(data)) if 'exit-status' in data: data['exit_status'] = data['exit-status'] del data['exit-status'] # FIXME: remove when browser-aware timezone support is available. if timestamp is None: timestamp = datetime.datetime.now(tz=tz.tzlocal()) logger.debug(key + " timestamp : " + timestamp.strftime(DATEFMT)) data['timestamp'] = timestamp.strftime(DATEFMT) # The userid for other events is the Palette "userid". profile = None if not 'username' in data and userid != None: profile = UserProfile.get(self.envid, userid) if not profile is None: data['username'] = profile.display_name() data['userid'] = profile.userid if profile.email: data['email'] = profile.email if userid: # userid passed to us has higher precedence than any # lookup we did, above. data['userid'] = userid if not 'username' in data: data['username'] = mako.runtime.UNDEFINED data['event_type'] = event_entry.event_type data['event_type_label'] = event_entry.event_type_label data['event_label'] = event_entry.event_label data['event_label_desc'] = event_entry.event_label_desc data['admin_visibility'] = event_entry.admin_visibility data['publisher_visiblity'] = event_entry.publisher_visibility # set server-url(s) data['server_url'] = self.system[SystemKeys.SERVER_URL] url = self.server.public_url() if url: data['tableau_server_url'] = url if not 'environment' in data: data['environment'] = self.server.environment.name if 'site_id' in data and 'site' not in data: site = Site.get_name_by_id(self.envid, data['site_id']) if not site is None: data['site'] = site if 'project_id' in data and 'project' not in data: project = Project.get_name_by_id(self.envid, data['project_id']) if not project is None: data['project'] = project # Create the row to get the eventid before doing subject/description # substitution. session = meta.DBSession() entry = EventEntry(complete=False, key='incomplete') # set the timestamp here in case it has tzinfo. entry.timestamp = timestamp session.add(entry) session.commit() data['eventid'] = entry.eventid # Use the data dict for template substitution. try: subject = subject % data except (ValueError, KeyError) as ex: subject = "Template subject conversion failure: " + str(ex) + \ "subject: " + subject + \ ", data: " + str(data) if event_description: try: mako_template = Template(event_description, default_filters=['h']) event_description = mako_template.render(**data) except MakoException: event_description = \ "Mako template message conversion failure: " + \ exceptions.text_error_template().render() + \ "\ntemplate: " + event_description + \ "\ndata: " + str(data) except TypeError as ex: event_description = \ "Mako template message conversion failure: " + \ str(ex) + \ "\ntemplate: " + event_description + \ "\ndata: " + str(data) else: event_description = self.make_default_description(data) event_description = re.sub("(\n|\r\n){3,}", "\n\n", event_description) if not event_description.endswith("\n"): event_description = event_description + "\n" if self.server.event_debug: event_description = event_description + "--------\n" + str(data) # FIXME: remove when browser-aware timezone support is available. if timestamp.tzinfo is None: # if not timezone is specified, assume UTC. summary = utc2local(timestamp).strftime(DATEFMT) else: summary = timestamp.strftime(DATEFMT) # Log the event to the database entry.complete = True entry.key = key entry.envid = self.envid entry.title = subject entry.description = event_description entry.level = event_entry.level entry.icon = event_entry.icon entry.color = event_entry.color entry.event_type = event_entry.event_type entry.summary = summary entry.userid = userid entry.site_id = site_id #entry.timestamp = timestamp session.merge(entry) session.commit() if not event_entry.send_email: return try: self.alert_email.send(event_entry, data, eventid=entry.eventid) except StandardError: exc_traceback = sys.exc_info()[2] tback = ''.join(traceback.format_tb(exc_traceback)) report = "Error: %s. Traceback: %s" % (sys.exc_info()[1], tback) logger.error( "alert_email: Failed for event '%s', '" "data '%s'. Will not send email. %s", event_entry.key, str(data), report)