コード例 #1
0
    def add_new_maint(self, soup, email):
        '''
        zayo bolds the relevant fields so we use bs4 to search for those
        and then get the next sibling
        '''

        current_app.logger.info(
            f'attempting to add new maint from email {email["Subject"]}')

        table = soup.find('table')
        if not table:
            subject = email['Subject']
            return False
        maint = Maintenance()

        dates = []

        for line in soup.find_all('b'):
            if type(line) == bs4.element.Tag:
                if line.text.lower().strip().endswith('activity date:'):
                    dt = parser.parse(self.clean_line(line.next_sibling))
                    t = datetime.date(dt.year, dt.month, dt.day)
                    dates.append(t)
                if line.text.lower().strip().startswith('maintenance ticket'):
                    maint.provider_maintenance_id = self.clean_line(
                        line.next_sibling)
                # elif 'urgency' in line.text.lower():
                #    row_insert['urgency'] = self.clean_line(line.next_sibling)

                elif 'location of maintenance' in line.text.lower():
                    maint.location = self.clean_line(line.next_sibling)

                elif 'maintenance window' in line.text.lower():
                    window = line.next_sibling.strip().split('-')
                    window = [time.strip() for time in window]
                    start = window.pop(0)
                    start = parser.parse(start)
                    maint.start = datetime.time(start.hour, start.minute)
                    window = window[0].split()
                    end = window.pop(0)
                    end = parser.parse(end)
                    maint.end = datetime.time(end.hour, end.minute)

                    if len(window) == 1:
                        if current_app.config['TZ_PREFIX']:
                            # zayo will send timezones such as "Eastern"
                            # instead of "US/Eastern" so the tzinfo
                            # may not be able to be parsed without a prefix
                            tz = window.pop()
                            pfx = current_app.config['TZ_PREFIX']
                            if tz != 'GMT':
                                maint.timezone = pfx + tz
                            else:
                                maint.timezone = tz
                        else:
                            maint.timezone = window.pop()
                    else:
                        # failsafe
                        maint.timezone = ' '.join(window)

                elif 'reason for maintenance' in line.text.lower():
                    maint.reason = self.clean_line(line.next_sibling)

        received = email['Received'].splitlines()[-1].strip()
        maint.received_dt = parser.parse(received)

        self.add_and_commit(maint)

        current_app.logger.info(
            f'maintenance {maint.provider_maintenance_id} added successfully')

        NEW_PARENT_MAINT.labels(provider=self.name).inc()

        cid_table = self.format_circuit_table(table)
        for row in cid_table.values:
            if not Circuit.query.filter_by(provider_cid=row[0]).first():

                current_app.logger.info(f'adding circuit {row[0]}')

                circuit = Circuit()
                circuit.provider_cid = row[0]
                if str(row[2]) == 'nan':
                    circuit.a_side = None
                else:
                    circuit.a_side = row[2]
                if str(row[3]) == 'nan':
                    circuit.z_side = None
                else:
                    circuit.z_side = row[3]
                this = Pro.query.filter_by(name=self.name,
                                           type=self.type).first()
                circuit.provider_id = this.id
                self.add_and_commit(circuit)

                current_app.logger.info(f'circuit {row[0]} added successfully')

            circuit_row = Circuit.query.filter_by(provider_cid=row[0]).first()
            maint_row = Maintenance.query.filter_by(
                provider_maintenance_id=maint.provider_maintenance_id,
                rescheduled=0).first()
            for date in dates:

                current_app.logger.info(
                    f'adding maint_circuit row for {maint_row.provider_maintenance_id}'
                )

                mc = MaintCircuit(impact=row[1], date=date)
                circuit_row.maintenances.append(mc)
                mc.maint_id = maint_row.id
                db.session.commit()

                current_app.logger.info(
                    f'maint_circuit row for {maint_row.provider_maintenance_id} added successfully'
                )

                NEW_CID_MAINT.labels(cid=circuit_row.provider_cid).inc()

        return True
コード例 #2
0
    def add_new_maint(self, soup, email):
        maint_id = self.get_maint_id(email)
        if not maint_id:
            return False

        maint = Maintenance()
        maint.provider_maintenance_id = maint_id
        received = email['Received'].splitlines()[-1].strip()
        maint.received_dt = parser.parse(received)
        start_re = re.search(r'Start: (.*)(\r|\n)', soup.text)
        end_re = re.search(r'End: (.*)(\r|\n)', soup.text)
        location_re = re.search(r'Location: (.*)(\r|\n)', soup.text)
        reason_re = re.search(r'Reason: (.*)(\r|\n)', soup.text)
        impact_re = re.search(r'Impact: (.*)(\r|\n)', soup.text)
        impact = impact_re.groups()[0]
        start_dt = parser.parse(start_re.groups()[0])
        end_dt = parser.parse(end_re.groups()[0])
        maint.start = start_dt.time()
        maint.end = end_dt.time()
        maint.timezone = start_dt.tzname()
        maint.location = location_re.groups()[0]
        maint.reason = reason_re.groups()[0]
        if not all((start_re, end_re, location_re, reason_re, impact_re)):
            raise ParsingError(
                'Unable to parse the maintenance notification from GTT: {}'.
                format(soup.text))

        self.add_and_commit(maint)

        NEW_PARENT_MAINT.labels(provider=self.name).inc()

        # sometimes maint emails contain the same cid several times
        cids = set()
        a_side = set()

        for line in soup.text.splitlines():
            if 'gtt service' in line.lower():
                cid = re.search(r'GTT Service = (.+);', line)
                if cid:
                    cids.add(cid.groups()[0])
            elif line.lower().startswith('site address'):
                loc = re.search(r'= (.*)', line)
                if loc:
                    a_side.add(loc.groups()[0])
            # there is sometimes two location lines with
            # = ostensibly being the circuit location
            elif line.lower().startswith('location ='):
                loc = re.search(r'= (.*)', line)
                if loc:
                    a_side.add(loc.groups()[0])

        if len(cids) == len(a_side):
            for cid, a_side in zip(cids, a_side):
                if not Circuit.query.filter_by(provider_cid=cid).first():
                    circuit = Circuit()
                    circuit.provider_cid = cid
                    circuit.a_side = a_side
                    this = Pro.query.filter_by(name=self.name,
                                               type=self.type).first()
                    circuit.provider_id = this.id
                    self.add_and_commit(circuit)

                circuit_row = Circuit.query.filter_by(provider_cid=cid).first()
                maint_row = Maintenance.query.filter_by(
                    provider_maintenance_id=maint.provider_maintenance_id,
                    rescheduled=0).first()

                mc = MaintCircuit(impact=impact, date=start_dt.date())
                circuit_row.maintenances.append(mc)
                mc.maint_id = maint_row.id
                db.session.commit()
                NEW_CID_MAINT.labels(cid=cid).inc()

        return True
コード例 #3
0
    def add_new_maint(self, soup, email):
        '''
        create a new telstra maintenance
        '''
        maint = Maintenance()
        maint.provider_maintenance_id = email['Subject'].split()[-1]
        maint.location = 'n/a'  # telstra doesn't give this info :(
        maint.reason = ''

        received = email['Received'].splitlines()[-1].strip()
        maint.received_dt = parser.parse(received)

        headers = soup.findAll('th')
        impact = None
        cid = None
        date = None

        for column in headers:
            if 'expected impact' in self.clean_line(column.text.lower()):
                impact = self.clean_line(column.next_sibling.next_sibling.text)

            elif 'service(s) impacted' in self.clean_line(column.text.lower()):
                cid = self.clean_line(column.next_sibling.next_sibling.text)

            elif 'maintenance window' in self.clean_line(column.text.lower()):
                date = self.clean_line(column.next_sibling.next_sibling.text)

        if not all((impact, cid, date)):
            raise ParsingError(
                f'unable to parse telstra impact: {impact}, cid: {cid}, date: {date} subject: {email["Subject"]}'
            )

        fullstart, fullend = date.split(' to ')

        datestart, timestart = fullstart.split()
        dateend, timeend = fullend.split()

        startdate = parser.parse(datestart).date()

        timematch = re.compile(r'^\d+:\d+(?=[:00])?')

        starttime = timematch.search(timestart).group()
        endtime = timematch.search(timeend).group()

        start = parser.parse(starttime).time()
        end = parser.parse(endtime).time()

        maint.start = start
        maint.end = end

        tzmatch = re.compile(r'\((\w+)\)')

        tz = tzmatch.search(timestart).groups()[0]
        maint.timezone = tz

        # grab maintenance details. This is not pretty
        details = []
        for i in soup.find_all('tr'):
            if 'maintenance details' in i.text.lower():
                det = i
                details = det.findNextSiblings('tr')
                break

        for line in details:
            if 'service(s) impacted' in line.text.lower():
                break
            maint.reason += clean_line(line.text)
            maint.reason += ' '

        self.add_and_commit(maint)

        NEW_PARENT_MAINT.labels(provider=self.name).inc()

        # add the circuit if it doesn't exist

        circuit = Circuit.query.filter_by(provider_cid=cid).first()

        if not circuit:
            circuit = Circuit()
            circuit.provider_cid = cid
            circuit.a_side = ''
            circuit.z_side = ''

            this = Pro.query.filter_by(name=self.name, type=self.type).first()
            circuit.provider_id = this.id
            self.add_and_commit(circuit)

        # add the maint_circuit row

        maint_row = Maintenance.query.filter_by(
            provider_maintenance_id=maint.provider_maintenance_id,
            rescheduled=0).first()

        mc = MaintCircuit(impact=impact, date=startdate)
        circuit.maintenances.append(mc)
        mc.maint_id = maint_row.id
        db.session.commit()

        NEW_CID_MAINT.labels(cid=circuit.provider_cid).inc()

        return True