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

feature(storage): API for solved and unsolved configs #1692

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
13 changes: 13 additions & 0 deletions doc/dbus/bus/org.opensuse.Agama.Storage1.bus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,25 @@
<interface name="org.opensuse.Agama.Storage1">
<method name="Probe">
</method>
<method name="SetConfig">
<arg name="serialized_config" direction="in" type="s"/>
<arg name="result" direction="out" type="u"/>
</method>
<method name="GetConfig">
<arg name="serialized_config" direction="out" type="s"/>
</method>
<method name="GetSolvedConfig">
<arg name="serialized_config" direction="out" type="s"/>
</method>
<method name="Install">
</method>
<method name="Finish">
</method>
<property type="b" name="DeprecatedSystem" access="read"/>
</interface>
<interface name="org.opensuse.Agama.Storage1.Devices">
<property type="aa{sv}" name="Actions" access="read"/>
</interface>
<interface name="org.opensuse.Agama.Storage1.DASD.Manager">
<method name="Probe">
</method>
Expand Down
78 changes: 78 additions & 0 deletions doc/dbus/org.opensuse.Agama.Storage1.doc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,84 @@
<interface name="org.opensuse.Agama.Storage1">
<method name="Probe">
</method>
<!--
Sets the storage config.
-->
<method name="SetConfig">
<!--
E.g.,
{
"storage": {
"drives": [
{
"search": "/dev/vda",
"partitions": [
{ "generate": "default" }
]
}
]
}
}
-->
<arg name="serialized_config" direction="in" type="s"/>
<!--
Whether the proposal was correctly calculated:
0: success
1: failure
-->
<arg name="result" direction="out" type="u"/>
</method>
<!--
Gets the unsolved storage config.
-->
<method name="GetConfig">
<!--
E.g.,
{
joseivanlopez marked this conversation as resolved.
Show resolved Hide resolved
"storage": {
"drives": [
{
"search": "/dev/vda",
"partitions": [
{ "generate": "default" }
]
}
]
}
}
-->
<arg name="serialized_config" direction="out" type="s"/>
</method>
<!--
Gets the solved storage config.
-->
<method name="GetSolvedConfig">
<!--
E.g.,
{
"storage": {
"drives": [
{
"search": "/dev/vda",
"partitions": [
{
"filesystem": {
"path": "/home",
"type": "xfs"
},
"size": {
"min": "10 GiB",
"max": "10 GiB"
}
}
]
}
]
}
}
-->
<arg name="serialized_config" direction="out" type="s"/>
</method>
<method name="Install">
</method>
<method name="Finish">
Expand Down
7 changes: 7 additions & 0 deletions rust/agama-lib/src/storage/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ impl<'a> StorageClient<'a> {
Ok(settings)
}

/// Get the storage solved config according to the JSON schema
pub async fn get_solved_config(&self) -> Result<StorageSettings, ServiceError> {
let serialized_settings = self.storage_proxy.get_solved_config().await?;
let settings = serde_json::from_str(serialized_settings.as_str()).unwrap();
Ok(settings)
}

pub async fn calculate(&self, settings: ProposalSettingsPatch) -> Result<u32, ServiceError> {
Ok(self.calculator_proxy.calculate(settings.into()).await?)
}
Expand Down
3 changes: 3 additions & 0 deletions rust/agama-lib/src/storage/proxies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ trait Storage1 {
/// Get the current storage config according to the JSON schema
fn get_config(&self) -> zbus::Result<String>;

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

/// DeprecatedSystem property
#[dbus_proxy(property)]
fn deprecated_system(&self) -> zbus::Result<bool>;
Expand Down
26 changes: 26 additions & 0 deletions rust/agama-server/src/storage/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub async fn storage_service(dbus: zbus::Connection) -> Result<Router, ServiceEr
let state = StorageState { client };
let router = Router::new()
.route("/config", put(set_config).get(get_config))
.route("/solved_config", get(get_solved_config))
.route("/probe", post(probe))
.route("/devices/dirty", get(devices_dirty))
.route("/devices/system", get(system_devices))
Expand Down Expand Up @@ -155,6 +156,31 @@ async fn get_config(State(state): State<StorageState<'_>>) -> Result<Json<Storag
Ok(Json(settings))
}

/// Returns the solved storage configuration.
///
/// * `state` : service state.
#[utoipa::path(
get,
path = "/solved_config",
context_path = "/api/storage",
operation_id = "get_storage_solved_config",
responses(
(status = 200, description = "storage solved configuration", body = StorageSettings),
(status = 400, description = "The D-Bus service could not perform the action")
)
)]
async fn get_solved_config(
State(state): State<StorageState<'_>>,
) -> Result<Json<StorageSettings>, Error> {
// StorageSettings is just a wrapper over serde_json::value::RawValue
let settings = state
.client
.get_solved_config()
.await
.map_err(Error::Service)?;
Ok(Json(settings))
}

/// Sets the storage configuration.
///
/// * `state`: service state.
Expand Down
6 changes: 6 additions & 0 deletions rust/package/agama.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Thu Oct 24 14:19:46 UTC 2024 - José Iván López González <jlopez@suse.com>

- Storage: extend the HTTP API to allow getting the solved storage
config (gh#agama-project/agama#1692).

-------------------------------------------------------------------
Wed Oct 23 15:25:36 UTC 2024 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

Expand Down
9 changes: 6 additions & 3 deletions service/lib/agama/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

require "yaml"
require "yast2/arch_filter"
require "agama/copyable"
require "agama/config_reader"
require "agama/product_reader"

Expand All @@ -31,6 +32,8 @@ module Agama
# This also means that config needs to be re-evaluated if conditions
# data change, like if user pick different distro to install.
class Config
include Copyable

# @return [Hash] configuration data
attr_accessor :pure_data
attr_accessor :logger
Expand Down Expand Up @@ -124,11 +127,11 @@ def multi_product?
def copy
logger = self.logger
@logger = nil # cannot dump logger as it can contain IO
res = Marshal.load(Marshal.dump(self))
new_config = super
@logger = logger
res.logger = logger
new_config.logger = logger

res
new_config
end

# Returns a new {Config} with the merge of the given ones
Expand Down
32 changes: 32 additions & 0 deletions service/lib/agama/copyable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

# Copyright (c) [2024] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

module Agama
# Mixin to make a class copyable.
module Copyable
# Copies the object by doing a deep dup.
#
# @return [Object] New instance of the object's class.
def copy
Marshal.load(Marshal.dump(self))
end
end
end
7 changes: 5 additions & 2 deletions service/lib/agama/dbus/storage/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,11 @@ def apply_config(serialized_config)

# Gets and serializes the storage config used to calculate the current proposal.
#
# @param solved [Boolean] Whether to recover the solved config.
# @return [String] Serialized config according to the JSON schema.
def recover_config
JSON.pretty_generate(proposal.config_json)
def recover_config(solved: false)
json = proposal.storage_json(solved: solved)
JSON.pretty_generate(json)
end

def install
Expand All @@ -139,6 +141,7 @@ def deprecated_system
busy_while { apply_config(serialized_config) }
end
dbus_method(:GetConfig, "out serialized_config:s") { recover_config }
dbus_method(:GetSolvedConfig, "out serialized_config:s") { recover_config(solved: true) }
dbus_method(:Install) { install }
dbus_method(:Finish) { finish }
dbus_reader(:deprecated_system, "b")
Expand Down
3 changes: 3 additions & 0 deletions service/lib/agama/storage/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "agama/copyable"
require "agama/storage/configs/boot"
require "agama/storage/config_conversions/from_json"

module Agama
module Storage
# Settings used to calculate an storage proposal.
class Config
include Copyable

# Boot settings.
#
# @return [Configs::Boot]
Expand Down
14 changes: 6 additions & 8 deletions service/lib/agama/storage/configs/with_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "agama/copyable"

module Agama
module Storage
module Configs
# Mixin for configs with search.
module WithSearch
# Needed when a search returns multiple devices and the configuration needs to be replicated
# for each one.
include Copyable

# @return [Search, nil]
attr_accessor :search

Expand All @@ -35,14 +41,6 @@ module WithSearch
def found_device
search&.device
end

# Creates a deep copy of the config element
#
# Needed when a search returns multiple devices and the configuration needs to be replicated
# for each one.
def copy
Marshal.load(Marshal.dump(self))
end
end
end
end
Expand Down
Loading
Loading