Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rust/agama-cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ pub enum CliError {
InvalidKeyName(String),
#[error("Cannot perform the installation as the settings are not valid")]
ValidationError,
#[error("Could not start the installation")]
InstallationError,
}
44 changes: 35 additions & 9 deletions rust/agama-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use printers::Format;
use profile::run as run_profile_cmd;
use progress::InstallerProgress;
use std::error::Error;
use std::thread::sleep;
use std::time::Duration;

#[derive(Parser)]
Expand All @@ -39,17 +40,43 @@ async fn probe() -> Result<(), Box<dyn Error>> {
Ok(probe.await?)
}

async fn install(manager: &ManagerClient<'_>) -> Result<(), Box<dyn Error>> {
/// Starts the installation process
///
/// Before starting, it makes sure that the manager is idle.
///
/// * `manager`: the manager client.
async fn install(manager: &ManagerClient<'_>, max_attempts: u8) -> Result<(), Box<dyn Error>> {
if manager.is_busy().await {
println!("Agama's manager is busy. Waiting until it is ready...");
}

if !manager.can_install().await? {
// TODO: add some hints what is wrong or add dedicated command for it?
eprintln!("There are issues with configuration. Cannot install.");
return Err(Box::new(CliError::ValidationError));
}
let another_manager = build_manager().await?;
let install = task::spawn(async move { another_manager.install().await });
show_progress().await?;
// Display the progress (if needed) and makes sure that the manager is ready
manager.wait().await?;

Ok(install.await?)
// Try to start the installation up to max_attempts times.
let mut attempts = 1;
loop {
match manager.install().await {
Ok(()) => break,
Err(e) => {
eprintln!(
"Could not start the installation process: {e}. Attempt {}/{}.",
attempts, max_attempts
);
}
}
if attempts == max_attempts {
eprintln!("Giving up.");
return Err(Box::new(CliError::InstallationError));
}
attempts += 1;
sleep(Duration::from_secs(1));
}
println!("The installation process has started.");
Ok(())
}

async fn show_progress() -> Result<(), ServiceError> {
Expand Down Expand Up @@ -95,8 +122,7 @@ async fn run_command(cli: Cli) -> Result<(), Box<dyn Error>> {
Commands::Profile(subcommand) => Ok(run_profile_cmd(subcommand)?),
Commands::Install => {
let manager = build_manager().await?;
block_on(wait_for_services(&manager))?;
block_on(install(&manager))
block_on(install(&manager, 3))
}
_ => unimplemented!(),
}
Expand Down
29 changes: 29 additions & 0 deletions rust/agama-lib/src/manager.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
use crate::error::ServiceError;
use crate::proxies::ServiceStatusProxy;
use crate::{
progress::Progress,
proxies::{ManagerProxy, ProgressProxy},
};
use futures_util::StreamExt;
use zbus::Connection;

/// D-Bus client for the manager service
pub struct ManagerClient<'a> {
manager_proxy: ManagerProxy<'a>,
progress_proxy: ProgressProxy<'a>,
status_proxy: ServiceStatusProxy<'a>,
}

impl<'a> ManagerClient<'a> {
pub async fn new(connection: Connection) -> zbus::Result<ManagerClient<'a>> {
Ok(Self {
manager_proxy: ManagerProxy::new(&connection).await?,
progress_proxy: ProgressProxy::new(&connection).await?,
status_proxy: ServiceStatusProxy::new(&connection).await?,
})
}

Expand All @@ -38,4 +42,29 @@ impl<'a> ManagerClient<'a> {
pub async fn progress(&self) -> zbus::Result<Progress> {
Progress::from_proxy(&self.progress_proxy).await
}

/// Returns whether the service is busy or not
///
/// TODO: move this code to a trait with functions related to the service status.
pub async fn is_busy(&self) -> bool {
if let Ok(status) = self.status_proxy.current().await {
return status != 0;
}
true
}

/// Waits until the manager is idle.
pub async fn wait(&self) -> Result<(), ServiceError> {
if !self.is_busy().await {
return Ok(());
}

let mut s = self.status_proxy.receive_current_changed().await;
while let Some(change) = s.next().await {
if change.get().await? == 0 {
return Ok(());
}
}
Ok(())
}
}
6 changes: 6 additions & 0 deletions rust/package/agama-cli.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Thu Jul 6 09:13:47 UTC 2023 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

- Improve the waiting logic and implement a retry mechanism for the
"agama install" command (bsc#1213047).

-------------------------------------------------------------------
Wed Jul 5 11:11:20 UTC 2023 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

Expand Down