Commit e27799ab authored by Nicholas Verne's avatar Nicholas Verne Committed by Commit Bot

Reland "Adds UpgradeContainer logic to CrostiniManager."

Reverted in https://chromium-review.googlesource.com/c/chromium/src/+/1862337

This fixes an uninitialized member variable in a test fixture found by msan.

Adds UpgradeContainer logic to CrostiniManager.

A call to UpgradeContainer can start off a long-running upgrade process
via the Cicerone daemon. A dbus signal UpgradeContainerProgressSignal is used
to communicate progress to Chrome, including the final success or failure of
the upgrade itself.

Bug: 930901
Change-Id: I18ae12c5706f9a989c5c8247ca8ba223d25cf41a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1862883Reviewed-by: default avatarNic Hollingum <hollingum@google.com>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Commit-Queue: Ryo Hashimoto <hashimoto@chromium.org>
Auto-Submit: Nicholas Verne <nverne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706776}
parent 509165ca
...@@ -1307,6 +1307,82 @@ void CrostiniManager::CancelImportLxdContainer(ContainerId key) { ...@@ -1307,6 +1307,82 @@ void CrostiniManager::CancelImportLxdContainer(ContainerId key) {
weak_ptr_factory_.GetWeakPtr(), std::move(key))); weak_ptr_factory_.GetWeakPtr(), std::move(key)));
} }
namespace {
vm_tools::cicerone::UpgradeContainerRequest::Version ConvertVersion(
ContainerVersion from) {
switch (from) {
case ContainerVersion::STRETCH:
return vm_tools::cicerone::UpgradeContainerRequest::DEBIAN_STRETCH;
case ContainerVersion::BUSTER:
return vm_tools::cicerone::UpgradeContainerRequest::DEBIAN_BUSTER;
case ContainerVersion::UNKNOWN:
default:
return vm_tools::cicerone::UpgradeContainerRequest::UNKNOWN;
}
}
} // namespace
void CrostiniManager::UpgradeContainer(const ContainerId& key,
ContainerVersion source_version,
ContainerVersion target_version,
CrostiniResultCallback callback) {
const auto& vm_name = key.vm_name;
const auto& container_name = key.container_name;
if (vm_name.empty()) {
LOG(ERROR) << "vm_name is required";
std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
return;
}
if (container_name.empty()) {
LOG(ERROR) << "container_name is required";
std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
return;
}
if (!GetCiceroneClient()->IsUpgradeContainerProgressSignalConnected()) {
// Technically we could still start the upgrade, but we wouldn't be able to
// detect when the upgrade completes, successfully or otherwise.
LOG(ERROR)
<< "Attempted to upgrade container when progress signal not connected.";
std::move(callback).Run(CrostiniResult::UPGRADE_CONTAINER_FAILED);
return;
}
vm_tools::cicerone::UpgradeContainerRequest request;
request.set_owner_id(owner_id_);
request.set_vm_name(vm_name);
request.set_container_name(container_name);
request.set_source_version(ConvertVersion(source_version));
request.set_target_version(ConvertVersion(target_version));
GetCiceroneClient()->UpgradeContainer(
std::move(request),
base::BindOnce(&CrostiniManager::OnUpgradeContainer,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CrostiniManager::CancelUpgradeContainer(const ContainerId& key,
CrostiniResultCallback callback) {
const auto& vm_name = key.vm_name;
const auto& container_name = key.container_name;
if (vm_name.empty()) {
LOG(ERROR) << "vm_name is required";
std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
return;
}
if (container_name.empty()) {
LOG(ERROR) << "container_name is required";
std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
return;
}
vm_tools::cicerone::CancelUpgradeContainerRequest request;
request.set_owner_id(owner_id_);
request.set_vm_name(vm_name);
request.set_container_name(container_name);
GetCiceroneClient()->CancelUpgradeContainer(
std::move(request),
base::BindOnce(&CrostiniManager::OnCancelUpgradeContainer,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CrostiniManager::LaunchContainerApplication( void CrostiniManager::LaunchContainerApplication(
std::string vm_name, std::string vm_name,
std::string container_name, std::string container_name,
...@@ -1750,6 +1826,16 @@ void CrostiniManager::RemoveImportContainerProgressObserver( ...@@ -1750,6 +1826,16 @@ void CrostiniManager::RemoveImportContainerProgressObserver(
import_container_progress_observers_.RemoveObserver(observer); import_container_progress_observers_.RemoveObserver(observer);
} }
void CrostiniManager::AddUpgradeContainerProgressObserver(
UpgradeContainerProgressObserver* observer) {
upgrade_container_progress_observers_.AddObserver(observer);
}
void CrostiniManager::RemoveUpgradeContainerProgressObserver(
UpgradeContainerProgressObserver* observer) {
upgrade_container_progress_observers_.RemoveObserver(observer);
}
void CrostiniManager::AddVmShutdownObserver(VmShutdownObserver* observer) { void CrostiniManager::AddVmShutdownObserver(VmShutdownObserver* observer) {
vm_shutdown_observers_.AddObserver(observer); vm_shutdown_observers_.AddObserver(observer);
} }
...@@ -2146,6 +2232,41 @@ void CrostiniManager::OnApplyAnsiblePlaybookProgress( ...@@ -2146,6 +2232,41 @@ void CrostiniManager::OnApplyAnsiblePlaybookProgress(
->OnApplyAnsiblePlaybookProgress(signal.status()); ->OnApplyAnsiblePlaybookProgress(signal.status());
} }
void CrostiniManager::OnUpgradeContainerProgress(
const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) {
if (signal.owner_id() != owner_id_)
return;
UpgradeContainerProgressStatus status;
switch (signal.status()) {
case vm_tools::cicerone::UpgradeContainerProgressSignal::SUCCEEDED:
status = UpgradeContainerProgressStatus::SUCCEEDED;
break;
case vm_tools::cicerone::UpgradeContainerProgressSignal::UNKNOWN:
case vm_tools::cicerone::UpgradeContainerProgressSignal::FAILED:
status = UpgradeContainerProgressStatus::FAILED;
LOG(ERROR) << "Upgrade failed: " << signal.failure_reason();
break;
case vm_tools::cicerone::UpgradeContainerProgressSignal::IN_PROGRESS:
status = UpgradeContainerProgressStatus::UPGRADING;
break;
default:
NOTREACHED();
}
std::vector<std::string> progress_messages;
progress_messages.reserve(signal.progress_messages().size());
for (const auto& msg : signal.progress_messages()) {
progress_messages.push_back(msg);
}
ContainerId container_id(signal.vm_name(), signal.container_name());
for (auto& observer : upgrade_container_progress_observers_) {
observer.OnUpgradeContainerProgress(container_id, status,
progress_messages);
}
}
void CrostiniManager::OnUninstallPackageOwningFile( void CrostiniManager::OnUninstallPackageOwningFile(
CrostiniResultCallback callback, CrostiniResultCallback callback,
base::Optional<vm_tools::cicerone::UninstallPackageOwningFileResponse> base::Optional<vm_tools::cicerone::UninstallPackageOwningFileResponse>
...@@ -2809,6 +2930,66 @@ void CrostiniManager::OnCancelImportLxdContainer( ...@@ -2809,6 +2930,66 @@ void CrostiniManager::OnCancelImportLxdContainer(
} }
} }
void CrostiniManager::OnUpgradeContainer(
CrostiniResultCallback callback,
base::Optional<vm_tools::cicerone::UpgradeContainerResponse> response) {
if (!response) {
LOG(ERROR) << "Failed to start upgrading container. Empty response";
std::move(callback).Run(CrostiniResult::UPGRADE_CONTAINER_FAILED);
return;
}
CrostiniResult result = CrostiniResult::SUCCESS;
switch (response->status()) {
case vm_tools::cicerone::UpgradeContainerResponse::STARTED:
break;
case vm_tools::cicerone::UpgradeContainerResponse::ALREADY_RUNNING:
result = CrostiniResult::UPGRADE_CONTAINER_ALREADY_RUNNING;
LOG(ERROR) << "Upgrade already running. Nothing to do.";
break;
case vm_tools::cicerone::UpgradeContainerResponse::ALREADY_UPGRADED:
LOG(ERROR) << "Container already upgraded. Nothing to do.";
result = CrostiniResult::UPGRADE_CONTAINER_ALREADY_UPGRADED;
break;
case vm_tools::cicerone::UpgradeContainerResponse::NOT_SUPPORTED:
result = CrostiniResult::UPGRADE_CONTAINER_NOT_SUPPORTED;
break;
case vm_tools::cicerone::UpgradeContainerResponse::UNKNOWN:
case vm_tools::cicerone::UpgradeContainerResponse::FAILED:
default:
LOG(ERROR) << "Upgrade container failed. Failure reason "
<< response->failure_reason();
result = CrostiniResult::UPGRADE_CONTAINER_FAILED;
break;
}
std::move(callback).Run(result);
}
void CrostiniManager::OnCancelUpgradeContainer(
CrostiniResultCallback callback,
base::Optional<vm_tools::cicerone::CancelUpgradeContainerResponse>
response) {
if (!response) {
LOG(ERROR) << "Failed to cancel upgrading container. Empty response";
std::move(callback).Run(CrostiniResult::CANCEL_UPGRADE_CONTAINER_FAILED);
return;
}
CrostiniResult result = CrostiniResult::SUCCESS;
switch (response->status()) {
case vm_tools::cicerone::CancelUpgradeContainerResponse::CANCELLED:
case vm_tools::cicerone::CancelUpgradeContainerResponse::NOT_RUNNING:
break;
case vm_tools::cicerone::CancelUpgradeContainerResponse::UNKNOWN:
case vm_tools::cicerone::CancelUpgradeContainerResponse::FAILED:
default:
LOG(ERROR) << "Cancel upgrade container failed. Failure reason "
<< response->failure_reason();
result = CrostiniResult::CANCEL_UPGRADE_CONTAINER_FAILED;
break;
}
std::move(callback).Run(result);
}
void CrostiniManager::OnPendingAppListUpdates( void CrostiniManager::OnPendingAppListUpdates(
const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) { const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) {
ContainerId container_id(signal.vm_name(), signal.container_name()); ContainerId container_id(signal.vm_name(), signal.container_name());
......
...@@ -90,6 +90,14 @@ class ImportContainerProgressObserver { ...@@ -90,6 +90,14 @@ class ImportContainerProgressObserver {
uint64_t minimum_required_space) = 0; uint64_t minimum_required_space) = 0;
}; };
class UpgradeContainerProgressObserver {
public:
virtual void OnUpgradeContainerProgress(
const ContainerId& container_id,
UpgradeContainerProgressStatus status,
const std::vector<std::string>& messages) = 0;
};
class InstallerViewStatusObserver : public base::CheckedObserver { class InstallerViewStatusObserver : public base::CheckedObserver {
public: public:
// Called when the CrostiniInstallerView is opened or closed. // Called when the CrostiniInstallerView is opened or closed.
...@@ -275,6 +283,19 @@ class CrostiniManager : public KeyedService, ...@@ -275,6 +283,19 @@ class CrostiniManager : public KeyedService,
// CiceroneClient::CancelImportLxdContainer. // CiceroneClient::CancelImportLxdContainer.
void CancelImportLxdContainer(ContainerId key); void CancelImportLxdContainer(ContainerId key);
// Checks the arguments for upgrading an existing container via
// CiceroneClient::UpgradeContainer. An UpgradeProgressObserver should be used
// to monitor further results.
void UpgradeContainer(const ContainerId& key,
ContainerVersion source_version,
ContainerVersion target_version,
CrostiniResultCallback callback);
// Checks the arguments for canceling the upgrade of an existing container via
// CiceroneClient::CancelUpgradeContainer.
void CancelUpgradeContainer(const ContainerId& key,
CrostiniResultCallback callback);
// Asynchronously launches an app as specified by its desktop file id. // Asynchronously launches an app as specified by its desktop file id.
void LaunchContainerApplication(std::string vm_name, void LaunchContainerApplication(std::string vm_name,
std::string container_name, std::string container_name,
...@@ -420,6 +441,12 @@ class CrostiniManager : public KeyedService, ...@@ -420,6 +441,12 @@ class CrostiniManager : public KeyedService,
void RemoveImportContainerProgressObserver( void RemoveImportContainerProgressObserver(
ImportContainerProgressObserver* observer); ImportContainerProgressObserver* observer);
// Add/remove observers for container upgrade
void AddUpgradeContainerProgressObserver(
UpgradeContainerProgressObserver* observer);
void RemoveUpgradeContainerProgressObserver(
UpgradeContainerProgressObserver* observer);
// Add/remove vm shutdown observers. // Add/remove vm shutdown observers.
void AddVmShutdownObserver(VmShutdownObserver* observer); void AddVmShutdownObserver(VmShutdownObserver* observer);
void RemoveVmShutdownObserver(VmShutdownObserver* observer); void RemoveVmShutdownObserver(VmShutdownObserver* observer);
...@@ -464,6 +491,9 @@ class CrostiniManager : public KeyedService, ...@@ -464,6 +491,9 @@ class CrostiniManager : public KeyedService,
void OnApplyAnsiblePlaybookProgress( void OnApplyAnsiblePlaybookProgress(
const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal) const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal)
override; override;
void OnUpgradeContainerProgress(
const vm_tools::cicerone::UpgradeContainerProgressSignal& signal)
override;
// chromeos::PowerManagerClient::Observer overrides: // chromeos::PowerManagerClient::Observer overrides:
void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
...@@ -641,6 +671,17 @@ class CrostiniManager : public KeyedService, ...@@ -641,6 +671,17 @@ class CrostiniManager : public KeyedService,
base::Optional<vm_tools::cicerone::CancelImportLxdContainerResponse> base::Optional<vm_tools::cicerone::CancelImportLxdContainerResponse>
response); response);
// Callback for CiceroneClient::UpgradeContainer.
void OnUpgradeContainer(
CrostiniResultCallback callback,
base::Optional<vm_tools::cicerone::UpgradeContainerResponse> response);
// Callback for CiceroneClient::CancelUpgradeContainer.
void OnCancelUpgradeContainer(
CrostiniResultCallback callback,
base::Optional<vm_tools::cicerone::CancelUpgradeContainerResponse>
response);
// Callback for CrostiniManager::LaunchContainerApplication. // Callback for CrostiniManager::LaunchContainerApplication.
void OnLaunchContainerApplication( void OnLaunchContainerApplication(
BoolCallback callback, BoolCallback callback,
...@@ -771,6 +812,9 @@ class CrostiniManager : public KeyedService, ...@@ -771,6 +812,9 @@ class CrostiniManager : public KeyedService,
base::ObserverList<ImportContainerProgressObserver>::Unchecked base::ObserverList<ImportContainerProgressObserver>::Unchecked
import_container_progress_observers_; import_container_progress_observers_;
base::ObserverList<UpgradeContainerProgressObserver>::Unchecked
upgrade_container_progress_observers_;
base::ObserverList<VmShutdownObserver> vm_shutdown_observers_; base::ObserverList<VmShutdownObserver> vm_shutdown_observers_;
// Only one restarter flow is actually running for a given container, other // Only one restarter flow is actually running for a given container, other
......
...@@ -1587,4 +1587,92 @@ TEST_F(CrostiniManagerTest, StartContainerWithAnsibleInfraSuccess) { ...@@ -1587,4 +1587,92 @@ TEST_F(CrostiniManagerTest, StartContainerWithAnsibleInfraSuccess) {
run_loop()->Run(); run_loop()->Run();
} }
class CrostiniManagerUpgradeContainerTest
: public CrostiniManagerTest,
public UpgradeContainerProgressObserver {
public:
void SetUp() override {
CrostiniManagerTest::SetUp();
progress_signal_.set_owner_id(CryptohomeIdForProfile(profile()));
progress_signal_.set_vm_name(kVmName);
progress_signal_.set_container_name(kContainerName);
progress_run_loop_ = std::make_unique<base::RunLoop>();
crostini_manager()->AddUpgradeContainerProgressObserver(this);
}
void TearDown() override {
crostini_manager()->RemoveUpgradeContainerProgressObserver(this);
progress_run_loop_.reset();
CrostiniManagerTest::TearDown();
}
void RunUntilUpgradeDone(UpgradeContainerProgressStatus final_status) {
final_status_ = final_status;
progress_run_loop_->Run();
}
void SendProgressSignal() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
&chromeos::FakeCiceroneClient::NotifyUpgradeContainerProgress,
base::Unretained(fake_cicerone_client_), progress_signal_));
}
protected:
// UpgradeContainerProgressObserver
void OnUpgradeContainerProgress(
const ContainerId& container_id,
UpgradeContainerProgressStatus status,
const std::vector<std::string>& messages) override {
if (status == final_status_) {
progress_run_loop_->Quit();
}
}
ContainerId container_id_ = ContainerId(kVmName, kContainerName);
UpgradeContainerProgressStatus final_status_ =
UpgradeContainerProgressStatus::FAILED;
vm_tools::cicerone::UpgradeContainerProgressSignal progress_signal_;
// must be created on UI thread
std::unique_ptr<base::RunLoop> progress_run_loop_;
};
TEST_F(CrostiniManagerUpgradeContainerTest, UpgradeContainerSuccess) {
crostini_manager()->UpgradeContainer(
container_id_, ContainerVersion::STRETCH, ContainerVersion::BUSTER,
base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
CrostiniResult::SUCCESS));
run_loop()->Run();
progress_signal_.set_status(
vm_tools::cicerone::UpgradeContainerProgressSignal::SUCCEEDED);
SendProgressSignal();
RunUntilUpgradeDone(UpgradeContainerProgressStatus::SUCCEEDED);
}
TEST_F(CrostiniManagerUpgradeContainerTest, CancelUpgradeContainerSuccess) {
crostini_manager()->UpgradeContainer(
container_id_, ContainerVersion::STRETCH, ContainerVersion::BUSTER,
base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
CrostiniResult::SUCCESS));
progress_signal_.set_status(
vm_tools::cicerone::UpgradeContainerProgressSignal::IN_PROGRESS);
SendProgressSignal();
run_loop()->Run();
base::RunLoop run_loop2;
crostini_manager()->CancelUpgradeContainer(
container_id_,
base::BindOnce(&ExpectCrostiniResult, run_loop2.QuitClosure(),
CrostiniResult::SUCCESS));
run_loop2.Run();
}
} // namespace crostini } // namespace crostini
...@@ -63,7 +63,13 @@ enum class CrostiniResult { ...@@ -63,7 +63,13 @@ enum class CrostiniResult {
CONTAINER_EXPORT_IMPORT_CANCELLED = 37, CONTAINER_EXPORT_IMPORT_CANCELLED = 37,
RESTART_ABORTED = 38, RESTART_ABORTED = 38,
RESTART_FAILED_VM_STOPPED = 39, RESTART_FAILED_VM_STOPPED = 39,
kMaxValue = RESTART_FAILED_VM_STOPPED, UPGRADE_CONTAINER_STARTED = 40,
UPGRADE_CONTAINER_ALREADY_RUNNING = 41,
UPGRADE_CONTAINER_NOT_SUPPORTED = 42,
UPGRADE_CONTAINER_ALREADY_UPGRADED = 43,
UPGRADE_CONTAINER_FAILED = 44,
CANCEL_UPGRADE_CONTAINER_FAILED = 45,
kMaxValue = CANCEL_UPGRADE_CONTAINER_FAILED,
}; };
enum class InstallLinuxPackageProgressStatus { enum class InstallLinuxPackageProgressStatus {
...@@ -101,6 +107,18 @@ enum class ImportContainerProgressStatus { ...@@ -101,6 +107,18 @@ enum class ImportContainerProgressStatus {
FAILURE_SPACE, FAILURE_SPACE,
}; };
enum class UpgradeContainerProgressStatus {
SUCCEEDED,
FAILED,
UPGRADING,
};
enum class ContainerVersion {
UNKNOWN,
STRETCH,
BUSTER,
};
struct VmInfo { struct VmInfo {
VmState state; VmState state;
vm_tools::concierge::VmInfo info; vm_tools::concierge::VmInfo info;
......
...@@ -94,6 +94,10 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -94,6 +94,10 @@ class CiceroneClientImpl : public CiceroneClient {
return is_apply_ansible_playbook_progress_signal_connected_; return is_apply_ansible_playbook_progress_signal_connected_;
} }
bool IsUpgradeContainerProgressSignalConnected() override {
return is_upgrade_container_progress_signal_connected_;
}
void LaunchContainerApplication( void LaunchContainerApplication(
const vm_tools::cicerone::LaunchContainerApplicationRequest& request, const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse> DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
...@@ -440,6 +444,51 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -440,6 +444,51 @@ class CiceroneClientImpl : public CiceroneClient {
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void UpgradeContainer(
const vm_tools::cicerone::UpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback)
override {
dbus::MethodCall method_call(vm_tools::cicerone::kVmCiceroneInterface,
vm_tools::cicerone::kUpgradeContainerMethod);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode UpgradeContainerRequest protobuf";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
return;
}
cicerone_proxy_->CallMethod(
&method_call, kDefaultTimeout.InMilliseconds(),
base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
vm_tools::cicerone::UpgradeContainerResponse>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CancelUpgradeContainer(
const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
callback) override {
dbus::MethodCall method_call(
vm_tools::cicerone::kVmCiceroneInterface,
vm_tools::cicerone::kCancelUpgradeContainerMethod);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode CancelUpgradeContainerRequest protobuf";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
return;
}
cicerone_proxy_->CallMethod(
&method_call, kDefaultTimeout.InMilliseconds(),
base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
vm_tools::cicerone::CancelUpgradeContainerResponse>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WaitForServiceToBeAvailable( void WaitForServiceToBeAvailable(
dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)
override { override {
...@@ -552,6 +601,15 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -552,6 +601,15 @@ class CiceroneClientImpl : public CiceroneClient {
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CiceroneClientImpl::OnSignalConnected, base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
cicerone_proxy_->ConnectToSignal(
vm_tools::cicerone::kVmCiceroneInterface,
vm_tools::cicerone::kUpgradeContainerProgressSignal,
base::BindRepeating(
&CiceroneClientImpl::OnUpgradeContainerProgressSignal,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
weak_ptr_factory_.GetWeakPtr()));
} }
private: private:
...@@ -728,12 +786,24 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -728,12 +786,24 @@ class CiceroneClientImpl : public CiceroneClient {
} }
} }
void OnUpgradeContainerProgressSignal(dbus::Signal* signal) {
vm_tools::cicerone::UpgradeContainerProgressSignal proto;
dbus::MessageReader reader(signal);
if (!reader.PopArrayOfBytesAsProto(&proto)) {
LOG(ERROR) << "Failed to parse proto from DBus Signal";
return;
}
for (auto& observer : observer_list_) {
observer.OnUpgradeContainerProgress(proto);
}
}
void OnSignalConnected(const std::string& interface_name, void OnSignalConnected(const std::string& interface_name,
const std::string& signal_name, const std::string& signal_name,
bool is_connected) { bool is_connected) {
if (!is_connected) { if (!is_connected) {
LOG(ERROR) LOG(ERROR)
<< "Failed to connect to Signal. Async StartContainer will not work"; << "Failed to connect to Signal. Async container ops may not work";
} }
DCHECK_EQ(interface_name, vm_tools::cicerone::kVmCiceroneInterface); DCHECK_EQ(interface_name, vm_tools::cicerone::kVmCiceroneInterface);
if (signal_name == vm_tools::cicerone::kContainerStartedSignal) { if (signal_name == vm_tools::cicerone::kContainerStartedSignal) {
...@@ -769,6 +839,9 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -769,6 +839,9 @@ class CiceroneClientImpl : public CiceroneClient {
} else if (signal_name == } else if (signal_name ==
vm_tools::cicerone::kApplyAnsiblePlaybookProgressSignal) { vm_tools::cicerone::kApplyAnsiblePlaybookProgressSignal) {
is_apply_ansible_playbook_progress_signal_connected_ = is_connected; is_apply_ansible_playbook_progress_signal_connected_ = is_connected;
} else if (signal_name ==
vm_tools::cicerone::kUpgradeContainerProgressSignal) {
is_upgrade_container_progress_signal_connected_ = is_connected;
} else { } else {
NOTREACHED(); NOTREACHED();
} }
...@@ -791,6 +864,7 @@ class CiceroneClientImpl : public CiceroneClient { ...@@ -791,6 +864,7 @@ class CiceroneClientImpl : public CiceroneClient {
bool is_import_lxd_container_progress_signal_connected_ = false; bool is_import_lxd_container_progress_signal_connected_ = false;
bool is_pending_app_list_updates_signal_connected_ = false; bool is_pending_app_list_updates_signal_connected_ = false;
bool is_apply_ansible_playbook_progress_signal_connected_ = false; bool is_apply_ansible_playbook_progress_signal_connected_ = false;
bool is_upgrade_container_progress_signal_connected_ = false;
// Note: This should remain the last member so it'll be destroyed and // Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed. // invalidate its weak pointers before any other members are destroyed.
......
...@@ -89,6 +89,11 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient { ...@@ -89,6 +89,11 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient {
const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal&
signal) = 0; signal) = 0;
// This is signaled from Cicerone while a container is being upgraded
// via UpgradeContainer.
virtual void OnUpgradeContainerProgress(
const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) = 0;
protected: protected:
virtual ~Observer() = default; virtual ~Observer() = default;
}; };
...@@ -146,6 +151,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient { ...@@ -146,6 +151,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient {
// This should be true prior to calling ApplyAnsiblePlaybook. // This should be true prior to calling ApplyAnsiblePlaybook.
virtual bool IsApplyAnsiblePlaybookProgressSignalConnected() = 0; virtual bool IsApplyAnsiblePlaybookProgressSignalConnected() = 0;
// This should be true prior to calling UpgradeContainer.
virtual bool IsUpgradeContainerProgressSignalConnected() = 0;
// Launches an application inside a running Container. // Launches an application inside a running Container.
// |callback| is called after the method call finishes. // |callback| is called after the method call finishes.
virtual void LaunchContainerApplication( virtual void LaunchContainerApplication(
...@@ -254,6 +262,20 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient { ...@@ -254,6 +262,20 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) CiceroneClient : public DBusClient {
DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse> DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse>
callback) = 0; callback) = 0;
// Upgrades the container.
// |callback| is called when the method completes.
virtual void UpgradeContainer(
const vm_tools::cicerone::UpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse>
callback) = 0;
// Cancels the in progress container upgrade.
// |callback| is called when the method completes.
virtual void CancelUpgradeContainer(
const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
callback) = 0;
// Registers |callback| to run when the Cicerone service becomes available. // Registers |callback| to run when the Cicerone service becomes available.
// If the service is already available, or if connecting to the name-owner- // If the service is already available, or if connecting to the name-owner-
// changed signal fails, |callback| will be run once asynchronously. // changed signal fails, |callback| will be run once asynchronously.
......
...@@ -38,6 +38,12 @@ FakeCiceroneClient::FakeCiceroneClient() { ...@@ -38,6 +38,12 @@ FakeCiceroneClient::FakeCiceroneClient() {
import_lxd_container_response_.set_status( import_lxd_container_response_.set_status(
vm_tools::cicerone::ImportLxdContainerResponse::IMPORTING); vm_tools::cicerone::ImportLxdContainerResponse::IMPORTING);
upgrade_container_response_.set_status(
vm_tools::cicerone::UpgradeContainerResponse::STARTED);
cancel_upgrade_container_response_.set_status(
vm_tools::cicerone::CancelUpgradeContainerResponse::CANCELLED);
} }
FakeCiceroneClient::~FakeCiceroneClient() = default; FakeCiceroneClient::~FakeCiceroneClient() = default;
...@@ -98,6 +104,10 @@ bool FakeCiceroneClient::IsApplyAnsiblePlaybookProgressSignalConnected() { ...@@ -98,6 +104,10 @@ bool FakeCiceroneClient::IsApplyAnsiblePlaybookProgressSignalConnected() {
return is_apply_ansible_playbook_progress_signal_connected_; return is_apply_ansible_playbook_progress_signal_connected_;
} }
bool FakeCiceroneClient::IsUpgradeContainerProgressSignalConnected() {
return is_upgrade_container_progress_signal_connected_;
}
// Currently no tests need to change the output of this method. If you want to // Currently no tests need to change the output of this method. If you want to
// add one, make it return a variable like the above examples. // add one, make it return a variable like the above examples.
bool FakeCiceroneClient::IsPendingAppListUpdatesSignalConnected() { bool FakeCiceroneClient::IsPendingAppListUpdatesSignalConnected() {
...@@ -291,6 +301,23 @@ void FakeCiceroneClient::ApplyAnsiblePlaybook( ...@@ -291,6 +301,23 @@ void FakeCiceroneClient::ApplyAnsiblePlaybook(
base::BindOnce(std::move(callback), apply_ansible_playbook_response_)); base::BindOnce(std::move(callback), apply_ansible_playbook_response_));
} }
void FakeCiceroneClient::UpgradeContainer(
const vm_tools::cicerone::UpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), upgrade_container_response_));
}
void FakeCiceroneClient::CancelUpgradeContainer(
const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), cancel_upgrade_container_response_));
}
void FakeCiceroneClient::NotifyLxdContainerCreated( void FakeCiceroneClient::NotifyLxdContainerCreated(
const vm_tools::cicerone::LxdContainerCreatedSignal& proto) { const vm_tools::cicerone::LxdContainerCreatedSignal& proto) {
for (auto& observer : observer_list_) { for (auto& observer : observer_list_) {
...@@ -361,4 +388,11 @@ void FakeCiceroneClient::NotifyApplyAnsiblePlaybookProgress( ...@@ -361,4 +388,11 @@ void FakeCiceroneClient::NotifyApplyAnsiblePlaybookProgress(
} }
} }
void FakeCiceroneClient::NotifyUpgradeContainerProgress(
const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) {
for (auto& observer : observer_list_) {
observer.OnUpgradeContainerProgress(signal);
}
}
} // namespace chromeos } // namespace chromeos
...@@ -38,6 +38,7 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -38,6 +38,7 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
bool IsImportLxdContainerProgressSignalConnected() override; bool IsImportLxdContainerProgressSignalConnected() override;
bool IsPendingAppListUpdatesSignalConnected() override; bool IsPendingAppListUpdatesSignalConnected() override;
bool IsApplyAnsiblePlaybookProgressSignalConnected() override; bool IsApplyAnsiblePlaybookProgressSignalConnected() override;
bool IsUpgradeContainerProgressSignalConnected() override;
void LaunchContainerApplication( void LaunchContainerApplication(
const vm_tools::cicerone::LaunchContainerApplicationRequest& request, const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse> DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
...@@ -105,6 +106,14 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -105,6 +106,14 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
const vm_tools::cicerone::ApplyAnsiblePlaybookRequest& request, const vm_tools::cicerone::ApplyAnsiblePlaybookRequest& request,
DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse> DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse>
callback) override; callback) override;
void UpgradeContainer(
const vm_tools::cicerone::UpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback)
override;
void CancelUpgradeContainer(
const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
callback) override;
void WaitForServiceToBeAvailable( void WaitForServiceToBeAvailable(
dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override; dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
...@@ -152,6 +161,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -152,6 +161,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
void set_import_lxd_container_progress_signal_connected(bool connected) { void set_import_lxd_container_progress_signal_connected(bool connected) {
is_import_lxd_container_progress_signal_connected_ = connected; is_import_lxd_container_progress_signal_connected_ = connected;
} }
void set_upgrade_container_progress_signal_connected(bool connected) {
is_upgrade_container_progress_signal_connected_ = connected;
}
void set_launch_container_application_response( void set_launch_container_application_response(
const vm_tools::cicerone::LaunchContainerApplicationResponse& const vm_tools::cicerone::LaunchContainerApplicationResponse&
launch_container_application_response) { launch_container_application_response) {
...@@ -245,6 +257,16 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -245,6 +257,16 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
apply_ansible_playbook_response) { apply_ansible_playbook_response) {
apply_ansible_playbook_response_ = apply_ansible_playbook_response; apply_ansible_playbook_response_ = apply_ansible_playbook_response;
} }
void set_upgrade_container_response(
vm_tools::cicerone::UpgradeContainerResponse upgrade_container_response) {
upgrade_container_response_ = std::move(upgrade_container_response);
}
void set_cancel_upgrade_container_response(
vm_tools::cicerone::CancelUpgradeContainerResponse
cancel_upgrade_container_response) {
cancel_upgrade_container_response_ =
std::move(cancel_upgrade_container_response);
}
// Additional functions to allow tests to trigger Signals. // Additional functions to allow tests to trigger Signals.
void NotifyLxdContainerCreated( void NotifyLxdContainerCreated(
...@@ -269,6 +291,8 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -269,6 +291,8 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
const vm_tools::cicerone::PendingAppListUpdatesSignal& signal); const vm_tools::cicerone::PendingAppListUpdatesSignal& signal);
void NotifyApplyAnsiblePlaybookProgress( void NotifyApplyAnsiblePlaybookProgress(
const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal); const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal);
void NotifyUpgradeContainerProgress(
const vm_tools::cicerone::UpgradeContainerProgressSignal& signal);
protected: protected:
void Init(dbus::Bus* bus) override {} void Init(dbus::Bus* bus) override {}
...@@ -286,6 +310,7 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -286,6 +310,7 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
bool is_export_lxd_container_progress_signal_connected_ = true; bool is_export_lxd_container_progress_signal_connected_ = true;
bool is_import_lxd_container_progress_signal_connected_ = true; bool is_import_lxd_container_progress_signal_connected_ = true;
bool is_apply_ansible_playbook_progress_signal_connected_ = true; bool is_apply_ansible_playbook_progress_signal_connected_ = true;
bool is_upgrade_container_progress_signal_connected_ = true;
std::string last_container_username_; std::string last_container_username_;
bool send_container_started_signal_ = true; bool send_container_started_signal_ = true;
...@@ -327,6 +352,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient ...@@ -327,6 +352,9 @@ class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeCiceroneClient
cancel_import_lxd_container_response_; cancel_import_lxd_container_response_;
vm_tools::cicerone::ApplyAnsiblePlaybookResponse vm_tools::cicerone::ApplyAnsiblePlaybookResponse
apply_ansible_playbook_response_; apply_ansible_playbook_response_;
vm_tools::cicerone::UpgradeContainerResponse upgrade_container_response_;
vm_tools::cicerone::CancelUpgradeContainerResponse
cancel_upgrade_container_response_;
vm_tools::cicerone::OsRelease lxd_container_os_release_; vm_tools::cicerone::OsRelease lxd_container_os_release_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment