Ejemplo n.º 1
0
def get_boxids_by_key(key, value):
    """Select boxes by key-type and key-value"""
    db = _get_db()
    netbox_ids = []
    if key in ('room', 'location'):
        if key == 'location':
            sql = """SELECT netboxid
                        FROM netbox
                            INNER JOIN room USING (roomid)
                        WHERE locationid = %s"""
        if key == 'room':
            sql = """SELECT netboxid
                        FROM netbox
                        WHERE roomid = %s"""
        db.execute(sql, (value,))
        netbox_ids = [box_id for (box_id,) in db.fetchall()]
    if key == 'service':
        sql = "SELECT netboxid FROM service WHERE serviceid = %s"
        db.execute(sql, (int(value),))
        result = db.fetchone()
        if result:
            (box_id,) = result
            netbox_ids.append(box_id)
    if key == 'netbox':
        netbox_ids.append(int(value))
    return netbox_ids
Ejemplo n.º 2
0
    def getusers(self, sent='N'):
        """
        Get users which has messages with given sent status (normally unsent).

        Returns a sorted list with the phone numbers for all users with
        messages with given sent status.
        """

        users = []
        dbconn = self._connect()
        db = dbconn.cursor()

        data = dict(sent=sent)
        sql = """SELECT DISTINCT phone
            FROM smsq
            WHERE sent = %(sent)s
            ORDER BY phone"""
        db.execute(sql, data)
        result = db.fetchall()
        # Rollback so we don't have old open transactions which foobars the
        # usage of now() in setsentstatus()
        dbconn.rollback()

        # Create a simple list without the tuples
        for row in result:
            users.append(row[0])

        return users
Ejemplo n.º 3
0
    def getmsgs(self, sent='N'):
        """
        Get all messages with given sent status (normally unsent).

        Returns a list of dictionaries containing messages details of SMS in
        queue with the specified status.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        data = dict(sent=sent)
        sql = """SELECT smsq.id as smsqid, name, msg, time 
            FROM smsq 
            JOIN account ON (account.id = smsq.accountid) 
            WHERE sent = %(sent)s ORDER BY time ASC"""
        db.execute(sql, data)
        
        result = []
        for (smsqid, name, msg, time) in db.fetchall():
            result.append(dict(id=smsqid, name=name, msg=msg,
                               time=time.strftime("%Y-%m-%d %H:%M")))

        # Rollback so we don't have old open transactions which foobars the
        # usage of now() in setsentstatus()
        dbconn.rollback()

        return result
Ejemplo n.º 4
0
def schedule():
    """Check if there are maintenance tasks to be schedule"""
    db = _get_db()
    sql = """UPDATE maint_task SET state = 'scheduled'
        WHERE state IS NULL
        OR state NOT IN ('scheduled', 'active', 'passed', 'canceled')"""
    db.execute(sql)
    _get_dbconn().commit()
Ejemplo n.º 5
0
def check_tasks_without_end():
    """Loop thru all maintenance tasks without a defined end time, and
    end the task if all boxes included in the task have been up for
    longer than a minimum time."""
    db = _get_db()
    tasks_and_boxes = get_tasks_and_boxes_without_end()
    # Loop thru all maintenance tasks and check if the affected boxes
    # have been up for minimum time.
    for (maint_id, netbox_ids) in tasks_and_boxes.iteritems():
        boxes_still_on_maint = []
        for box_id in netbox_ids:
            sql = """SELECT end_time FROM alerthist
                        WHERE netboxid = %s AND
                            eventtypeid = 'boxState' AND
                            end_time IS NOT NULL
                        ORDER BY end_time DESC LIMIT 1"""
            db.execute(sql, (box_id,))
            result = db.fetchone()
            if result:
                (end_time,) = result
                # Box is up
                end_time_to_check = INFINITY
                if end_time < (INFINITY -
                               datetime.timedelta(minutes=MINIMUM_UPTIME_MINS)):
                    end_time_to_check = (end_time +
                            datetime.timedelta(minutes=MINIMUM_UPTIME_MINS))
                if end_time_to_check > datetime.datetime.now():
                    # Box have not been up for minimum time yet.
                    boxes_still_on_maint.append(str(box_id))
            else:
                # Box is not up
                boxes_still_on_maint.append(str(box_id))
        if len(boxes_still_on_maint) > 0:
            # Some boxes are still down...
            _logger.debug(
                "Maintenance task %d: Boxes still on maintenance: %r",
                maint_id, boxes_still_on_maint)
        else:
            # All affected boxes for this maintenance task have been up
            # again for the minimum time.
            time_now = datetime.datetime.now()
            _logger.warn("Maintenance task %d: Set end at %s",
                         maint_id, time_now)
            sql = """UPDATE maint_task
                            SET maint_end = %s
                        WHERE maint_taskid = %s"""
            db.execute(sql, (time_now, maint_id,))
            _get_dbconn().commit()
Ejemplo n.º 6
0
    def inserttestmsgs(self, uid, phone, msg):
        """
        Insert test messages into the SMS queue for debugging purposes.

        Returns a integer indicating how many rows have been inserted.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        data = dict(uid=uid, phone=phone, msg=msg)
        sql = """INSERT INTO smsq (accountid, time, phone, msg) VALUES (
                 %(uid)s, now(), %(phone)s, %(msg)s)"""

        db.execute(sql, data)
        dbconn.commit()

        return db.rowcount
Ejemplo n.º 7
0
    def cancel(self, minage='0'):
        """
        Mark all unsent messages as ignored.

        Input:
            minage  Minimum age required for canceling message, default '0'.
                    Format as PostgreSQL interval type, e.g. '1 day 12 hours'.

        Returns number of messages canceled.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        data = dict(minage=str(minage))

        # Test minage
        if minage != '0':
            sql = "SELECT interval %(minage)s"
            try:
                db.execute(sql, data)
            except nav.db.driver.ProgrammingError:
                self.logger.warning("'autocancel' value (%s) is not valid. " +
                                    "Check config for errors.",
                                    minage)
                return 0
            except Exception:
                self.logger.exception("Unknown exception caught in " +
                                      "cancel(). Exiting.")
                sys.exit(1)

        # Ignore messages
        sql = """UPDATE smsq SET sent = 'I'
            WHERE sent = 'N' AND time < now() - interval %(minage)s"""
        db.execute(sql, data)
        dbconn.commit()

        return db.rowcount
Ejemplo n.º 8
0
    def getusermsgs(self, user, sent='N'):
        """
        Get the user's messages which has given sent status (normally unsent).

        Returns a list of messsages ordered with the most severe first. Each
        message is a tuple with the ID, text, and severity of the message.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        data = dict(phone=user, sent=sent)
        sql = """SELECT id, msg, severity
            FROM smsq
            WHERE phone = %(phone)s AND sent = %(sent)s
            ORDER BY severity DESC, time ASC"""
        db.execute(sql, data)
        result = db.fetchall()
        # Rollback so we don't have old open transactions which foobars the
        # usage of now() in setsentstatus()
        dbconn.rollback()

        return result
Ejemplo n.º 9
0
def get_tasks_and_boxes_without_end():
    """Collect all netboxes from maintenance tasks that do not have a defined
        end time.  Place them in a dictionary with maintenance identity as key
        and a list of affected netboxes for each task."""
    db = _get_db()
    #  Select all affected components for every task.
    sql = """SELECT maint_taskid, key, value
                FROM maint_task
                    INNER JOIN maint_component USING (maint_taskid)
                WHERE state = 'active' AND
                    maint_end >= %s"""
    db.execute(sql, (INFINITY,))
    tasks_and_boxes = {}
    for (maint_id, key, value) in db.fetchall():
        # Collect affected boxes for each maintenance task.
        netbox_ids = get_boxids_by_key(key, value)
        # Use maintenance key as key for netboxes that are affected by
        # the maintenance task.
        if maint_id in tasks_and_boxes:
            tasks_and_boxes[maint_id].extend(netbox_ids)
        else:
            tasks_and_boxes[maint_id] = netbox_ids
    return tasks_and_boxes
Ejemplo n.º 10
0
    def setsentstatus(self, identifier, sent, smsid=0):
        """
        Set the sent status of a message given ID and status.

        Returns number of messages changed.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        if sent == 'Y' or sent == 'I':
            sql = """UPDATE smsq
                SET sent = %(sent)s, smsid = %(smsid)s, timesent = now()
                WHERE id = %(id)s"""
        else:
            sql = """UPDATE smsq
                SET sent = %(sent)s, smsid = %(smsid)s
                WHERE id = %(id)s"""

        data = dict(sent=sent, smsid=smsid, id=identifier)
        db.execute(sql, data)
        dbconn.commit()

        return db.rowcount
Ejemplo n.º 11
0
    def setsentstatus(self, identifier, sent, smsid=0):
        """
        Set the sent status of a message given ID and status.

        Returns number of messages changed.
        """

        dbconn = self._connect()
        db = dbconn.cursor()

        if sent == 'Y' or sent == 'I':
            sql = """UPDATE smsq
                SET sent = %(sent)s, smsid = %(smsid)s, timesent = now()
                WHERE id = %(id)s"""
        else:
            sql = """UPDATE smsq
                SET sent = %(sent)s, smsid = %(smsid)s
                WHERE id = %(id)s"""

        data = dict(sent=sent, smsid=smsid, id=identifier)
        db.execute(sql, data)
        dbconn.commit()

        return db.rowcount
Ejemplo n.º 12
0
def check_state(events, maxdate_boxes):
    """
    Checks if there are some maintenance tasks to be set active or passed.
    """
    time_now = datetime.datetime.now()

    db = _get_db()
    sql = """SELECT maint_taskid FROM maint_task
        WHERE maint_start < %s AND state = 'scheduled'"""
    db.execute(sql, (time_now,))
    for (taskid,) in db.fetchall():
        sched_event = {}
        sched_event['type'] = 'active'
        sched_event['taskid'] = taskid
        events.append(sched_event)

    sql = """SELECT maint_taskid, maint_end FROM maint_task
        WHERE maint_end < %s AND state = 'active'"""
    db.execute(sql, (time_now,))
    for (taskid, maint_end) in db.fetchall():
        active_event = {}
        active_event['type'] = 'passed'
        active_event['taskid'] = taskid
        active_event['maint_end'] = maint_end
        events.append(active_event)

    # Get boxes that should still stay on maintenance
    sql = """SELECT max(maint_end) AS maint_end, key, value
        FROM maint_task INNER JOIN maint_component USING (maint_taskid)
        WHERE state = 'active' AND maint_end > %s
        GROUP BY key, value"""
    db.execute(sql, (time_now,))
    for (maint_end, key, value) in db.fetchall():
        boxids = get_boxids_by_key(key, value)
        for boxid in boxids:
            if boxid in maxdate_boxes and maxdate_boxes[boxid] > maint_end:
                continue
            maxdate_boxes[boxid] = maint_end
Ejemplo n.º 13
0
def setTask(taskid, maint_start, maint_end, description, author, state):
    """
    Insert or update a maintenance task

    Input:
        taskid      Maintenance task ID if update, set to false if new task
        maint_start Start time of task
        maint_end   End time of task
        description Description of the task
        author      Username of author
        state       State of task, initally 'scheduled', used by other
                    subsystems

    Returns:
        msgid       ID of updated or inserted task

    """

    dbconn = nav.db.getConnection('webfront', 'manage')
    db = dbconn.cursor(cursor_factory=psycopg2.extras.DictCursor)

    if taskid:
        sql = """UPDATE maint_task SET
                maint_start = %(maint_start)s,
                maint_end = %(maint_end)s,
                description = %(description)s,
                author = %(author)s,
                state = %(state)s
            WHERE
                maint_taskid = %(maint_taskid)s"""
    else:
        sql = """INSERT INTO maint_task (
                maint_start,
                maint_end,
                description,
                author,
                state
            ) VALUES (
                %(maint_start)s,
                %(maint_end)s,
                %(description)s,
                %(author)s,
                %(state)s
            )"""

    if not isinstance(description, unicode):
        description = description.decode('utf-8')

    data = {
        'maint_taskid': taskid,
        'maint_start': time.strftime('%Y-%m-%d %H:%M:%S', maint_start),
        'maint_end': time.strftime('%Y-%m-%d %H:%M:%S', maint_end),
        'description': description,
        'author': author,
        'state': state
    }

    logger.debug("setTask() query: %s", sql % data)
    db.execute(sql, data)
    if not taskid:
        db.execute("SELECT CURRVAL('maint_task_maint_taskid_seq')")
        taskid = db.fetchone()['currval']
    logger.debug("setTask() number of results: %d", db.rowcount)

    return taskid
Ejemplo n.º 14
0
def remove_forgotten(boxes_off_maintenance):
    """
    Remove 'forgotten' netboxes from their maintenance state.

    Sometimes, like when netboxes have been deleted from a maintenance task
    during its active maintenance window, we will no longer know that the box
    has gone on maintenenance and should be taken off. This function takes all
    'forgotten' netboxes off maintenance.

    """
    db = _get_db()
    # This SQL retrieves a list of boxes that are currently on
    # maintenance, according to the alert history.
    sql_actual = """SELECT ah.netboxid, ah.deviceid, n.sysname, subid
        FROM alerthist ah LEFT JOIN netbox n USING (netboxid)
        WHERE eventtypeid='maintenanceState' AND netboxid IS NOT NULL
        AND end_time = 'infinity'"""

    # This SQL retrieves a list of boxes that are supposed to be on
    # maintenance, according to the schedule.
    sql_sched = """SELECT n.netboxid, n.deviceid, n.sysname, NULL AS subid
        FROM maint m INNER JOIN netbox n ON (n.netboxid::text = m.value)
        WHERE m.key = 'netbox' AND m.state = 'active'

        UNION

        SELECT n.netboxid, n.deviceid, n.sysname, NULL AS subid
        FROM maint m INNER JOIN netbox n ON (n.roomid = m.value)
        WHERE m.key = 'room' AND m.state = 'active'

        UNION

        SELECT n.netboxid, n.deviceid, n.sysname, NULL AS subid
        FROM maint m INNER JOIN netbox n ON (n.roomid IN
            (SELECT roomid FROM room WHERE locationid = m.value))
        WHERE m.key = 'location' AND m.state = 'active'

        UNION

        SELECT n.netboxid, n.deviceid, n.sysname, m.value AS subid
        FROM maint m INNER JOIN netbox n ON (n.netboxid IN
            (SELECT netboxid FROM service WHERE
                serviceid::text LIKE m.value))
        WHERE m.key = 'service' AND m.state = 'active'"""

    # The full SQL is a set operation to select all boxes that are
    # currently on maintenance and subtracts those that are supposed
    # to be on maintenance - resulting in a list of boxes that should
    # be taken off maintenance immediately.
    sql_full = "(%s) \n EXCEPT \n (%s)" % (sql_actual, sql_sched)
    db.execute(sql_full)

    target = 'eventEngine'
    subsystem = 'maintenance'
    source = subsystem
    severity = 50
    eventtype = 'maintenanceState'
    state = 'e'
    value = 0

    for (netboxid, deviceid, sysname, subid) in db.fetchall():
        if netboxid in boxes_off_maintenance:
            # MaintenenceOff-events posted during this run might not
            # have been processed by eventEngine yet. We discard these
            # boxes here.
            continue

        # If it's a service, we have to set subid also
        if subid is None:
            _logger.info("Box %s (%d) is on unscheduled maintenance. "
                         "Taking off maintenance now.", sysname, netboxid)
            subid = False
        else:
            _logger.info(
                "Service (%d) at box %s (%d) is on unscheduled maintenance. "
                "Taking off maintenance...", subid, sysname, netboxid)
            subid = int(subid)

        # Create event
        event = nav.event.Event(
            source=source, target=target,
            deviceid=deviceid, netboxid=netboxid, subid=subid,
            eventtypeid=eventtype, state=state, value=value, severity=severity)

        result = event.post()
        _logger.debug("Event: %s, Result: %s", event, result)

    # Commit transaction
    _get_dbconn().commit()
Ejemplo n.º 15
0
def send_event(events, maxdate_boxes, boxes_off_maintenance):
    """Sends events to the event queue."""
    db = _get_db()
    for curr_event in events:
        event_type = curr_event['type']
        taskid = curr_event['taskid']

        # Get all components related to task/event
        sql = """SELECT key, value FROM maint_component
                 WHERE maint_taskid = %(maint_taskid)s"""
        data = {'maint_taskid': taskid}
        db.execute(sql, data)

        for (key, val) in db.fetchall():
            # Prepare event variables
            target = 'eventEngine'
            subsystem = 'maintenance'
            source = subsystem
            severity = 50
            eventtype = 'maintenanceState'
            if event_type == 'active':
                state = 's'  # s = start
                value = 100
            elif event_type == 'passed':
                state = 'e'  # e = end
                value = 0

            # Get all related netboxes
            netboxes = []
            if key in ('location', 'room'):
                if key == 'location':
                    sql = """SELECT netboxid, sysname, deviceid
                        FROM netbox INNER JOIN room USING (roomid)
                        WHERE locationid = %(locationid)s"""
                    data = {'locationid': val}

                    _logger.debug("location query: %s", sql % data)
                    db.execute(sql, data)
                    _logger.debug("location number of results: %d", db.rowcount)
                elif key == 'room':
                    sql = """SELECT netboxid, sysname, deviceid
                        FROM netbox
                        WHERE roomid = %(roomid)s"""
                    data = {'roomid': val}

                    _logger.debug("room query: %s", sql % data)
                    db.execute(sql, data)
                    _logger.debug("room number of results: %d", db.rowcount)

                for (netboxid, sysname, deviceid) in db.fetchall():
                    netboxes.append({'netboxid': netboxid,
                                     'sysname': sysname,
                                     'deviceid': deviceid,
                                     'cvar': 'netbox',
                                     'cval': sysname})
            elif key == 'netbox':
                sql = """SELECT netboxid, sysname, deviceid
                    FROM netbox
                    WHERE netboxid = %(netboxid)s"""
                data = {'netboxid': int(val)}

                _logger.debug("netbox query: %s", sql % data)
                db.execute(sql, data)
                _logger.debug("netbox number of results: %d", db.rowcount)
                result = db.fetchone()

                if result:
                    (netboxid, sysname, deviceid) = result
                    netboxes.append({'netboxid': netboxid,
                                     'sysname': sysname,
                                     'deviceid': deviceid,
                                     'cvar': 'netbox',
                                     'cval': sysname})
            elif key == 'service':
                sql = """SELECT netboxid, sysname, deviceid, handler
                    FROM service INNER JOIN netbox USING (netboxid)
                    WHERE serviceid = %(serviceid)s"""
                data = {'serviceid': int(val)}

                _logger.debug("service query: %s", sql % data)
                db.execute(sql, data)
                _logger.debug("service number of results: %d", db.rowcount)
                result = db.fetchone()

                if result:
                    (netboxid, sysname, deviceid, handler) = result
                    netboxes.append({'netboxid': netboxid,
                                     'sysname': sysname,
                                     'deviceid': deviceid,
                                     'serviceid': int(val),
                                     'servicename': handler,
                                     'cvar': 'service',
                                     'cval': handler})
            elif key == 'module':
                # Unsupported as of NAV 3.2
                raise DeprecationWarning("Deprecated component key")

            # Create events for all related netboxes
            for netbox in netboxes:
                if event_type == 'passed' and netbox['netboxid'] in maxdate_boxes:
                    netbox_id = netbox['netboxid']
                    if maxdate_boxes[netbox_id] > curr_event['maint_end']:
                        _logger.debug(
                            "Skip stop event for netbox %s. It's on "
                            "maintenance until %s.",
                            str(netbox['netboxid']),
                            str(curr_event['maint_end'])
                        )
                        continue
                    # Append to list of boxes taken off maintenance
                    # during this run
                if event_type == 'passed':
                    boxes_off_maintenance.append(netbox['netboxid'])

                if 'serviceid' in netbox:
                    subid = netbox['serviceid']
                else:
                    subid = None

                # Create event
                event = nav.event.Event(source=source, target=target,
                    deviceid=netbox['deviceid'],
                    netboxid=netbox['netboxid'], subid=subid,
                    eventtypeid=eventtype, state=state, value=value,
                    severity=severity)
                event[netbox['cvar']] = netbox['cval']
                event['maint_taskid'] = taskid

                # Add event to eventq
                result = event.post()
                _logger.debug("Event: %s, Result: %s", event, result)

        # Update state
        sql = """UPDATE maint_task
            SET state = %(state)s
            WHERE maint_taskid = %(maint_taskid)s"""
        data = {'state': event_type,
                'maint_taskid': taskid}
        db.execute(sql, data)

        # Commit transaction
        _get_dbconn().commit()