Gestione dei job e delle richieste di lavoro pianificate

Viene descritto come gestire i job pianificati e le richieste di lavoro di Gestione del sistema operativo.

Job pianificati

Quando si utilizza il servizio Gestione sistema operativo per gestire gli aggiornamenti su un'istanza gestita o su un gruppo di istanze gestite, si ha il controllo completo su quando vengono eseguite le azioni.

Se si specifica che un'azione viene eseguita immediatamente, il servizio Gestione sistema operativo crea una richiesta di lavoro.

Se si specifica che un'azione deve essere eseguita in una data e un'ora specifiche, il servizio Gestione sistema operativo crea un job pianificato. Sono disponibili due modalità di base per i job pianificati:

  • Job pianificato in cui il job viene eseguito una sola volta.

    È possibile pianificare job occasionali per attività quali l'installazione di un aggiornamento o di un set di aggiornamenti. Questi task rappresentano attività specifiche di un evento occasionale. Ad esempio, è possibile pianificare un job occasionale installando una versione di pacchetto specifica, come Python, per supportare un'applicazione. Quando si pianificano queste azioni, è possibile eseguire immediatamente l'azione oppure scegliere una pianificazione personalizzata in cui selezionare la data e ora in cui pianificare un job occasionale.

  • Job pianificato in cui il job si ripete a un intervallo specificato.

    È possibile pianificare job ricorrenti per task quali l'installazione di tutti gli aggiornamenti disponibili per un gruppo di istanze gestite. Ad esempio, è possibile pianificare un job per installare tutti gli aggiornamenti di sicurezza ogni settimana in un determinato momento. Quando si pianificano queste azioni, è possibile eseguire immediatamente l'azione oppure scegliere una pianificazione personalizzata in cui è possibile selezionare Data e ora per eseguire inizialmente il job, quindi facoltativamente impostare il job su Ripeti a un intervallo specificato (Orario, Giornaliero, Settimanale o Mensile).

Quando vengono raggiunte la data e l'ora schedulate, vengono create una o più richieste di lavoro per eseguire l'azione. Si dispone del controllo completo sui job pianificati, per eseguirli immediatamente, per eliminarli o per saltare un job ricorrente. Il servizio Gestione sistema operativo gestisce una cronologia completa dei job pianificati e delle richieste di lavoro associate.

Nota

Per ulteriori informazioni sulle attività che supportano i job pianificati, vedere Gestione di package Linux e Gestione degli aggiornamenti di Windows.

Richieste di lavoro

Azioni come l'installazione o la rimozione di aggiornamenti sono asincrone e avviano le richieste di lavoro. È possibile utilizzare la richiesta di lavoro per tenere traccia dello stato di queste operazioni, inclusa la possibilità di vedere perché un'azione non è riuscita. Il servizio Gestione sistema operativo gestisce una cronologia completa delle richieste di lavoro sulle istanze gestite o sui gruppi di istanze gestite.

Stati richiesta di lavoro

Gli stati della richiesta di lavoro sono:

Data di accettazione
La richiesta si trova nella coda delle richieste di lavoro da elaborare.
In corso
Elaborazione della richiesta di lavoro in corso.
Operazione riuscita
Elaborazione della richiesta di lavoro riuscita.
Errore
Impossibile elaborare la richiesta di lavoro. È possibile esaminare i log delle richieste di lavoro per identificare i problemi, quindi risolverli.
Annullamento in corso
Annullamento della richiesta di lavoro in corso.
Operazione annullata
La richiesta di lavoro è stata annullata.
Nota

Il servizio Gestione sistema operativo esegue il cleanup delle richieste di lavoro che risalgono a più di 2 settimane e che sono state completate correttamente o non sono riuscite. Il cleanup di qualsiasi richiesta di lavoro non avviata o in corso non viene eseguito.

Utilizzo di Console

Per gestire i job pianificati
  1. Aprire il menu di navigazione e selezionare Computazione. In Gestione sistema operativo, selezionare Job schedulati.
  2. Nella sezione Ambito elenco, selezionare il compartimento che contiene i job pianificati.
  3. Accanto a un job pianificato, fare clic sull'icona Azioni (tre punti) e selezionare un'azione:
    • Visualizza dettagli: vedere le istanze interessate dal job e l'azione da eseguire.
    • Esegui ora: esegue l'override della pianificazione ed esegue immediatamente il job.
    • Salta: (solo job pianificati ricorrenti) ritarda il job pianificato fino alla successiva ricorrenza programmata.
    • Elimina: consente di annullare il job pianificato.

Uso dell'API

Per informazioni sull'uso dell'API e delle richieste di firma, vedere API REST e Credenziali di sicurezza. Per informazioni sugli SDK, consulta Software Development Kits e interfaccia della riga di comando.

Job pianificati

Utilizzare le seguenti operazioni API per l'utilizzo dei job pianificati:

Richieste di lavoro

Utilizzare le operazioni API riportate di seguito per analizzare le richieste di lavoro.

Per un elenco completo delle operazioni API disponibili per il servizio Gestione sistema operativo, vedere API di gestione del sistema operativo.

Utilizzo dell'SDK Python per generare report di conformità

In questa sezione viene illustrato come eseguire un report di conformità alla sicurezza utilizzando uno script Python di esempio (compliance_report.py) che utilizza le API Gestione sistema operativo. Lo script Python di esempio genera un report sulla conformità della sicurezza, in una tenancy o per compartimento, per tutte le istanze gestite a cui mancano gli aggiornamenti della sicurezza.

Nota

L'SDK Python consente di scrivere codice per gestire le risorse di Oracle Cloud Infrastructure. Per ulteriori informazioni, vedere SDK Python.
Suggerimento

Per una dimostrazione video che mostra come eseguire un report sulla conformità alla sicurezza, vedere Video: Creare un report sulla conformità per le istanze 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)
Per eseguire un report di conformità alla sicurezza utilizzando lo script compliance_report.py

  1. Assicurarsi che Python sia installato.

    Ad esempio, eseguire il seguente comando su Oracle Linux:

    sudo yum install python3 -y
  2. In un editor di file come vi, creare lo script Python di esempio utilizzato per questo esempio, compliance_report.py.

    Ad esempio:

    sudo vi compliance_report.py
  3. Copiare il contenuto di compliance_report.py nel file.
  4. Rendere lo script eseguibile.

    Ad esempio:

    chmod +x compliance_report.py
  5. Eseguire lo script per generare un report di conformità alla sicurezza.

    Per visualizzare le opzioni disponibili per l'esecuzione dello script, eseguire lo script compliance_report.py con l'opzione --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
    Importante

    Quando si utilizza lo script compliance_report.py, tenere presenti le seguenti istruzioni d'uso:

    • Per eseguire correttamente questo script di esempio, è necessario disporre delle autorizzazioni appropriate per leggere e interrogare il compartimento.
    • L'opzione --compartment-ocid è obbligatoria. Per Compartment_ID, specificare l'OCID della tenancy (compartimento radice) o l'OCID per un compartimento nella tenancy.
    • L'opzione --use-instance-principles imposta lo script per l'autenticazione utilizzando i principi dell'istanza di Oracle Cloud Infrastructure. Se questa opzione non viene utilizzata, è necessario configurare un profilo in ~/.oci/config.
    • L'opzione --recursive genera il report per il compartimento e tutti i compartimenti secondari all'interno dell'area. Non è possibile utilizzare l'opzione --recursive con i gruppi di istanze gestite. Se si esegue il report a livello di compartimento, non utilizzare l'opzione --recursive.
    • Quando si utilizza l'opzione --show details, nell'output viene visualizzato un elenco dettagliato delle patch di sicurezza specifiche mancanti per ogni istanza gestita. Se si esegue lo script senza questa opzione, nell'output vengono evidenziati solo gli aggiornamenti mancanti nelle istanze gestite e il numero di aggiornamenti mancanti.
    • L'opzione --region è facoltativa.
      • Se è stata specificata un'area specifica in ~/.oci/config, è possibile utilizzare l'opzione --region per sostituire quest'area con quella specificata per questo parametro.
      • Se si utilizzano i principi dell'istanza, è possibile eseguire lo script in un'area e utilizzare l'opzione --region per definire la destinazione di un'area diversa.

    L'esempio riportato di seguito mostra come generare un report di esempio utilizzando lo 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)