Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage): load storage config for guided proposal #1293

Merged
merged 5 commits into from
Jun 26, 2024
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
12 changes: 6 additions & 6 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions rust/agama-lib/src/install_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module implements the mechanisms to load and store the installation settings.
use crate::{
localization::LocalizationSettings, network::NetworkSettings, product::ProductSettings,
software::SoftwareSettings, storage::StorageSettings, users::UserSettings,
software::SoftwareSettings, users::UserSettings,
};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;
Expand All @@ -26,8 +26,10 @@ pub struct InstallSettings {
#[serde(default)]
pub product: Option<ProductSettings>,
#[serde(default)]
pub storage: Option<StorageSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub storage: Option<Box<RawValue>>,
#[serde(default, rename = "legacyAutoyastStorage")]
#[serde(skip_serializing_if = "Option::is_none")]
pub storage_autoyast: Option<Box<RawValue>>,
#[serde(default)]
pub network: Option<NetworkSettings>,
Expand Down
2 changes: 0 additions & 2 deletions rust/agama-lib/src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
//! Implements support for handling the storage settings

mod autoyast;
pub mod client;
pub mod model;
pub mod proxies;
mod settings;
mod store;

pub use autoyast::store::StorageAutoyastStore;
pub use client::{
iscsi::{ISCSIAuth, ISCSIClient, ISCSIInitiator, ISCSINode},
StorageClient,
Expand Down
2 changes: 0 additions & 2 deletions rust/agama-lib/src/storage/autoyast.rs

This file was deleted.

26 changes: 0 additions & 26 deletions rust/agama-lib/src/storage/autoyast/store.rs

This file was deleted.

75 changes: 15 additions & 60 deletions rust/agama-lib/src/storage/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use super::model::{
Action, BlockDevice, Component, Device, DeviceInfo, DeviceSid, Drive, Filesystem, LvmLv, LvmVg,
Md, Multipath, Partition, PartitionTable, ProposalSettings, ProposalSettingsPatch,
ProposalTarget, Raid, Volume,
Md, Multipath, Partition, PartitionTable, ProposalSettings, ProposalSettingsPatch, Raid,
Volume,
};
use super::proxies::{ProposalCalculatorProxy, ProposalProxy, Storage1Proxy};
use super::StorageSettings;
Expand Down Expand Up @@ -105,73 +105,28 @@ impl<'a> StorageClient<'a> {
Ok(self.proposal_proxy.settings().await?.try_into()?)
}

/// Returns the boot device proposal setting
/// DEPRECATED, use proposal_settings instead
pub async fn boot_device(&self) -> Result<Option<String>, ServiceError> {
let settings = self.proposal_settings().await?;
let boot_device = settings.boot_device;

if boot_device.is_empty() {
Ok(None)
} else {
Ok(Some(boot_device))
}
}

/// Returns the lvm proposal setting
/// DEPRECATED, use proposal_settings instead
pub async fn lvm(&self) -> Result<Option<bool>, ServiceError> {
let settings = self.proposal_settings().await?;
Ok(Some(!matches!(settings.target, ProposalTarget::Disk)))
}

/// Returns the encryption password proposal setting
/// DEPRECATED, use proposal_settings instead
pub async fn encryption_password(&self) -> Result<Option<String>, ServiceError> {
let settings = self.proposal_settings().await?;
let value = settings.encryption_password;

if value.is_empty() {
Ok(None)
} else {
Ok(Some(value))
}
}

/// Runs the probing process
pub async fn probe(&self) -> Result<(), ServiceError> {
Ok(self.storage_proxy.probe().await?)
}

/// TODO: remove calculate when CLI will be adapted
pub async fn calculate2(&self, settings: ProposalSettingsPatch) -> Result<u32, ServiceError> {
Ok(self.calculator_proxy.calculate(settings.into()).await?)
/// Set the storage config according to the JSON schema
pub async fn set_config(&self, settings: StorageSettings) -> Result<u32, ServiceError> {
Ok(self
.storage_proxy
.set_config(serde_json::to_string(&settings).unwrap().as_str())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np: I know we are kind of in a hurry, but in the future we should drop this call to unwrap.

.await?)
}

pub async fn calculate_autoyast(&self, settings: &str) -> Result<u32, ServiceError> {
Ok(self.calculator_proxy.calculate_autoyast(settings).await?)
/// Get the storage config according to the JSON schema
pub async fn get_config(&self) -> Result<StorageSettings, ServiceError> {
let serialized_settings = self.storage_proxy.get_config().await?;
let settings = serde_json::from_str(serialized_settings.as_str()).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same than above.

Ok(settings)
}

/// Calculates a new proposal with the given settings.
pub async fn calculate(&self, settings: &StorageSettings) -> Result<u32, ServiceError> {
let mut dbus_settings: HashMap<&str, zbus::zvariant::Value<'_>> = HashMap::new();

if let Some(boot_device) = settings.boot_device.clone() {
dbus_settings.insert("BootDevice", zbus::zvariant::Value::new(boot_device));
}

if let Some(encryption_password) = settings.encryption_password.clone() {
dbus_settings.insert(
"EncryptionPassword",
zbus::zvariant::Value::new(encryption_password),
);
}

if let Some(lvm) = settings.lvm {
dbus_settings.insert("LVM", zbus::zvariant::Value::new(lvm));
}

Ok(self.calculator_proxy.calculate(dbus_settings).await?)
pub async fn calculate(&self, settings: ProposalSettingsPatch) -> Result<u32, ServiceError> {
Ok(self.calculator_proxy.calculate(settings.into()).await?)
}

/// Probed devices.
Expand Down
9 changes: 6 additions & 3 deletions rust/agama-lib/src/storage/proxies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ trait Storage1 {
/// Probe method
fn probe(&self) -> zbus::Result<()>;

/// Set the storage config according to the JSON schema
fn set_config(&self, settings: &str) -> zbus::Result<u32>;

/// Get the current storage config according to the JSON schema
fn get_config(&self) -> zbus::Result<String>;

/// DeprecatedSystem property
#[dbus_proxy(property)]
fn deprecated_system(&self) -> zbus::Result<bool>;
Expand All @@ -35,9 +41,6 @@ trait ProposalCalculator {
settings: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
) -> zbus::Result<u32>;

/// Calculate AutoYaST proposal
fn calculate_autoyast(&self, settings: &str) -> zbus::Result<u32>;

/// DefaultVolume method
fn default_volume(
&self,
Expand Down
23 changes: 17 additions & 6 deletions rust/agama-lib/src/storage/settings.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
//! Representation of the storage settings

use crate::install_settings::InstallSettings;
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;

/// Storage settings for installation
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageSettings {
/// Whether LVM should be enabled
pub lvm: Option<bool>,
/// Encryption password for the storage devices (in clear text)
pub encryption_password: Option<String>,
/// Boot device to use in the installation
pub boot_device: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub storage: Option<Box<RawValue>>,
#[serde(default, rename = "legacyAutoyastStorage")]
#[serde(skip_serializing_if = "Option::is_none")]
pub storage_autoyast: Option<Box<RawValue>>,
}

impl From<&InstallSettings> for StorageSettings {
fn from(install_settings: &InstallSettings) -> Self {
StorageSettings {
storage: install_settings.storage.clone(),
storage_autoyast: install_settings.storage_autoyast.clone(),
}
}
}
18 changes: 3 additions & 15 deletions rust/agama-lib/src/storage/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,11 @@ impl<'a> StorageStore<'a> {
}

pub async fn load(&self) -> Result<StorageSettings, ServiceError> {
// If it is not possible to get the settings (e.g., there are no settings yet), return
// the default.
let Ok(boot_device) = self.storage_client.boot_device().await else {
return Ok(StorageSettings::default());
};
let lvm = self.storage_client.lvm().await?;
let encryption_password = self.storage_client.encryption_password().await?;

Ok(StorageSettings {
boot_device,
lvm,
encryption_password,
})
Ok(self.storage_client.get_config().await?)
}

pub async fn store(&self, settings: &StorageSettings) -> Result<(), ServiceError> {
self.storage_client.calculate(settings).await?;
pub async fn store(&self, settings: StorageSettings) -> Result<(), ServiceError> {
self.storage_client.set_config(settings).await?;
Ok(())
}
}
26 changes: 8 additions & 18 deletions rust/agama-lib/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use crate::error::ServiceError;
use crate::install_settings::InstallSettings;
use crate::{
localization::LocalizationStore, network::NetworkStore, product::ProductStore,
software::SoftwareStore, storage::StorageAutoyastStore, storage::StorageStore,
users::UsersStore,
software::SoftwareStore, storage::StorageStore, users::UsersStore,
};
use zbus::Connection;

Expand All @@ -22,7 +21,6 @@ pub struct Store<'a> {
product: ProductStore<'a>,
software: SoftwareStore<'a>,
storage: StorageStore<'a>,
storage_autoyast: StorageAutoyastStore<'a>,
localization: LocalizationStore<'a>,
}

Expand All @@ -37,25 +35,23 @@ impl<'a> Store<'a> {
network: NetworkStore::new(http_client).await?,
product: ProductStore::new(connection.clone()).await?,
software: SoftwareStore::new(connection.clone()).await?,
storage: StorageStore::new(connection.clone()).await?,
storage_autoyast: StorageAutoyastStore::new(connection).await?,
storage: StorageStore::new(connection).await?,
})
}

/// Loads the installation settings from the HTTP interface.
///
/// NOTE: The storage AutoYaST settings cannot be loaded because they cannot be modified. The
/// ability of using the storage AutoYaST settings from a JSON config file is temporary and it
/// will be removed in the future.
pub async fn load(&self) -> Result<InstallSettings, ServiceError> {
let mut settings: InstallSettings = Default::default();
settings.network = Some(self.network.load().await?);
settings.storage = Some(self.storage.load().await?);
settings.software = Some(self.software.load().await?);
settings.user = Some(self.users.load().await?);
settings.product = Some(self.product.load().await?);
settings.localization = Some(self.localization.load().await?);

let storage_settings = self.storage.load().await?;
settings.storage = storage_settings.storage.clone();
settings.storage_autoyast = storage_settings.storage_autoyast.clone();

// TODO: use try_join here
Ok(settings)
}
Expand All @@ -80,14 +76,8 @@ impl<'a> Store<'a> {
if let Some(user) = &settings.user {
self.users.store(user).await?;
}
if let Some(storage) = &settings.storage {
self.storage.store(storage).await?;
}
if let Some(storage_autoyast) = &settings.storage_autoyast {
// Storage scope has precedence.
if settings.storage.is_none() {
self.storage_autoyast.store(storage_autoyast.get()).await?;
}
if settings.storage.is_some() || settings.storage_autoyast.is_some() {
self.storage.store(settings.into()).await?
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion rust/agama-server/src/storage/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,6 @@ async fn set_proposal_settings(
State(state): State<StorageState<'_>>,
Json(config): Json<ProposalSettingsPatch>,
) -> Result<Json<bool>, Error> {
let result = state.client.calculate2(config).await?;
let result = state.client.calculate(config).await?;
Ok(Json(result == 0))
}
5 changes: 5 additions & 0 deletions rust/package/agama.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
-------------------------------------------------------------------
Wed Jun 26 10:29:05 UTC 2024 - José Iván López González <[email protected]>

- Set and get storage config (gh#openSUSE/agama#1293).

-------------------------------------------------------------------
Tue Jun 25 15:16:33 UTC 2024 - Imobach Gonzalez Sosa <[email protected]>

Expand Down
Loading
Loading