def install_updates()

in src/core/src/core_logic/PatchInstaller.py [0:0]


    def install_updates(self, maintenance_window, package_manager, simulate=False):
        """wrapper function of installing updates"""
        self.composite_logger.log("\n\nGetting available updates...")
        package_manager.refresh_repo()

        packages, package_versions = package_manager.get_available_updates(self.package_filter)  # Initial, ignoring exclusions
        self.telemetry_writer.write_event("Initial package list: " + str(packages), Constants.TelemetryEventLevel.Verbose)

        not_included_packages, not_included_package_versions = self.get_not_included_updates(package_manager, packages)
        self.telemetry_writer.write_event("Not Included package list: " + str(not_included_packages), Constants.TelemetryEventLevel.Verbose)

        excluded_packages, excluded_package_versions = self.get_excluded_updates(package_manager, packages, package_versions)
        self.telemetry_writer.write_event("Excluded package list: " + str(excluded_packages), Constants.TelemetryEventLevel.Verbose)

        packages, package_versions = self.filter_out_excluded_updates(packages, package_versions, excluded_packages)  # honoring exclusions

        # For ubuntu VMs, filter out esm_packages, if the VM is not attached.
        # These packages will already be marked with version as 'UA_ESM_REQUIRED'.
        # Esm packages will not be dependent packages to non-esm packages. This is confirmed by Canonical. So, once these are removed from processing, we need not worry about handling it in our batch / sequential patch processing logic.
        # Adding this after filtering excluded packages, so we don`t un-intentionally mark excluded esm-package status as failed.
        packages, package_versions, self.skipped_esm_packages, self.skipped_esm_package_versions, self.esm_packages_found_without_attach = package_manager.separate_out_esm_packages(packages, package_versions)

        self.telemetry_writer.write_event("Final package list: " + str(packages), Constants.TelemetryEventLevel.Verbose)

        # Set initial statuses
        if not package_manager.get_package_manager_setting(Constants.PACKAGE_MGR_SETTING_REPEAT_PATCH_OPERATION, False):  # 'Not included' list is not accurate when a repeat is required
            self.status_handler.set_package_install_status(not_included_packages, not_included_package_versions, Constants.NOT_SELECTED)
        self.status_handler.set_package_install_status(excluded_packages, excluded_package_versions, Constants.EXCLUDED)
        self.status_handler.set_package_install_status(packages, package_versions, Constants.PENDING)
        self.status_handler.set_package_install_status(self.skipped_esm_packages, self.skipped_esm_package_versions, Constants.FAILED)
        self.composite_logger.log("\nList of packages to be updated: \n" + str(packages))

        sec_packages, sec_package_versions = self.package_manager.get_security_updates()
        self.telemetry_writer.write_event("Security packages out of the final package list: " + str(sec_packages), Constants.TelemetryEventLevel.Verbose)
        self.status_handler.set_package_install_status_classification(sec_packages, sec_package_versions, classification="Security")

        # Set the security-esm package status.
        package_manager.set_security_esm_package_status(Constants.INSTALLATION, packages)

        self.composite_logger.log("\nNote: Packages that are neither included nor excluded may still be installed if an included package has a dependency on it.")
        # We will see this as packages going from NotSelected --> Installed. We could remove them preemptively from not_included_packages, but we're explicitly choosing not to.

        self.composite_logger.log("[Progress Legend: (A)ttempted, (S)ucceeded, (F)ailed, (D)ependencies est.* (Important: Dependencies are excluded in all other counts)]")
        installed_update_count = 0  # includes dependencies

        patch_installation_successful = True
        maintenance_window_exceeded = False
        all_packages, all_package_versions = package_manager.get_all_updates(cached=False)
        self.telemetry_writer.write_event("All available packages list: " + str(all_packages), Constants.TelemetryEventLevel.Verbose)
        self.last_still_needed_packages = list(all_packages)
        self.last_still_needed_package_versions = list(all_package_versions)

        packages, package_versions, install_update_count_in_batch_patching, patch_installation_successful = self.batch_patching(all_packages, all_package_versions,
                                                                                                                packages, package_versions, maintenance_window,
                                                                                                                package_manager)

        installed_update_count = install_update_count_in_batch_patching
        attempted_parent_package_install_count_in_batch_patching = self.attempted_parent_package_install_count
        successful_parent_package_install_count_in_batch_patching = self.successful_parent_package_install_count

        if len(packages) == 0:
            self.log_final_metrics(maintenance_window, patch_installation_successful, maintenance_window_exceeded, installed_update_count)
            return installed_update_count, patch_installation_successful, maintenance_window_exceeded
        else:
            progress_status = self.progress_template.format(str(datetime.timedelta(minutes=maintenance_window.get_remaining_time_in_minutes())), str(self.attempted_parent_package_install_count), str(self.successful_parent_package_install_count), str(self.failed_parent_package_install_count), str(installed_update_count - self.successful_parent_package_install_count),
                                                        "Following packages are not attempted or failed in batch installation: " + str(packages))
            self.composite_logger.log(progress_status)

        stopwatch_for_sequential_install_process = Stopwatch(self.env_layer, self.telemetry_writer, self.composite_logger)
        stopwatch_for_sequential_install_process.start()

        for package, version in zip(packages, package_versions):
            if package not in self.last_still_needed_packages:
                self.composite_logger.log("The following package is already installed, it could have been installed as dependent package of some other package: " + package)
                self.attempted_parent_package_install_count += 1
                self.successful_parent_package_install_count += 1
                continue

            single_package_install_stopwatch = Stopwatch(self.env_layer, self.telemetry_writer, self.composite_logger)
            single_package_install_stopwatch.start()
            # Extension state check
            if self.lifecycle_manager is not None:
                self.lifecycle_manager.lifecycle_status_check()     # may terminate the code abruptly, as designed

            # maintenance window check
            remaining_time = maintenance_window.get_remaining_time_in_minutes()
            if maintenance_window.is_package_install_time_available(package_manager, remaining_time, number_of_packages_in_batch=1) is False:
                error_msg = "Stopped patch installation as it is past the maintenance window cutoff time."
                self.composite_logger.log_error("\n" + error_msg)
                self.status_handler.add_error_to_status(error_msg, Constants.PatchOperationErrorCodes.DEFAULT_ERROR)
                maintenance_window_exceeded = True
                self.status_handler.set_maintenance_window_exceeded(True)
                break

            # point in time status
            progress_status = self.progress_template.format(str(datetime.timedelta(minutes=remaining_time)), str(self.attempted_parent_package_install_count), str(self.successful_parent_package_install_count), str(self.failed_parent_package_install_count), str(installed_update_count - self.successful_parent_package_install_count),
                                                            "Processing package: " + str(package) + " (" + str(version) + ")")

            self.composite_logger.log(progress_status)

            # include all dependencies (with specified versions) explicitly
            # package_and_dependencies initially contains only one package. The dependencies are added in the list by method include_dependencies
            package_and_dependencies = [package]
            package_and_dependency_versions = [version]
            
            self.include_dependencies(package_manager, [package], [version], all_packages, all_package_versions, packages, package_versions, package_and_dependencies, package_and_dependency_versions)

            # parent package install (+ dependencies) and parent package result management
            install_result = package_manager.install_update_and_dependencies_and_get_status(package_and_dependencies, package_and_dependency_versions, simulate)

            # Update reboot pending status in status_handler
            self.status_handler.set_reboot_pending(self.package_manager.is_reboot_pending())

            if install_result == Constants.FAILED:
                self.status_handler.set_package_install_status(package_manager.get_product_name(str(package_and_dependencies[0])), str(package_and_dependency_versions[0]), Constants.FAILED)
                self.failed_parent_package_install_count += 1
                patch_installation_successful = False
            elif install_result == Constants.INSTALLED:
                self.status_handler.set_package_install_status(package_manager.get_product_name(str(package_and_dependencies[0])), str(package_and_dependency_versions[0]), Constants.INSTALLED)
                self.successful_parent_package_install_count += 1
                if package in self.last_still_needed_packages:
                    index = self.last_still_needed_packages.index(package)
                    self.last_still_needed_packages.pop(index)
                    self.last_still_needed_package_versions.pop(index)
                    installed_update_count += 1
            self.attempted_parent_package_install_count += 1

            number_of_dependencies_installed = 0
            number_of_dependencies_failed = 0
            # dependency package result management
            for dependency, dependency_version in zip(package_and_dependencies, package_and_dependency_versions):
                if dependency not in self.last_still_needed_packages or dependency == package:
                    continue

                if package_manager.is_package_version_installed(dependency, dependency_version):
                    self.composite_logger.log_debug(" - Marking dependency as succeeded: " + str(dependency) + "(" + str(dependency_version) + ")")
                    self.status_handler.set_package_install_status(package_manager.get_product_name(str(dependency)), str(dependency_version), Constants.INSTALLED)
                    index = self.last_still_needed_packages.index(dependency)
                    self.last_still_needed_packages.pop(index)
                    self.last_still_needed_package_versions.pop(index)
                    installed_update_count += 1
                    number_of_dependencies_installed += 1
                else:
                    # status is not logged by design here, in case you were wondering if that's a bug
                    message = " - [Info] Dependency appears to have failed to install (note: it *may* be retried): " + str(dependency) + "(" + str(dependency_version) + ")"
                    self.composite_logger.log_debug(message)
                    number_of_dependencies_failed += 1

            # dependency package result management fallback (not reliable enough to be used as primary, and will be removed; remember to retain last_still_needed refresh when you do that)
            installed_update_count += self.perform_status_reconciliation_conditionally(package_manager, condition=(self.attempted_parent_package_install_count % Constants.PACKAGE_STATUS_REFRESH_RATE_IN_SECONDS == 0))  # reconcile status after every 10 attempted installs

            package_install_perf_log = "[{0}={1}][{2}={3}][{4}={5}][{6}={7}][{8}={9}][{10}={11}][{12}={13}][{14}={15}]".format(Constants.PerfLogTrackerParams.TASK, "InstallPackage",
                                       "PackageName", package, "PackageVersion", version, "PackageAndDependencies", str(package_and_dependencies),"PackageAndDependencyVersions", str(package_and_dependency_versions),
                                       "PackageInstallResult", str(install_result), "NumberOfDependenciesInstalled", str(number_of_dependencies_installed), "NumberOfDependenciesFailed", str(number_of_dependencies_failed))

            single_package_install_stopwatch.stop_and_write_telemetry(str(package_install_perf_log))

        self.composite_logger.log_debug("\nPerforming final system state reconciliation...")
        installed_update_count += self.perform_status_reconciliation_conditionally(package_manager, True)
        self.log_final_metrics(maintenance_window, patch_installation_successful, maintenance_window_exceeded, installed_update_count)

        install_update_count_in_sequential_patching = installed_update_count - install_update_count_in_batch_patching
        attempted_parent_package_install_count_in_sequential_patching = self.attempted_parent_package_install_count - attempted_parent_package_install_count_in_batch_patching
        successful_parent_package_install_count_in_sequential_patching = self.successful_parent_package_install_count - successful_parent_package_install_count_in_batch_patching
        failed_parent_package_install_count_after_sequential_patching = self.failed_parent_package_install_count

        sequential_processing_perf_log = "[{0}={1}][{2}={3}][{4}={5}][{6}={7}][{8}={9}]".format(Constants.PerfLogTrackerParams.TASK, "InstallPackagesSequentially", "InstalledPackagesCountInSequentialProcessing",
                                         install_update_count_in_sequential_patching, "AttemptedParentPackageInstallCount", attempted_parent_package_install_count_in_sequential_patching,
                                         "SuccessfulParentPackageInstallCount", successful_parent_package_install_count_in_sequential_patching, "FailedParentPackageInstallCount", 
                                         failed_parent_package_install_count_after_sequential_patching)

        stopwatch_for_sequential_install_process.stop_and_write_telemetry(sequential_processing_perf_log)

        return installed_update_count, patch_installation_successful, maintenance_window_exceeded