1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_CROSTINI_ANSIBLE_ANSIBLE_MANAGEMENT_SERVICE_H_
#define CHROME_BROWSER_ASH_CROSTINI_ANSIBLE_ANSIBLE_MANAGEMENT_SERVICE_H_
#include <string>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "components/keyed_service/core/keyed_service.h"
class Profile;
namespace views {
class Widget;
} // namespace views
namespace crostini {
struct AnsibleConfiguration {
AnsibleConfiguration(std::string playbook,
base::FilePath path,
base::OnceCallback<void(bool success)> callback);
AnsibleConfiguration(base::FilePath path,
base::OnceCallback<void(bool success)> callback);
~AnsibleConfiguration();
std::string playbook;
base::FilePath path;
base::OnceCallback<void(bool success)> callback;
};
// TODO(okalitova): Install Ansible from backports repo once this is feasible.
extern const char kCrostiniDefaultAnsibleVersion[];
// AnsibleManagementService is responsible for Crostini default
// container management using Ansible.
class AnsibleManagementService : public KeyedService,
public LinuxPackageOperationProgressObserver {
public:
// Observer class for Ansible Management Service related events.
class Observer : public base::CheckedObserver {
public:
~Observer() override = default;
virtual void OnAnsibleSoftwareConfigurationStarted(
const guest_os::GuestId& container_id) = 0;
virtual void OnAnsibleSoftwareConfigurationProgress(
const guest_os::GuestId& container_id,
const std::vector<std::string>& status_lines) {}
virtual void OnAnsibleSoftwareConfigurationFinished(
const guest_os::GuestId& container_id,
bool success) = 0;
virtual void OnAnsibleSoftwareInstall(
const guest_os::GuestId& container_id) {}
virtual void OnApplyAnsiblePlaybook(const guest_os::GuestId& container_id) {
}
// Mainly for testing purposes only. Signals observers that the UI element
// is ready for interaction for a particular configuration task.
virtual void OnAnsibleSoftwareConfigurationUiPrompt(
const guest_os::GuestId& container_id,
bool interactive) {}
};
explicit AnsibleManagementService(Profile* profile);
AnsibleManagementService(const AnsibleManagementService&) = delete;
AnsibleManagementService& operator=(const AnsibleManagementService&) = delete;
~AnsibleManagementService() override;
// Preconfigures a container with a specified Ansible playbook.
virtual void ConfigureContainer(
const guest_os::GuestId& container_id,
base::FilePath playbook,
base::OnceCallback<void(bool success)> callback);
// LinuxPackageOperationProgressObserver:
void OnInstallLinuxPackageProgress(const guest_os::GuestId& container_id,
InstallLinuxPackageProgressStatus status,
int progress_percent,
const std::string& error_message) override;
void OnUninstallPackageProgress(const guest_os::GuestId& container_id,
UninstallPackageProgressStatus status,
int progress_percent) override;
virtual void OnApplyAnsiblePlaybookProgress(
const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal);
// Gets the input from the user-facing dialog to determine whether or not a
// configuration task should be retried.
void RetryConfiguration(const guest_os::GuestId& container_id);
void CancelConfiguration(const guest_os::GuestId& container_id);
void CompleteConfiguration(const guest_os::GuestId& container_id,
bool success);
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Sets up and returns a mock instance of AnsibleManagementService.
static AnsibleManagementService* SetUpMockAnsibleManagementServiceForTesting(
Profile* profile);
views::Widget* GetDialogWidgetForTesting(
const guest_os::GuestId& container_id);
void AddConfigurationTaskForTesting(const guest_os::GuestId& container_id,
views::Widget* widget);
private:
bool IsCancelled(const guest_os::GuestId& container_id);
// Helper function to create the UI elements needed. We won't need to keep
// track of this because it'll be self-destructing.
void CreateUiElement(const guest_os::GuestId& container_id);
void OnInstallAnsibleInContainer(const guest_os::GuestId& container_id,
CrostiniResult result);
void GetAnsiblePlaybookToApply(const guest_os::GuestId& container_id);
void OnAnsiblePlaybookRetrieved(const guest_os::GuestId& container_id,
bool success);
void ApplyAnsiblePlaybook(const guest_os::GuestId& container_id);
void OnApplyAnsiblePlaybook(
const guest_os::GuestId& container_id,
std::optional<vm_tools::cicerone::ApplyAnsiblePlaybookResponse> response);
// Helper function that runs relevant callback and notifies observers.
void OnConfigurationFinished(const guest_os::GuestId& container_id,
bool success);
raw_ptr<Profile> profile_;
base::ObserverList<Observer> observers_;
std::map<guest_os::GuestId, std::unique_ptr<AnsibleConfiguration>>
configuration_tasks_;
// We don't really need to know about these, but keeping them so we can access
// for testing purposes.
std::map<guest_os::GuestId, raw_ptr<views::Widget, CtnExperimental>>
ui_elements_;
base::WeakPtrFactory<AnsibleManagementService> weak_ptr_factory_;
};
} // namespace crostini
#endif // CHROME_BROWSER_ASH_CROSTINI_ANSIBLE_ANSIBLE_MANAGEMENT_SERVICE_H_
|