def handle_put(cls, **kwargs):
     """Refresh cached counts for given inventory ID."""
     inventory_id = kwargs.get("inventory_id", None)
     cls._system_exists(inventory_id)
     DB.execute_sql("SELECT refresh_system_cached_counts(%s)",
                    (inventory_id, ))
     return ""
 def handle_patch(cls, **kwargs):
     """Update the 'status' field for a system/cve combination"""
     data = kwargs['data']
     in_inventory_id = data['inventory_id']
     in_cve = data['cve']
     in_status_id = data['status_id']
     LOGGER.debug('SYSID [%s] CVE [%s] STATUS-ID [%s] ACCT [%s]',
                  in_inventory_id, in_cve, in_status_id, connexion.context['user'])
     try:
         plat = (SystemPlatform.select(SystemPlatform.inventory_id)
                 .where((SystemPlatform.rh_account == connexion.context['user']) &
                        (SystemPlatform.inventory_id == in_inventory_id) &
                        (SystemPlatform.opt_out == False)))  # pylint: disable=singleton-comparison
         if cls.hide_satellite_managed():
             plat = plat.where(SystemPlatform.satellite_managed == False)  # pylint: disable=singleton-comparison
         vuln = (SystemVulnerabilities.update(status_id=in_status_id)
                 .from_(plat)
                 .where((SystemVulnerabilities.inventory_id == in_inventory_id) &
                        (SystemVulnerabilities.cve == in_cve)))
         rows_modified = vuln.execute()
         if rows_modified == 0:
             # sysid/cve/acct combination does not exist
             return cls.format_exception('inventory_id/cve must exist and inventory_id must be visible to user', 404)
     except (IntegrityError, ValueError, psycopg2IntegrityError) as integ_error:
         # usually means bad-status-id
         DB.rollback()
         return cls.format_exception(str(integ_error), 500)
     return ''
    def handle_patch(cls, **kwargs):
        """Set status for a CVE"""
        data = kwargs['data']
        cve_list = data['cve']
        if isinstance(cve_list, str):
            cve_list = [cve_list]

        values = {}
        updated = []
        if 'status_id' in data:
            values['status_id'] = data['status_id']
        if 'status_text' in data:
            try:
                values['status_text'] = data['status_text'].strip() \
                                        if data['status_text'].strip() else None
            except AttributeError:
                values['status_text'] = None
        if not values:
            return cls.format_exception(
                'At least one of the "status_id" or "status_text" parameters is required.', 400)
        try:
            to_insert = []
            cves = CveMetadata.select(CveMetadata.id, CveMetadata.cve).where(CveMetadata.cve << cve_list)
            rh_account = get_or_create_account()
            for cve in cves:
                updated.append(cve.cve)
                if 'status_id' in data:
                    # refresh number of divergent statuses in CVE-system pairs
                    # pylint: disable=singleton-comparison
                    query = (SystemVulnerabilities.select(fn.Count(SystemVulnerabilities.id).alias('systems'))
                             .join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id))
                             .join(InsightsRule, JOIN.LEFT_OUTER, on=(InsightsRule.id == SystemVulnerabilities.rule_id))
                             .where(SystemPlatform.rh_account_id == rh_account[0].id)
                             .where((SystemPlatform.opt_out == False)  # noqa: E712
                                    & (SystemPlatform.stale == False)  # noqa: E712
                                    & (SystemPlatform.when_deleted.is_null(True)))
                             .where(SystemVulnerabilities.cve_id == cve.id)
                             .where((SystemVulnerabilities.mitigation_reason.is_null(True)) | (InsightsRule.active == False))
                             .where((SystemVulnerabilities.when_mitigated.is_null(True)) | (InsightsRule.active == True))
                             .where(SystemVulnerabilities.status_id != values.get('status_id', 0))
                             .dicts())
                    values['systems_status_divergent'] = query[0]['systems']

                to_insert.append((cve.id, rh_account[0].id, values.get('status_id', 0),
                                  values.get('status_text', None), values.get('systems_status_divergent', 0)))
            if not to_insert:
                return cls.format_exception('At least one given CVE must exist', 404)
            (CveAccountData.insert_many(to_insert, fields=cls._fields)
             .on_conflict(conflict_target=cls._conflict_target, preserve=[], update=values).execute())
        except (IntegrityError, psycopg2IntegrityError, DataError):
            # usually means bad status
            LOGGER.exception('Error during setting status (IntegrityError):')
            DB.rollback()
            return cls.format_exception(f"status_id={data['status_id']} is invalid", 400)
        except ValueError as value_error:
            LOGGER.exception('Error during setting status (ValueError):')
            DB.rollback()
            return cls.format_exception(f'status_text or other key value is invalid ({value_error})', 400)
        return {'updated': updated}
 def handle_delete(cls, **kwargs):
     pid = kwargs["pid"]
     try:
         LOGGER.info("Killing query with PID %s", pid)
         DB.execute_sql("SELECT pg_terminate_backend(%s)", (pid,))
     except DatabaseError as err:
         LOGGER.exception("Internal server error: %s", err)
         return "Error"
     return "Ok"
 def handle_put(cls, **kwargs):
     """Refresh cached counts for given account ID and CVE."""
     account = kwargs.get("account_id", None)
     cve = kwargs.get("cve_id", None)
     cls._account_exists(account)
     cls._cve_exists(cve)
     DB.execute_sql("SELECT refresh_cve_account_cached_counts(%s, %s)",
                    (cve, account))
     return ""
Esempio n. 6
0
    def handle_patch(cls, **kwargs):
        """Update the 'status' field for a system/cve combination"""
        # pylint: disable=singleton-comparison
        data = kwargs['data']

        try:
            in_inventory_id_list, in_cve_list, status_to_cves_map, status_text_to_cves_map = cls._prepare_data(data)
            rh_account = get_or_create_account()
            systems = (SystemPlatform.select(SystemPlatform.id)
                       .where((SystemPlatform.rh_account_id == rh_account[0].id) &
                              (SystemPlatform.opt_out == False)))  # noqa: E712
            if in_inventory_id_list is not None:
                systems = systems.where(SystemPlatform.inventory_id << in_inventory_id_list)
            rows_modified = set()
            # set statuses and their CVE lists
            for status_id, status_cve_list in status_to_cves_map.items():
                status_id_update = (SystemVulnerabilities.update(status_id=status_id)
                                    .where((SystemVulnerabilities.system_id << systems) &
                                           (SystemVulnerabilities.cve_id <<
                                            (CveMetadata.select(CveMetadata.id).where(
                                                CveMetadata.cve << status_cve_list))))
                                    .returning(SystemVulnerabilities.id))
                rows_modified.update([row.id for row in status_id_update])

            cls._update_divergent_status_count(in_cve_list, rh_account[0].id)

            for status_text, status_cve_list in status_text_to_cves_map.items():
                status_text_update = (SystemVulnerabilities.update(status_text=status_text)
                                      .where((SystemVulnerabilities.system_id << systems) &
                                             (SystemVulnerabilities.cve_id <<
                                              (CveMetadata.select(CveMetadata.id).where(
                                                  CveMetadata.cve << status_cve_list))))
                                      .returning(SystemVulnerabilities.id))
                rows_modified.update([row.id for row in status_text_update])

            updated_details = (SystemVulnerabilities.select(SystemPlatform.inventory_id, CveMetadata.cve)
                               .join(CveMetadata, on=(SystemVulnerabilities.cve_id == CveMetadata.id))
                               .join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id))
                               .where(SystemVulnerabilities.id << list(rows_modified))
                               .dicts())
            updated = []
            for updated_row in updated_details:
                updated.append({"inventory_id": updated_row["inventory_id"], "cve": updated_row["cve"]})
            if not updated:
                # sysid/cve/acct combination does not exist
                return cls.format_exception('inventory_id/cve must exist and inventory_id must be visible to user', 404)
        except (IntegrityError, psycopg2IntegrityError, DataError) as value_error:
            # usually means bad-status-id
            LOGGER.error(str(value_error))
            DB.rollback()
            return cls.format_exception(f'status_id={list(status_to_cves_map.keys())} is invalid', 400)
        except ValueError as value_error:
            LOGGER.exception('Error during setting status (ValueError):')
            DB.rollback()
            return cls.format_exception(f'status_text or other key value is invalid ({value_error})', 400)
        return {"updated": updated}
    def handle_patch(cls, **kwargs):
        """Set status for a CVE"""
        data = kwargs['data']
        cve_list = data['cve']
        if isinstance(cve_list, str):
            cve_list = [cve_list]

        values = {}
        updated = []
        if 'status_id' in data:
            values['status_id'] = data['status_id']
        if 'status_text' in data:
            try:
                values['status_text'] = data['status_text'].strip() \
                    if data['status_text'].strip() else None
            except AttributeError:
                values['status_text'] = None
        if not values:
            return cls.format_exception(
                'At least one of the "status_id" or "status_text" parameters is required.',
                400)
        try:
            to_insert = []
            cves = CveMetadata.select(
                CveMetadata.id,
                CveMetadata.cve).where(CveMetadata.cve << cve_list)
            rh_account = get_or_create_account()
            for cve in cves:  # pylint: disable=not-an-iterable
                updated.append(cve.cve)
                to_insert.append(
                    (cve.id, rh_account[0].id, values.get('status_id', 0),
                     values.get('status_text', None)))
            if not to_insert:
                return cls.format_exception(
                    'At least one given CVE must exist', 404)
            (CveAccountData.insert_many(
                to_insert, fields=cls._fields).on_conflict(
                    conflict_target=cls._conflict_target,
                    preserve=[],
                    update=values).execute())
            RHAccount.update(
                last_status_change=datetime.now(timezone.utc)).where(
                    RHAccount.id == rh_account[0].id).execute()
        except (IntegrityError, psycopg2IntegrityError, DataError):
            # usually means bad status
            LOGGER.exception('Error during setting status (IntegrityError):')
            DB.rollback()
            return cls.format_exception(
                f"status_id={data['status_id']} is invalid", 400)
        except ValueError as value_error:
            LOGGER.exception('Error during setting status (ValueError):')
            DB.rollback()
            return cls.format_exception(
                f'status_text or other key value is invalid ({value_error})',
                400)
        return {'updated': updated}
Esempio n. 8
0
    def handle_patch(cls, **kwargs):
        """Set business risk for a CVE"""
        data = kwargs['data']
        cve_list = data['cve']
        if isinstance(cve_list, str):
            cve_list = [cve_list]

        values = {}
        updated = []
        if 'business_risk_id' in data:
            values['business_risk_id'] = data['business_risk_id']
        if 'business_risk_text' in data:
            try:
                values['business_risk_text'] = data['business_risk_text'].strip() \
                                               if data['business_risk_text'].strip() else None
            except AttributeError:
                values['business_risk_text'] = None
        if not values:
            return cls.format_exception(
                'At least one of the "business_risk_id" or "business_risk_text" parameters is required.',
                400)
        try:
            to_insert = []
            cves = CveMetadata.select(
                CveMetadata.id,
                CveMetadata.cve).where(CveMetadata.cve << cve_list)
            rh_account = get_or_create_account()
            for cve in cves:
                updated.append(cve.cve)
                to_insert.append((cve.id, rh_account[0].id,
                                  values.get('business_risk_id', 0),
                                  values.get('business_risk_text', None)))
            if not to_insert:
                return cls.format_exception(
                    'At least one given CVE must exist', 404)
            (CveAccountData.insert_many(
                to_insert, fields=cls._fields).on_conflict(
                    conflict_target=cls._conflict_target,
                    preserve=[],
                    update=values).execute())
        except (IntegrityError, psycopg2IntegrityError, DataError):
            # usually means bad business_risk_id
            LOGGER.exception(
                'Error during setting business risk (IntegrityError):')
            DB.rollback()
            return cls.format_exception(
                f'business_risk_id=%s is invalid' % data['business_risk_id'],
                400)
        except ValueError as value_error:
            LOGGER.exception(
                'Error during setting business risk (ValueError):')
            DB.rollback()
            return cls.format_exception(
                f'business_risk_text or other key value is invalid ({value_error})',
                400)
        return {'updated': updated}
Esempio n. 9
0
def wait_on_cyndi():
    """Waits until inventory.hosts schema is initialized"""
    LOGGER.info("Waiting for cyndi...")
    while True:
        try:
            InventoryHosts.select(InventoryHosts.id).limit(1).exists()
            LOGGER.info("Cyndi schema exists, OK")
            DB.close()
            break
        except DatabaseError:
            DB.rollback()
            LOGGER.info("Cyndi not initialized, waiting")
            sleep(2)
Esempio n. 10
0
    def handle_patch(cls, **kwargs):
        """Set status for a CVE"""
        data = kwargs['data']
        cve_list = data['cve']
        if isinstance(cve_list, str):
            cve_list = [cve_list]

        values = {}
        updated = []
        if 'status_id' in data:
            values['status_id'] = data['status_id']
        if 'status_text' in data:
            values['status_text'] = data['status_text'].strip(
            ) if data['status_text'].strip() else None
        if not values:
            return cls.format_exception(
                'At least one of the "status_id" or "status_text" parameters is required.',
                400)
        try:
            to_insert = []
            cves = CveMetadata.select(
                CveMetadata.id,
                CveMetadata.cve).where(CveMetadata.cve << cve_list)
            rh_account = RHAccount.select(RHAccount.id).where(
                RHAccount.name == connexion.context['user'])
            for cve in cves:
                updated.append(cve.cve)
                to_insert.append(
                    (cve.id, rh_account[0].id, values.get('status_id', 0),
                     values.get('status_text', None)))
            if not to_insert:
                return cls.format_exception(
                    'At least one given CVE must exist', 404)
            (CveAccountData.insert_many(
                to_insert, fields=cls._fields).on_conflict(
                    conflict_target=cls._conflict_target,
                    preserve=[],
                    update=values).execute())
        except (IntegrityError, psycopg2IntegrityError):
            # usually means bad status
            LOGGER.exception('Error during setting status (IntegrityError):')
            DB.rollback()
            return cls.format_exception(
                f'status_id=%s is invalid' % data['status_id'], 400)
        except ValueError as value_error:
            LOGGER.exception('Error during setting status (ValueError):')
            DB.rollback()
            return cls.format_exception(str(value_error), 500)
        return {'updated': updated}
    def handle_get(cls, **kwargs):
        rh_account_id = kwargs["rh_account_id"]
        try:
            tables = DB.execute_sql("""
                        SELECT tableoid::pg_catalog.regclass
                        FROM system_vulnerabilities
                        WHERE rh_account_id = %s""", (rh_account_id,))

            if tables.rowcount < 1:
                return "No tables to vacuum"

            command = ["pg_repack",
                       "-p", str(CFG.db_port), "-d", CFG.db_name,
                       "-h", CFG.db_host, "-U", CFG.db_user, "-k"]

            for table in tables:
                command.append("-t")
                command.append(table[0])

            LOGGER.info("Repacking tables %s", tables)
            subprocess.Popen(command, env={"PGPASSWORD": CFG.db_pass})

        except DatabaseError as err:
            LOGGER.exception("Internal server error: %s", err)
            return "Error"
        return "Ok"
 def handle_delete(cls, **kwargs):  # pylint: disable=unused-argument
     """Delete systems from system_platform table missing in inventory."""
     DB.execute_sql("""
         UPDATE system_platform sp
            SET opt_out = true, stale = true, when_deleted = now()
         FROM (
             SELECT sp2.inventory_id
             FROM system_platform sp2 LEFT JOIN
                  inventory.hosts ih ON sp2.inventory_id = ih.id
             WHERE ih.id IS NULL
               AND sp2.when_deleted IS NULL
             ORDER BY sp2.inventory_id
             FOR UPDATE OF sp2
         ) up
         WHERE sp.inventory_id = up.inventory_id
     """)
     return ""
    def handle_get(cls, **kwargs):
        rh_account_id = kwargs["rh_account_id"]
        result = []
        try:
            tables = DB.execute_sql("""
                        SELECT DISTINCT(tableoid::pg_catalog.regclass)
                        FROM system_vulnerabilities
                        WHERE rh_account_id = %s""", (rh_account_id,))

            for table in tables:
                res = DB.execute_sql("""SELECT * FROM pgstattuple(%s)""", (table[0],)).fetchone()
                res = cls.format_bloat_result(res)
                res["table_name"] = table[0]
                result.append(res)
        except DatabaseError as err:
            LOGGER.exception("Internal server error: %s", err)
        return {"tables": result}
    def handle_get(cls, **kwargs):
        table = kwargs["table_name"]
        try:
            res = DB.execute_sql("""SELECT * FROM pgstattuple(%s)""", (table,)).fetchone()
        except DatabaseError as err:
            LOGGER.exception("Internal server error: %s", err)
            return {}

        return cls.format_bloat_result(res)
 def handle_get(cls, **kwargs):  # pylint: disable=unused-argument
     """Get count of systems in system_platform table but missing in inventory."""
     cursor = DB.execute_sql("""
         SELECT COUNT(sp.inventory_id)
         FROM system_platform sp LEFT JOIN
              inventory.hosts ih ON sp.inventory_id = ih.id
         WHERE ih.id IS NULL
           AND sp.when_deleted IS NULL
     """)
     return cursor.fetchone()[0]
    def handle_get(cls, **kwargs):
        threshold = kwargs.get("ms_threshold", 0)
        username = kwargs.get("username", None)
        wait_event_type = kwargs.get("wait_event_type", None)

        result = []

        try:
            cursor = DB.execute_sql(
                """
                        SELECT pid, datname, usename, application_name,
                               query_start, now() - query_start AS running_time,
                               wait_event_type, wait_event, query
                        FROM pg_stat_activity
                        WHERE EXTRACT(MILLISECONDS FROM now() - query_start) >= %s AND
                              (usename = %s OR %s IS NULL) AND
                              (wait_event_type = %s OR %s IS NULL) AND
                              state = 'active'
                        """, (threshold, username, username, wait_event_type,
                              wait_event_type))
        except DatabaseError as err:
            LOGGER.exception("Internal server error: %s", err)
            return {"queries": result}

        for query in cursor:
            result.append({
                "pid": query[0],
                "db_name": query[1],
                "username": query[2],
                "app_name": query[3],
                "query_start": str(query[4]),
                "running_time": str(query[5]),
                "wait_event_type": query[6],
                "wait_event": query[7],
                "query": query[8]
            })

        return {"queries": result}
 def handle_delete(cls, **kwargs):
     """Delete system"""
     inventory_id = kwargs['inventory_id']
     cls._system_exists_and_visible(inventory_id)
     DB.execute_sql("SELECT delete_system(%s)", (inventory_id, ))
     return ""
 def handle_put(cls, **kwargs):
     """Refresh cached counts for given account ID."""
     account = kwargs.get("account_id", None)
     cls._account_exists(account)
     DB.execute_sql("SELECT refresh_account_cached_counts(%s)", (account, ))
     return ""
 def handle_put(cls, **kwargs):
     """Refresh cached counts for given CVE."""
     cve = kwargs.get("cve_id", None)
     cls._cve_exists(cve)
     DB.execute_sql("SELECT refresh_cve_cached_counts(%s)", (cve, ))
     return ""