Ejemplo n.º 1
0
    def report_duplicates(self):
        """
        Send a report on duplicate name+language+dictionary mappings.
        """

        if not self.dups:
            self.logger.error("no duplicates to report")
            return
        if self.recip:
            recips = [self.recip]
        else:
            recips = Job.get_group_email_addresses("GlossaryDupGroup")
        if not recips:
            raise Exception("no recipients found for glossary dup message")
        body = ["The following {:d} sets of ".format(len(self.dups)),
                "duplicate glossary mappings were found in the CDR ",
                "on {}. ".format(self.SERVER.upper()),
                "Mappings for any phrase + language + dictionary must ",
                "be unique. ",
                "Please correct the data so that this requirement is met. ",
                "You may need to look at the External Map Table for ",
                "Glossary Terms to find some of the mappings.\n"]
        template = "\n{} (language={!r} dictionary={!r})\n"
        for key in sorted(self.dups):
            name, language, dictionary = key
            args = name.upper(), language, dictionary
            body.append(template.format(*args))
            for doc_id in self.dups[key]:
                body.append("\tCDR{:010d}\n".format(doc_id))
        body = "".join(body)
        opts = dict(subject=self.SUBJECT, body=body)
        message = cdr.EmailMessage(self.SENDER, recips, **opts)
        message.send()
        self.logger.info("duplicate mapping notification sent to %r", recips)
Ejemplo n.º 2
0
    def send_report(self, report):
        """
        Email the report to the right recipient list.

        report    Serialized HTML document for the report.
        """

        if self.recip:
            recips = [self.recip]
        else:
            if self.test:
                group = "Test Publishing Notification"
            else:
                group = {
                    "spanish": "GovDelivery ES Docs Notification",
                    "english": "GovDelivery EN Docs Notification",
                    "trials": "GovDelivery Trials Notification"
                }.get(self.key)
                recips = Job.get_group_email_addresses(group)
        if recips:
            subject = "[%s] %s" % (self.TIER.name, self.title)
            opts = dict(subject=subject, body=report, subtype="html")
            message = cdr.EmailMessage(self.SENDER, recips, **opts)
            message.send()
            self.logger.info("sent %s", subject)
            self.logger.info("recips: %s", ", ".join(recips))
        else:
            self.logger.error("no email recipients for %s", group)
Ejemplo n.º 3
0
    def send_report(self, jobs):
        """
        Send weekly report of new translation jobs to lead translator

        Pass:
          Sequence of tuples of values
        """

        report = self.create_report(jobs)
        self.logger.debug("report\n%s", report)
        if self.recip:
            recips = [self.recip]
        else:
            group = "Spanish Translation Leads"
            if self.test:
                group = "Test Translation Queue Recips"
            recips = Job.get_group_email_addresses(group)
        if recips:
            subject = "[%s] %s" % (cdr.Tier().name, self.title)
            opts = dict(subject=subject, body=report, subtype="html")
            message = cdr.EmailMessage(self.SENDER, recips, **opts)
            message.send()
            self.logger.info("sent %s", subject)
            self.logger.info("recips: %s", ", ".join(recips))
        else:
            self.logger.error("no email recipients for %s", group)
Ejemplo n.º 4
0
 def check(self):
     problems = []
     for tier in self.TIERS:
         try:
             server = self.Server(tier)
         except Exception as e:
             self.logger.exception("failure checking %s", tier)
             problem = f"failure checking {tier}: {e}"
             problems.append(problem)
             continue
         for drive in sorted(server.free):
             free = server.free[drive]
             if free.bytes < self.thresholds[drive] * self.GB:
                 amount = f"{free.bytes} bytes {free.human}"
                 args = drive, server.name, amount
                 problem = "{}: drive on {} server down to {}".format(*args)
                 self.logger.warning(problem)
                 problems.append(problem)
     if problems:
         subject = "*** WARNING: CDR DISK SPACE CHECK ***"
         opts = dict(subject=subject, body="\n".join(problems))
         message = cdr.EmailMessage(self.FROM, self.recips, **opts)
         message.send()
         self.logger.info("sent alert to %s", ", ".join(self.recips))
     else:
         self.logger.info("disk space OK")
Ejemplo n.º 5
0
    def send(self, recips, subject, message):
        """
        Send an email message, trying multiple times before giving up.

        We pause between attempts in order to avoid flooding the NIH
        mail server with too many requests at the same time.

        Note that the `recips` argument will always be a sequence
        of addresses when we are sending internal messages reporting
        processing to the operators, and will always be a single
        string when sending the notification to an individual data
        partner contact. This is why the checks which prevent sending
        out email messages to outside data partners from non-production
        tiers works correctly.

        Pass:
            recips - string (for partner contact) or list of strings (for ops)
            subject - string for message's subject header
            message - string for message body

        Raise:
            exception propagated by sendmail if too many attempts fail
        """

        if isinstance(recips, str):
            if not cdr.isProdHost() or self.test:
                extra = "In live prod mode, would have gone to %r" % recips
                if Notify.test_recips is None:
                    if self.recip:
                        Notify.test_recips = [self.recip]
                    else:
                        group = "Test Publishing Notification"
                        test_recips = self.get_group_email_addresses(group)
                        Notify.test_recips = test_recips
                recips = Notify.test_recips
                self.logger.info("using recips: %r", recips)
                message = "<h3>%s</h3>\n%s" % (html_escape(extra), message)
            else:
                recips = [recips]
        tries, delay = 0, self.DELAY
        while True:
            self.logger.debug("top of send(%r)", recips)
            try:
                opts = dict(subject=subject, body=message, subtype="html")
                msg = cdr.EmailMessage(self.SENDER, recips, **opts)
                msg.send()
                msg = str(msg)
                if self.log_messages:
                    self.logger.debug(msg)
                return msg
            except Exception as e:
                self.logger.exception("failure sending to %r", recips)
                tries += 1
                if tries >= self.MAX_TRIES:
                    self.logger.error("bailing after %d tries", self.MAX_TRIES)
                    raise
                self.logger.debug("pausing %s seconds", delay)
                time.sleep(delay)
                delay += self.DELAY
Ejemplo n.º 6
0
 def run(self):
     self.logger.info("started")
     try:
         self.check()
     except Exception as e:
         self.logger.exception("failure")
         opts = dict(subject="DISK CHECK FAILURE", body=str(e))
         message = cdr.EmailMessage(self.FROM, self.recips, **opts)
         message.send()
Ejemplo n.º 7
0
def sendFailureMessage(header="*** Error ***", body=""):
    emailDL = cdr.getEmailList('Test Publishing Notification')
    subject = header
    if not body:
        body = """
The publishing job failed.  Please check the log files.
"""
    opts = dict(subject=subject, body=body)
    cdr.EmailMessage(cdr.OPERATOR, emailDL, **opts).send()

    return
Ejemplo n.º 8
0
def fatalError(msg):
    """
    Log and display error message.
    Then exit.

    Pass:
        Error message.
    """
    global recips, TIER

    # Add message to log file
    msg = "FATAL error: %s\n" %msg
    FS_LOGGER.error(msg)

    # Send mail to recipients from command line or registered group
    sender = '*****@*****.**'
    if not recips:
        try:
            group = "FileSweeper Error Notification"
            recips = CDRTask.get_group_email_addresses(group)
        except Exception as e:
            FS_LOGGER.exception("Getting email recipients from the CDR")

    # Message subject
    subject = "FileSweeper failed on %s tier" % TIER

    # Body
    errorBody = """
The CDR FileSweeper failed on %s at %s.

Error message was:
   %s
""" % (TIER, time.ctime(), msg)

    # Send it
    mailSent = False
    if recips:
        try:
            opts = dict(subject=subject, body=errorBody)
            cdr.EmailMessage(sender, recips, **opts).send()
            mailSent = True
        except Exception as e:
            FS_LOGGER.exception("Attempting to send mail for fatal error")

    if mailSent:
        FS_LOGGER.info("Mail sent to: %s", recips)
    else:
        FS_LOGGER.info("No mail sent")

    raise Exception(errorBody)
Ejemplo n.º 9
0
 def send_report(self, control):
     report = self.create_report(control)
     control.logger.debug("report\n%s", report)
     if self.recip:
         recips = [self.recip]
     elif control.test:
         group = "Test Translation Queue Recips"
         recips = Job.get_group_email_addresses(group)
     else:
         recips = [self.email]
     if recips:
         subject = "[%s] %s" % (cdr.Tier().name, control.title)
         opts = dict(subject=subject, body=report, subtype="html")
         message = cdr.EmailMessage(self.SENDER, recips, **opts)
         message.send()
         control.logger.info("sent %s", subject)
         control.logger.info("recips: %s", ", ".join(recips))
     else:
         control.logger.error("no email recipients for %s", group)
Ejemplo n.º 10
0
    def send_report(self, report):
        """
        Email the report to the right recipient list.

        report    Serialized HTML document for the report.
        """

        if self.recip:
            recips = [self.recip]
        else:
            if self.test:
                group = "Test Publishing Notification"
            else:
                group = "Licensee Report Notification"
            recips = Job.get_group_email_addresses(group)
        title = "PDQ Distribution Partner List"
        subject = "[%s] %s" % (cdr.Tier().name, title)
        opts = dict(subject=subject, body=report, subtype="html")
        message = cdr.EmailMessage(self.SENDER, recips, **opts)
        message.send()
        self.logger.info("sent %s", subject)
        self.logger.info("recips: %s", ", ".join(recips))
Ejemplo n.º 11
0
    def send(self):
        """
        Send the glossary information to registered Drupal CMS servers
        """

        failures = []
        success = "Sent glossary to server %r at %s"
        failure = "Failure sending glossary to server %r at %s: %s"
        for alias, base in self.servers.items():
            url = "{}/pdq/api/glossifier/refresh".format(base)
            try:
                response = requests.post(url, json=self.data, auth=self.auth)
                if response.ok:
                    self.logger.info(success, alias, base)
                else:
                    args = alias, base, response.reason
                    self.logger.error(failure, *args)
                    failures.append(args)
            except Exception as e:
                args = alias, base, e
                self.logger.exception(failure, *args)
                failures.append(args)
        if failures:
            group = "Developers Notification"
            if self.recip:
                recips = [self.recip]
            else:
                recips = Job.get_group_email_addresses(group)
            if not recips:
                raise Exception("no recips found for glossary failure message")
            tier = self.tier.name
            subject = "[{}] Failure sending glossary information".format(tier)
            lines = []
            for args in failures:
                lines.append("Server {!r} at {}: {}".format(*args))
            body = "\n".join(lines)
            opts = dict(subject=subject, body=body)
            message = cdr.EmailMessage(self.SENDER, recips, **opts)
            self.logger.error("send failure notice sent to %r", recips)
Ejemplo n.º 12
0
    def __sendMail(self):
        try:
            if self.__email:
                self.log("Sending mail to %s" % self.__email)
                sender = MailerJob.__CDR_EMAIL
                subject = "[%s] CDR Mailer Job Status" % self.__TIER.name

                # Specify the hostname based on the environment we're in
                # ------------------------------------------------------
                args = cdr.APPC, "PubStatus.py", self.__id
                url = "https://{}/cgi-bin/cdr/{}?id={:d}".format(*args)

                message = """\
Job %d has completed.  You can view a status report for this job at:

    %s
%s
Please do not reply to this message.
""" % (self.__id, url, self.__letterLink)
                opts = dict(subject=subject, body=message)
                cdr.EmailMessage(sender, [self.__email], **opts).send()
        except:
            self.log("failure sending email to %s: %s" %
                     (self.__email, cdr.exceptionInfo()))
Ejemplo n.º 13
0
    def send_report(self):
        """
        Send the report as an attachment to an email message.
        """

        label = str(self.month)
        book = cdr.EmailAttachment(filepath=self.report_path)
        subject = self.SUBJECT % label
        body = (
            "Attached is the monthly PDQ Distribution Partner report listing "
            "all documents downloaded from the SFTP server for %s.\n" % label,
            "The report is based on the log file provided at",
            "         %s\n" % self.log_path,
            "Please save the attached report to the network directory",
            "         L:\\OCPL\\_CROSS\\CDR\\Reports\\FTP Stats",
            "so the Clinical Trials team can access the information as needed.",
            "",
            "For questions or comments please reply to this email message.")
        body = "\n".join(body)
        recips = self.recips
        opts = dict(subject=subject, body=body, attachments=[book])
        message = cdr.EmailMessage(self.SENDER, recips, **opts)
        message.send()
        self.logger.info("sent report to %s", ", ".join(recips))
Ejemplo n.º 14
0
# ----------------------------------------------
emailDL = sorted(cdr.getEmailList('VOL Notification'))
emailDevs = sorted(cdr.getEmailList("Developers Notification"))
if not len(emailDL) or testMode:
    recips = emailDevs
else:
    recips = emailDL

allChanges = newMediaChanges + updMediaChanges + delMediaChanges
email_opts = dict(subject=subject, body=html, subtype="html")
if allChanges and recips:
    LOGGER.info("Sending Email to DL")
    LOGGER.info("   DL: %s", recips)
    LOGGER.info("\nEmail body:")
    LOGGER.info("-----------------------------------------------")
    LOGGER.info("%s", html)
    LOGGER.info("-----------------------------------------------\n")
    cdr.EmailMessage(sender, recips, **email_opts).send()
    LOGGER.info("Email send successfully!")
else:
    # Else statement included to monitor the program
    LOGGER.info("Email NOT submitted to DL")
    cdr.EmailMessage(sender, emailDevs, **email_opts).send()

# All done, going home now
# ------------------------
cpu = time.process_time()
LOGGER.info('CPU time: %6.2f seconds', cpu)
LOGGER.info('Notify_VOL - Finished')
sys.exit(0)
Ejemplo n.º 15
0
    def republish(self,
                  addNewLinkedDocuments,
                  docList=None,
                  jobList=None,
                  docType=None,
                  docTypeAll=False,
                  failedOnly=True,
                  email=''):
        """
            Requests that a set of documents be sent to Cancer.gov,
            avoiding the optimization which blocks sending the same
            version of a document twice in succession.

            Pass:

                addNewLinkedDocuments - True if the method should
                                        recursively look for and add
                                        to the job any new documents
                                        linked by any other document
                                        in the set to be re-published;
                                        otherwise False (required
                                        parameter)
                docList               - sequence of integers each
                                        identifying with its unique
                                        document identifier a CDR
                                        document to be republished
                                        (optional parameter); can
                                        be None (the default) or an
                                        empty sequence if documents
                                        will be identified by job or
                                        document type
                jobList               - sequence of integers each
                                        identifying a publishing job
                                        for which each of the documents
                                        were successfully exported
                                        are to be included in the new
                                        republishing job (optional
                                        parameter); can be None (the
                                        default) or an empty sequence
                                        if documents to be republished
                                        will be identified by document ID
                                        or document type
                docType               - string identifying the document
                                        type for which all publishable
                                        (or published -- see docTypeAll
                                        parameter below) documents are
                                        to be re-published (optional
                                        parameter); can be None (the
                                        default) or an empty string
                                        if documents to be republished
                                        will be identified by document
                                        ID and/or job ID; the document
                                        type 'Protocol' is mapped to
                                        'InScopeProtocol'
                docTypeAll            - True if all publishable documents
                                        of the type specified by the
                                        docType parameter should be
                                        included in the re-publishing
                                        job; False or None if the job
                                        should only send documents which
                                        are currently in the pub_proc_cg
                                        table as having been sent to
                                        Cancer.gov already (optional
                                        parameter, defaulting to False);
                                        ignored if the docType parameter
                                        is not specified
                failedOnly            - True if only documents with failure
                                        set to 'Y' in the pub_proc_doc
                                        table are to be included when
                                        collecting documents for
                                        specified publishing jobs; otherwise
                                        all documents are included for
                                        the publishing jobs specified
                                        (optional parameter, defaulting
                                        to True); ignored if no job IDs
                                        are specified
                email                 - optional string containing the
                                        address to which an email message
                                        is to be sent when the publishing
                                        job completes; also used for
                                        reporting failures if this
                                        method hits an exception

            Returns:

                integer representing the unique ID of the newly
                created export job

            An exception is raised in the event of a failure
            to create the new job.

        """

        # Record the request.
        self.__logger.info("republish(): %d doc IDs, %d job IDs, docType: %s",
                           docList and len(docList) or 0,
                           jobList and len(jobList) or 0, docType or "None")

        # Gather the documents from the list of individual document IDs
        self.__docs = {}
        if docList:
            for docId in docList:
                # Users might accidentally try to publish individual
                # modules.  Need to ensure we're dealing with a true
                # summary document
                # --------------------------------------------------
                self.__cursor.execute(
                    """\
                    SELECT 'x'
                      FROM query_term
                     WHERE path = '/Summary/@ModuleOnly'
                       AND doc_id = ?""", docId)
                row = self.__cursor.fetchone()
                if row:
                    self.__logger.error("republish(): *** Invalid document")
                    self.__logger.error("             *** Skipping module %s",
                                        docId)
                    continue

                self.__addDocumentToSet(docId)

        # Add to the list documents identified by previous publishing job
        if jobList:
            for jobId in jobList:
                self.__cursor.execute(
                    """\
                    SELECT doc_id, failure
                      FROM pub_proc_doc
                     WHERE pub_proc = ?
                       AND (removed IS NULL or removed = 'N')""", jobId)
                rows = self.__cursor.fetchall()
                for docId, failure in rows:
                    if not failedOnly or failure == 'Y':
                        self.__addDocumentToSet(docId)

        # Collect all documents of a specified document type if requested.
        if docType:

            # InScopeProtocol documents are know to Cancer.gov as 'Protocol'.
            if docType == 'Protocol':
                docType == 'InScopeProtocol'

            # Get all publishable documents of the specified document type ...
            if docTypeAll:
                self.__cursor.execute(
                    """\
                    SELECT DISTINCT v.id
                      FROM doc_version v
                      JOIN doc_type t
                        ON t.id = v.doc_type
                      JOIN document d
                        ON d.id = v.id
           LEFT OUTER JOIN query_term_pub q
                        ON v.id = q.doc_id
                       AND q.path = '/Summary/@ModuleOnly'
                     WHERE v.publishable = 'Y'
                       AND v.val_status = 'V'
                       AND d.active_status = 'A'
                       AND t.name = ?
                       AND q.value is null
                  ORDER BY v.id""", docType)

            # ... or just those already sent to Cancer.gov, as requested.
            else:
                # If selecting summaries we need to prevent summary modules
                # from being picked up for publishing.  These documents
                # should not exist in pub_proc_cg but might end up being
                # pushed if accidentally published via a hot-fix.
                # ---------------------------------------------------------
                self.__cursor.execute(
                    """\
                    SELECT a.id
                      FROM active_doc a
                      JOIN pub_proc_cg c
                        ON c.id = a.id
           LEFT OUTER JOIN query_term_pub q
                        ON c.id = q.doc_id
                       AND q.path = '/Summary/@ModuleOnly'
                      JOIN doc_type t
                        ON t.id = a.doc_type
                     WHERE t.name = ?
                       AND q.value IS NULL
                  ORDER BY a.id""", docType)
            rows = self.__cursor.fetchall()
            for row in rows:
                self.__addDocumentToSet(row[0])

        # Sanity check.
        if not self.__docs:
            raise Exception("republish(): no documents to publish")

        # Record the number of documents collected directly.
        self.__logger.info("republish(): %d documents collected",
                           len(self.__docs))

        # If requested, include new docs linked to by the ones we will publish.
        if addNewLinkedDocuments:
            numOriginalDocs = len(self.__docs)
            self.__addNewLinkedDocuments()
            self.__logger.info(
                "republish(): %d new linked documents added "
                "to set",
                len(self.__docs) - numOriginalDocs)

        try:

            # Make sure we don't optimize away the push of any of these docs.
            self.__adjustPubProcCgTable()
            self.__logger.info("republish(): pub_proc_cg table adjusted")

            # Use the publishing job type appropriate for republishing.
            pubSystem = 'Primary'
            pubSubset = 'Republish-Export'

            # Create a sequence of strings in the form doc-id/version-number.
            docs = [str(self.__docs[docId]) for docId in self.__docs]

            # Create the export job, which in turn creates the follow-on push
            # job.
            parms = []
            opts = dict(parms=parms, docList=docs, email=email)
            opts["tier"] = self.__tier
            resp = cdr.publish(self.__credentials, pubSystem, pubSubset,
                               **opts)

            # Make sure the job creation succeeded.
            jobId, errors = resp
            if jobId:
                jobId = int(jobId)
                message = "republish(): new publishing job %d created"
                self.__logger.info(message, jobId)
                return jobId
            else:
                self.__cleanupPubProcCgTable()
                raise Exception("republish(): %s" % errors)

        # Clean up in the event of failure, including resetting the
        # force_push and cg_new columns back to 'N'.  If we have an
        # email address, use it to notify the requestor of the bad news.
        except Exception as e:
            try:
                self.__logger.exception("republish failure")
            except:
                pass
            if email:
                try:
                    sender = "cdr@%s" % cdrcgi.WEBSERVER
                    subject = "Republication failure on %s" % self.__tier
                    body = "Failure republishing CDR documents:\n%s\n" % e
                    opts = dict(subject=subject, body=body)
                    message = cdr.EmailMessage(sender, [email], **opts)
                    message.send()
                    message = "republish(): sent failure notification to %s"
                    self.__logger.info(message, email)
                except:
                    pass
            try:
                self.__cleanupPubProcCgTable()
                self.__logger.info("republish(): pub_proc_cg table cleaned up")
            except:
                pass
            raise
Ejemplo n.º 16
0
            LOGGER.warning('*** Warning: No Email DL found')

        message = """\

Status and Error reports for the latest %s publishing/push jobs:

Publishing Job Report:
   %s/cgi-bin/cdr/PubStatus.py?id=%s

Push Job Report:
   %s/cgi-bin/cdr/PubStatus.py?id=%s

""" % (addSubj.lower(), url, submit[0], url, pushId)

        opts = dict(subject=subject, body=message)
        cdr.EmailMessage(cdr.OPERATOR, emailDL, **opts).send()
        LOGGER.info("Submitting Email: OK")
    except:
        LOGGER.exception("*** Error sending email ***")
        raise

except Exception as arg:
    LOGGER.exception("*** Standard Failure")
    subject = '[%s] *** SubmitPubJob.py - Standard Failure' % TIER
    msgBody = "The publishing job failed:  %s" % arg
    sendFailureMessage(subject, msgBody)
except:
    LOGGER.exception("*** Error - Program stopped with failure ***")
    raise

sys.exit(0)
Ejemplo n.º 17
0
# Retrieve the Email addresses from the specified group
# -----------------------------------------------------
emailDL = sorted(cdr.getEmailList('Operator Publishing Notification'))
emailDev = sorted(cdr.getEmailList("Developers Notification"))

# Set the variables and send the message
# --------------------------------------
sender = "*****@*****.**"
subject = "[%s] %s" % (cdr.Tier().name, sys.argv[1])
message = """\
Automated Publishing Email Notification:

%s""" % sys.argv[2]

try:
    # Somebody needs to get the message if the group is empty
    if not len(emailDL):
        emailDL = emailDev
        subject = '*** DL Missing *** %s' % subject

    opts = dict(subject=subject, body=message)
    cdr.EmailMessage(sender, emailDL, **opts).send()
except:
    LOGGER.exception('*** Failure sending email message')
    raise

# All done, we can go home now
# ----------------------------
LOGGER.info('PubEmail Notification - Finished')
sys.exit(0)