Gestion des tâches programmées et des demandes de travail

Décrit comment gérer les tâches programmées et les demandes de travail du service de gestion du système d'exploitation.

Tâches programmées

Lorsque vous utilisez le service de gestion du système d'exploitation pour gérer les mises à jour d'une instance gérée ou d'un groupe d'instances gérées, vous avez un contrôle total sur le moment où les actions sont effectuées.

Si vous indiquez qu'une action doit être appliquée immédiatement, le service de gestion du système d'exploitation crée une demande de travail.

Si vous indiquez qu'une action doit être effectuée à une date et heure particulières, le service de gestion du système d'exploitation crée une tâche programmée. Il existe deux modes de base pour les tâches programmées :

  • Tâche programmée pour laquelle le travail est exécuté une seule fois.

    Vous pouvez programmer des tâches ponctuelles pour des tâches telles que l'installation d'une mise à jour ou d'un jeu de mises à jour. Ces tâches représentent des activités propres à un événement ponctuel. Par exemple, vous pouvez programmer une tâche ponctuelle en installant une version d'ensemble spécifique, comme Python, pour prendre en charge une application. Lors de la programmation de ces actions, vous avez la possibilité d'exécuter l'action immédiatement ou de choisir un programme personnalisé où vous pouvez sélectionner la date et l'heure auxquelles programmer une tâche ponctuelle.

  • Tâche programmée pour laquelle le travail est exécuté de façon répétée à un intervalle spécifié.

    Vous pouvez programmer des tâches récurrentes pour des tâches telles que l'installation de toutes les mises à jour disponibles pour un groupe d'instances gérées. Par exemple, vous pouvez programmer une tâche pour installer toutes les mises à jour de sécurité toutes les semaines à un moment donné. Lors de la programmation de ces actions, vous avez la possibilité d'exécuter l'action immédiatement ou de choisir un programme personnalisé où vous pouvez sélectionner la date et l'heure d'exécution initiales de la tâche, puis, au besoin, régler la tâche à Répéter à un intervalle spécifié (horaire, quotidien, hebdomadaire ou mensuel).

Lorsque la date et l'heure programmées sont atteintes, une ou plusieurs demandes de travail sont créées pour exécuter l'action. Vous disposez d'un contrôle total sur les tâches programmées. Vous pouvez les exécuter immédiatement, les supprimer ou ignorer une tâche récurrente. Le service de gestion du système d'exploitation tient à jour un historique complet des tâches programmées et des demandes de travail associées.

Note

Pour plus d'informations sur les tâches qui prennent en charge les tâches programmées, voir Gestion des ensembles Linux et Gestion des mises à jour Windows.

Demandes de travail

Les actions telles que l'installation ou la suppression des mises à jour sont asynchrones et lancent des demandes de travail. Vous pouvez utiliser la demande de travail pour suivre le statut des opérations, notamment la raison de l'échec d'une action. Le service de gestion du système d'exploitation tient à jour un historique complet des demandes de travail relatives aux instances gérées ou aux groupes d'instances gérées.

États des demandes de travail

Les états d'une demande de travail sont :

Acceptée
La demande se trouve dans la file d'attente des demandes de travail à traiter.
En cours
La demande de travail est en cours de traitement.
Réussite
La demande de travail a été traitée avec succès.
Échec
Le traitement de la demande de travail a échoué. Vous pouvez consulter les journaux de demande de travail pour identifier les problèmes et les résoudre.
Annulation
La demande de travail est en cours d'annulation.
Annulée
La demande de travail a été annulée.
Note

Le service de gestion du système d'exploitation nettoie les demandes de travail qui ont plus de 2 semaines, qui ont été terminées avec succès ou ont échoué. Toute demande de travail non démarrée ou en cours n'est pas nettoyée.

Utilisation de la console

Pour gérer les tâches programmées
  1. Ouvrez le menu de navigation et sélectionnez Calcul. Sous Gestion du système d'exploitation, sélectionnez Tâches programmées.
  2. Dans la section Portée de la liste, sélectionnez le compartiment qui contient les tâches programmées.
  3. À côté d'une tâche programmée, cliquez sur l'icône Actions (trois points) et sélectionnez une action :
    • Voir les détails : Afficher les instances touchées par la tâche et l'action à effectuer.
    • Exécuter maintenant : Remplacer le programme et effectuer la tâche immédiatement.
    • Ignorer : (Tâches programmées récurrentes uniquement) Reporter la tâche programmée à la prochaine occurrence programmée.
    • Supprimer : Annuler la tâche programmée.

Utilisation de l'API

Pour des informations sur l'utilisation de l'API et les demandes de signature, voir API REST et Données d'identification de sécurité. Pour plus d'informations à propos des trousses SDK, voir Trousses SDK et interface de ligne de commande.

Tâches programmées

Pour les tâches programmées, utilisez les opérations d'API suivantes :

Demandes de travail

Pour analyser les demandes de travail, utilisez les opérations d'API suivantes :

Pour une liste complète des opérations d'API disponibles pour le service de gestion de système d'exploitation, voir API de gestion de système d'exploitation.

Utilisation de la trousse SDK Python pour générer des rapports de conformité

Cette section montre comment exécuter un rapport de conformité de sécurité à l'aide d'un exemple de script Python (compliance_report.py) qui tire parti des API du service de gestion du système d'exploitation. L'exemple de script Python génère un rapport de conformité de sécurité, pour une location ou par compartiment, pour toutes les instances gérées pour lesquelles il manque des mises à jour de sécurité.

Note

La trousse SDK Python vous permet d'écrire du code pour gérer les ressources Oracle Cloud Infrastructure. Pour plus d'informations, voir Trousse SDK Python.
Conseil

Pour une démonstration vidéo expliquant comment exécuter un rapport de conformité en matière de sécurité, voir Vidéo : Créer un rapport de conformité pour les instances Linux.
compliance_report.py

#!/usr/bin/env python3

#
# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at
#  http://oss.oracle.com/licenses/upl
#

import os
import sys
import oci
import time
import logging
import logging.handlers

from argparse import ArgumentParser, ArgumentError, Namespace, SUPPRESS
from oci.os_management import OsManagementClient
from oci.identity import IdentityClient

PROGRAM_NAME = os.path.basename(sys.argv[0]).replace('.py', '')
PROGRAM_VERSION = '0.1.0'


def setup_logger(enable_logfile=False, verbose=False, debug=False):
    class LevelsFilter(logging.Filter):
        def __init__(self, levels, name=''):
            logging.Filter.__init__(self, name)
            self.levels = levels

        def filter(self, record):
            if record.levelno in self.levels:
                return True
            return False

    flat_formatter = logging.Formatter('{message}', style='{')
    level_formatter = logging.Formatter('{levelname:8s}: {message}', style='{')
    log_file_handler = None
    if enable_logfile or debug:
        try:
            formatter = logging.Formatter('{asctime} - {name} - {levelname}({module}:{lineno}) - {message}', style='{')
            log_file_handler = logging.handlers.RotatingFileHandler('{0}.log'.format(PROGRAM_NAME),
                                                                    mode='a',
                                                                    maxBytes=1024 * 1024,
                                                                    backupCount=3)
            log_file_handler.setFormatter(formatter)
            log_file_handler.setLevel(logging.NOTSET)
        except IOError:
            pass

    logger = logging.getLogger(PROGRAM_NAME)
    stdout_handler = logging.StreamHandler(stream=sys.stdout)
    stdout_handler.setFormatter(flat_formatter)
    logger.setLevel(logging.ERROR)
    if verbose:
        stdout_handler.addFilter(LevelsFilter([logging.INFO]))
        logger.setLevel(logging.INFO)
    if debug:
        log_file_handler.setFormatter(level_formatter)
        log_file_handler.addFilter(LevelsFilter([logging.DEBUG,
                                                 logging.INFO,
                                                 logging.WARNING,
                                                 logging.ERROR,
                                                 logging.CRITICAL]))
        logger.setLevel(logging.DEBUG)
    stderr_handler = logging.StreamHandler(stream=sys.stderr)
    stderr_handler.setFormatter(level_formatter)
    stderr_handler.addFilter(LevelsFilter([logging.WARNING, logging.ERROR, logging.CRITICAL]))
    if log_file_handler is not None:
        logger.addHandler(log_file_handler)
    logger.addHandler(stdout_handler)
    logger.addHandler(stderr_handler)
    return logger


class OCIClients(object):
    def __init__(self, options):
        self.compartment_id = options.compartment_id
        if options.use_instance_principles:
            config = {}
            if options.region is not None:
                config['region'] = options.region
            signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
            if self.compartment_id is None:
                self.compartment_id = signer.tenancy_id
            self.osms_client = OsManagementClient(config,
                                                  timeout=(10, 600),
                                                  retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY,
                                                  signer=signer)
            self.iam_client = IdentityClient(config,
                                             timeout=(10, 600),
                                             retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY,
                                             signer=signer)
        else:
            config = oci.config.from_file(file_location=options.config_file, profile_name=options.config_profile)
            if options.region is not None:
                config['region'] = options.region
            if self.compartment_id is None:
                self.compartment_id = config.get('tenancy')
            else:
                config['compartment'] = self.compartment_id
            self.osms_client = OsManagementClient(config,
                                                  timeout=(10, 600),
                                                  retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY)
            self.iam_client = IdentityClient(config,
                                             timeout=(10, 600),
                                             retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY)

    def get_osms_client(self):
        return self.osms_client

    def get_iam_client(self):
        return self.iam_client


class Data(object):
    def __init__(self):
        self.managed_instance_group_id = None
        self.total_instances = 0
        self.vulnerable_instances = []

    def show_overview(self):
        print()
        print('        Patch Compliance Report Sample')
        print('        ==============================')
        print()
        if self.managed_instance_group_id is not None:
            print('Managed Instance Group ID: {0}'.format(self.managed_instance_group_id))
        vulnerable_instances = len(self.vulnerable_instances) if len(self.vulnerable_instances) > 0 else 'None'
        linking_verb = 'are' if len(self.vulnerable_instances) > 1 else 'is'
        plural = 's' if self.total_instances > 1 else ''
        print('\nDetected out of {0} managed instance{1}, {2} {3} '
              'missing security patches!\n'.format(self.total_instances, plural, vulnerable_instances, linking_verb))

    def show_details(self):
        for instance in self.vulnerable_instances:
            print('Managed Instance {0} ({1})'.format(instance.get('display_name'), instance.get('id')))
            print(' has the following outstanding security patches:')
            for update in instance.get('security_updates', []):
                print('  {0}'.format(update.get('display_name')))
                if update.get('related_cves', None) is not None:
                    print('      CVEs:', end='')
                    num_cve = 0
                    num_cves = len(update.get('related_cves', []))
                    cve_line = ''
                    for cve in update.get('related_cves', []):
                        num_cve += 1
                        cve_line = '{0} {1:<17}'.format(cve_line, cve + ',')
                        if len(cve_line) >= 65:
                            if num_cve < num_cves:
                                print(cve_line.rstrip(' '))
                                print('           ', end='')
                            else:
                                print(cve_line.rstrip(', '))
                            cve_line = ''
                    if cve_line != '':
                        print(cve_line.rstrip(', '))
            print()


def find_all_compartments(iam_client, compartment_id):
    LOGGER.info('Find sub compartments')
    compartment_ids = [compartment_id]
    if compartment_id.startswith('ocid1.tenancy.'):
        c_response = iam_client.list_compartments(compartment_id, compartment_id_in_subtree=True)
        compartment_ids.extend([c.id for c in c_response.data
                                if c.lifecycle_state == 'ACTIVE' and c.name != 'ManagedCompartmentForPaaS'])
    else:
        compartment_ids.extend(list_compartments(iam_client, compartment_ids))
    return compartment_ids


def list_compartments(iam_client, compartments):
    if compartments is None:
        return []
    sub_compartments = []
    for compartment in compartments:
        LOGGER.debug('List Compartment: {0}'.format(compartment))
        c_response = iam_client.list_compartments(compartment)
        sub_compartments.extend([c.id for c in c_response.data
                                 if c.lifecycle_state == 'ACTIVE' and c.name != 'ManagedCompartmentForPaaS'])
        sub_names = [c.name for c in c_response.data
                     if c.lifecycle_state == 'ACTIVE' and c.name != 'ManagedCompartmentForPaaS']
        LOGGER.debug('Sub Compartments: {0}'.format(sub_names))
        sub_compartments.extend(list_compartments(iam_client, sub_compartments))
    return sub_compartments


def query_managed_instance_group(osms_client, managed_instance_group_id):
    LOGGER.info('Retrieving Managed Instance Group ({0}) info'.format(managed_instance_group_id))
    mig_response = osms_client.get_managed_instance_group(managed_instance_group_id)
    total_instances, vuln_instances = query_managed_instances(osms_client, mig_response.data.managed_instances)
    return total_instances, vuln_instances


def query_compartment(osms_client, compartment_id):
    LOGGER.info('Retrieving Managed Instance list from compartment "{0}"'.format(compartment_id))
    request_options = {'limit':      10,
                       'sort_by':    'TIMECREATED',
                       'sort_order': 'ASC',
                       }
    managed_instances = []
    next_page = None
    has_next_page = True
    while has_next_page:
        if next_page is not None:
            request_options['page'] = next_page
        elif request_options.get('page', False):
            request_options.pop('page')
        try:
            mil_response = osms_client.list_managed_instances(compartment_id)  # , **request_options)
        except oci.exceptions.ServiceError as service_error:
            LOGGER.info('Service Exception "{0}")'.format(service_error.code))
            LOGGER.debug('OCI Request ID: "{0}"'.format(service_error.request_id))
            raise
        if mil_response is None:
            raise RuntimeError('Unable to retrieve updates from compartment {0}'.format(compartment_id))
        has_next_page = mil_response.has_next_page
        next_page = mil_response.next_page
        managed_instances.extend(mil_response.data)
    total_instances, vuln_instances = query_managed_instances(osms_client, managed_instances)
    return total_instances, vuln_instances


def query_managed_instances(osms_client, managed_instances):
    vuln_instances = []
    total_instances = len(managed_instances)
    for mi in managed_instances:
        LOGGER.info('Retrieving Managed Instance "{0}" info'.format(mi.display_name))
        mi_response = osms_client.get_managed_instance(mi.id)
        mi_data = mi_response.data
        LOGGER.debug('Managed Instance: {0}'.format(mi_data))
        linux_mi = mi_data.os_family == 'LINUX'
        available_security_updates = 0
        security_updates = []
        updates = None
        if mi_data.updates_available > 0:
            LOGGER.info('Retrieving Update info for Managed Instance "{0}"'.format(mi.display_name))
            request_options = {'limit':      10,
                               'sort_by':    'TIMECREATED',
                               'sort_order': 'ASC',
                               }
            next_page = None
            has_next_page = True
            while has_next_page:
                if next_page is not None:
                    request_options['page'] = next_page
                elif request_options.get('page', False):
                    request_options.pop('page')
                try:
                    if linux_mi:
                        updates = osms_client.list_available_updates_for_managed_instance(mi.id, **request_options)
                    else:
                        updates = osms_client.list_available_windows_updates_for_managed_instance(mi.id,
                                                                                                  **request_options)
                except oci.exceptions.ServiceError as service_error:
                    LOGGER.info('Service Exception "{0}")'.format(service_error.code))
                    LOGGER.debug('OCI Request ID: "{0}"'.format(service_error.request_id))
                if updates is None:
                    raise RuntimeError('Unable to retrieve updates from {0}'.format(mi.display_name))
                has_next_page = updates.has_next_page
                next_page = updates.next_page
                for update in updates.data:
                    LOGGER.debug('Update: {0}'.format(update))
                    if update.update_type == 'SECURITY':
                        available_security_updates += 1
                        if linux_mi:
                            security_updates.append({'display_name': update.display_name,
                                                     'related_cves': update.related_cves})
                        else:
                            security_updates.append({'display_name': update.display_name})
            if available_security_updates > 0:
                managed_instance = {
                        'compartment_id':             mi_data.compartment_id,
                        'display_name':               mi_data.display_name,
                        'id':                         mi_data.id,
                        'is_reboot_required':         mi_data.is_reboot_required,
                        'last_boot':                  mi_data.last_boot,
                        'last_checkin':               mi_data.last_checkin,
                        'managed_instance_groups':    mi_data.managed_instance_groups,
                        'os_family':                  mi_data.os_family,
                        'os_kernel_version':          mi_data.os_kernel_version,
                        'os_name':                    mi_data.os_name,
                        'os_version':                 mi_data.os_version,
                        'status':                     mi_data.status,
                        'updates_available':          mi_data.updates_available,
                        'security_updates_available': available_security_updates,
                        'security_updates':           security_updates
                }
                vuln_instances.append(managed_instance)
    return total_instances, vuln_instances


def main(argv=None):
    if argv is None:
        argv = sys.argv
    program_version_message = '{0} {1}'.format(PROGRAM_NAME, PROGRAM_VERSION)
    program_description = 'OS Management Reporting'
    options = Namespace()
    try:
        the_parser = ArgumentParser(description=program_description)
        select_grp = the_parser.add_mutually_exclusive_group()
        authop_grp = the_parser.add_mutually_exclusive_group()
        the_parser.add_argument('--compartment-ocid', '-c',
                                dest='compartment_id',
                                action='store',
                                default=None,
                                required=True,
                                help="Compartment to run query against, defaults to the root compartment")
        the_parser.add_argument('--region', '-r',
                                dest='region',
                                action='store',
                                default=None,
                                required=False,
                                help="Region to run query against")
        authop_grp.add_argument('--use-instance-principles', '-I',
                                dest='use_instance_principles',
                                action='store_true',
                                default=False,
                                required=False,
                                help="Authenticate using Instance Principles")
        select_grp.add_argument('--managed-instance-group-ocid', '-g',
                                dest='managed_instance_group_id',
                                action='store',
                                default=None,
                                required=False,
                                help="Managed Instance Group to query")
        authop_grp.add_argument('--oci-config', '-C',
                                dest='config_file',
                                action='store',
                                default=os.path.join('~', '.oci', 'config'),
                                required=False,
                                help="Oracle Cloud Infrastructure config file")
        the_parser.add_argument('--oci-config-profile', '-P',
                                dest='config_profile',
                                action='store',
                                default='DEFAULT',
                                required=False,
                                help="Oracle Cloud Infrastructure config profile to use")
        the_parser.add_argument('--show-details', '-d',
                                dest='show_details',
                                action='store_true',
                                default=False,
                                required=False,
                                help='Show detailed report')
        select_grp.add_argument('--recursive', '-R',
                                dest='scan_sub_compartments',
                                action='store_true',
                                default=False,
                                required=False,
                                help='Recursively scan sub-compartments')
        the_parser.add_argument('--verbose', '-v',
                                dest='verbose',
                                action='store_true',
                                default=False,
                                required=False,
                                help='Enable verbose mode')
        the_parser.add_argument("--version",
                                action="version",
                                version=program_version_message)
        the_parser.add_argument("--debug",
                                dest='debug_enabled',
                                action='store_true',
                                default=False,
                                required=False,
                                help=SUPPRESS)
        the_parser.parse_args(args=argv[1:], namespace=options)
    except ArgumentError:
        return 1
    # noinspection PyGlobalUndefined
    global LOGGER
    LOGGER = setup_logger(verbose=options.verbose, debug=options.debug_enabled)
    oci_clients = OCIClients(options)
    data = Data()
    if options.managed_instance_group_id is not None:
        total_instances, vulnerable_instances = query_managed_instance_group(oci_clients.osms_client,
                                                                             options.managed_instance_group_id)
        data.total_instances += total_instances
        data.vulnerable_instances.extend(vulnerable_instances)
        data.managed_instance_group_id = options.managed_instance_group_id
        LOGGER.debug('MIG Query: Total Instances {0}, Vulnerable Instances {1}'.format(total_instances,
                                                                                       vulnerable_instances))
    else:
        compartment_ids = [options.compartment_id]
        if options.scan_sub_compartments:
            compartment_ids = find_all_compartments(oci_clients.iam_client, options.compartment_id)
        for compartment_id in compartment_ids:
            total_instances, vulnerable_instances = query_compartment(oci_clients.osms_client, compartment_id)
            data.total_instances += total_instances
            data.vulnerable_instances.extend(vulnerable_instances)
            LOGGER.debug('Compartment ({0}) Instances: Total {1}, Vulnerable {2}'.format(compartment_id,
                                                                                         total_instances,
                                                                                         len(vulnerable_instances)))
    data.show_overview()
    if options.show_details:
        data.show_details()
    return 0


if __name__ == '__main__':
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        print('\n{0}: Cancelled by user'.format(PROGRAM_NAME))
        sys.exit(127)
Pour exécuter un rapport de conformité de sécurité à l'aide du script compliance_report.py

  1. Assurez-vous que Python est installé.

    Par exemple, exécutez la commande suivante dans Oracle Linux :

    sudo yum install python3 -y
  2. Dans un éditeur de fichiers tel que vi, créez l'exemple de script Python utilisé pour cet exemple compliance_report.py.

    Par exemple :

    sudo vi compliance_report.py
  3. Copiez le contenu de compliance_report.py dans votre fichier.
  4. Rendez le script exécutable.

    Par exemple :

    chmod +x compliance_report.py
  5. Exécutez le script pour générer un rapport de conformité de sécurité.

    Pour voir les options disponibles pour exécuter le script, lancez le script compliance_report.py avec l'option --help.

    # python3 compliance_report.py --help
    usage: compliance_report.py [-h] --compartment-ocid COMPARTMENT_ID
                                [--region REGION] [--use-instance-principles]
                                [--managed-instance-group-ocid MANAGED_INSTANCE_GROUP_ID]
                                [--oci-config CONFIG_FILE]
                                [--oci-config-profile CONFIG_PROFILE]
                                [--show-details] [--recursive] [--verbose]
                                [--version]
    
    OS Management Reporting
    
    optional arguments:
      -h, --help            show this help message and exit
      --compartment-ocid COMPARTMENT_ID, -c COMPARTMENT_ID
                            Compartment to run query against, defaults to the root
                            compartment
      --region REGION, -r REGION
                            Region to run query against
      --use-instance-principles, -I
                            Authenticate using Instance Principles
      --managed-instance-group-ocid MANAGED_INSTANCE_GROUP_ID, -g MANAGED_INSTANCE_GROUP_ID
                            Managed Instance Group to query
      --oci-config CONFIG_FILE, -C CONFIG_FILE
                            Oracle Cloud Infrastructure config file
      --oci-config-profile CONFIG_PROFILE, -P CONFIG_PROFILE
                            Oracle Cloud Infrastructure config profile to use
      --show-details, -d    Show detailed report
      --recursive, -R       Recursively scan sub-compartments
      --verbose, -v         Enable verbose mode
      --version             show program's version number and exit
    Important

    Lors de l'utilisation du script compliance_report.py, tenez compte des directives d'utilisation suivantes :

    • Vous devez disposer des autorisations appropriées permettant de lire et d'interroger le compartiment pour exécuter avec succès cet exemple de script.
    • L'option --compartment-ocid est obligatoire. Pour Compartment_ID, spécifiez l'OCID de la location (le compartiment racine) ou l'OCID d'un compartiment dans la location.
    • L'option --use-instance-principles définit le script à authentifier à l'aide des principes d'instance Oracle Cloud Infrastructure. Si vous n'utilisez pas cette option, vous devez avoir un profil défini dans ~/.oci/config.
    • L'option --recursive génère le rapport pour le compartiment et tous les sous-compartiments dans cette région. Vous ne pouvez pas utiliser l'option --recursive avec des groupes d'instances gérées. Si vous exécutez le rapport au niveau du compartiment, n'utilisez pas l'option --recursive.
    • Lorsque vous utilisez l'option --show details, la sortie affiche une liste détaillée des correctifs de sécurité spécifiques manquants pour chaque instance gérée. Si vous exécutez le script sans cette option, la sortie met en évidence uniquement les instances gérées manquantes et le nombre de mises à jour manquantes.
    • L'option --region est facultative.
      • Si vous avez spécifié une région spécifique dans ~/.oci/config, vous pouvez utiliser l'option --region pour remplacer cette région par celle que vous spécifiez pour ce paramètre.
      • Si vous utilisez des principes d'instance, vous pouvez exécuter le script dans une région et utiliser l'option --region pour cibler une autre région.

    L'exemple suivant montre comment générer un exemple de rapport à l'aide du script compliance_report.py :

    # python3 compliance_report.py --use-instance-principles --compartment-ocid=ocid1.tenancy.oc1..<unique_ID> --recursive --show-details --region=eu-zurich-1
    
            Patch Compliance Report Sample
            ==============================
    
    
    Detected out of 7 managed instances, 7 are missing security patches!
    
    Managed Instance sqa-test-prod-zurich-win2019srvstd (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      2020-04 Cumulative Update for Windows Server 2019 (1809) for x64-based Systems (KB4549949)
    
    Managed Instance sqa-test-prod-zurich-win2016srvstd (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      Security Intelligence Update for Windows Defender Antivirus - KB2267602 (Version 1.315.54.0)
      2020-04 Servicing Stack Update for Windows Server 2016 for x64-based Systems (KB4550994)
    
    Managed Instance sqa-test-prod-zurich-win2012srvstd (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      2020-04 Security Monthly Quality Rollup for Windows Server 2012 R2 for x64-based Systems (KB4550961)
    
    Managed Instance sqatest-ol6-0 (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      libcurl
          CVEs: CVE-2019-5482
      python
          CVEs: CVE-2018-20852
      kernel-uek-firmware
          CVEs: CVE-2018-5953,    CVE-2019-18806,   CVE-2020-10942
      python-libs
          CVEs: CVE-2018-20852
      sudo
          CVEs: CVE-2019-18634
      curl
          CVEs: CVE-2019-5482
      kernel-uek
          CVEs: CVE-2018-5953,    CVE-2019-18806,   CVE-2020-10942
      kernel
          CVEs: CVE-2017-1000371, CVE-2019-17666
      libicu
          CVEs: CVE-2020-10531
    
    Managed Instance sqatest-ol7-0 (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      kernel-tools-libs
          CVEs: CVE-2015-9289,    CVE-2017-17807,   CVE-2018-19985,   CVE-2018-20169,
                CVE-2018-7191,    CVE-2019-10207,   CVE-2019-10638,   CVE-2019-10639,
                CVE-2019-11190,   CVE-2019-11884,   CVE-2019-12382,   CVE-2019-13233,
                CVE-2019-13648,   CVE-2019-14283,   CVE-2019-15916,   CVE-2019-16746,
                CVE-2019-18660,   CVE-2019-3901,    CVE-2019-9503
      sqlite
          CVEs: CVE-2019-13734
      python
          CVEs: CVE-2018-20852,   CVE-2019-16056
      kernel-uek
          CVEs: CVE-2018-5953,    CVE-2019-18806,   CVE-2019-18809,   CVE-2020-10942
      python-libs
          CVEs: CVE-2018-20852,   CVE-2019-16056
      file
          CVEs: CVE-2018-10360
      file-libs
          CVEs: CVE-2018-10360
      curl
          CVEs: CVE-2019-5436
      libcurl
          CVEs: CVE-2019-5436
      mariadb-libs
          CVEs: CVE-2019-2737,    CVE-2019-2739,    CVE-2019-2740,    CVE-2019-2805
      kernel-tools
          CVEs: CVE-2015-9289,    CVE-2017-17807,   CVE-2018-19985,   CVE-2018-20169,
                CVE-2018-7191,    CVE-2019-10207,   CVE-2019-10638,   CVE-2019-10639,
                CVE-2019-11190,   CVE-2019-11884,   CVE-2019-12382,   CVE-2019-13233,
                CVE-2019-13648,   CVE-2019-14283,   CVE-2019-15916,   CVE-2019-16746,
                CVE-2019-18660,   CVE-2019-3901,    CVE-2019-9503
    
    Managed Instance sqatest-ol8-0 (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      sudo
          CVEs: CVE-2019-18634
      grub2-pc
          CVEs: CVE-2019-14865
      kernel
          CVEs: CVE-2019-15030,   CVE-2019-15031,   CVE-2019-18660,   CVE-2019-19527
      grub2-pc-modules
          CVEs: CVE-2019-14865
      sqlite-libs
          CVEs: CVE-2019-13734
      grub2-tools
          CVEs: CVE-2019-14865
      grub2-tools-minimal
          CVEs: CVE-2019-14865
      grub2-common
          CVEs: CVE-2019-14865
      bpftool
          CVEs: CVE-2019-15030,   CVE-2019-15031,   CVE-2019-18660,   CVE-2019-19527
      nss
          CVEs: CVE-2019-11745
      kernel-modules
          CVEs: CVE-2019-15030,   CVE-2019-15031,   CVE-2019-18660,   CVE-2019-19527
      libarchive
          CVEs: CVE-2019-18408
      grub2-tools-extra
          CVEs: CVE-2019-14865
      kernel-tools
          CVEs: CVE-2019-15030,   CVE-2019-15031,   CVE-2019-18660,   CVE-2019-19527
      nss-util
          CVEs: CVE-2019-11745
      kernel-tools-libs
          CVEs: CVE-2019-15030,   CVE-2019-15031,   CVE-2019-18660,   CVE-2019-19527
      nss-sysinit
          CVEs: CVE-2019-11745
    
    Managed Instance wb-zrh-cli-test (ocid1.instance.oc1.eu-zurich-1..<unique_ID>)
     has the following outstanding security patches:
      Security Intelligence Update for Windows Defender Antivirus - KB2267602 (Version 1.315.38.0)
      2020-04 Cumulative Update for Windows Server 2019 (1809) for x64-based Systems (KB4549949)