diff --git a/doc/questions.md b/doc/questions.md deleted file mode 100644 index 523d7755f1..0000000000 --- a/doc/questions.md +++ /dev/null @@ -1,73 +0,0 @@ -## Questions - -[Questions][] are a mechanism that allows the installer to ask for additional data which is needed without knowing it in advance. -Examples are Luks password when Luks encrypted partition occur, whenever activate multipath if installer is not sure -or when software repository is signed with unknown GPG key. - -Questions can have answering mode allowing to have unattended installation without stopping by questions. Question can be -also answered from predefined answers. Predefined answers with interactive mode means that question is not asked to user -and instead answer will be used immediatelly. In unattended mode it will prefer predefined answer over default ones. - -[Questions]: https://opensuse.github.io/agama/dbus/ref-org.opensuse.Agama.Questions1.html - -### Questions and Machine Answers - -Questions can be answered by user or by machine. Having machine answers is useful to make questions -non-blocking and non-interactive. Another option is combination that some questions are answered by machine and rest -is answered by user. - -#### Requirements for Questions - -To make it work there are several requirements for questions: - -1. each question has a hierarchical ID to allow partial matching. For example `storage.luks.password` or -software.repository.checksum. Why: it allows in the future when questions are consistent enough to allow something like -storage.* -> :skip. Also it is needed for matching of answers with type of generic question. -2. every question has a defined default secure answer. Why: it allows user to define that he wants default answers for all questions - to prevent questions to block installation. -3. questions can define additional params in map that help user to answer them. Example repository url and its checksum. - Partition identification for luks password. Why: Getting data only from question text is hard and very unreadable with regexp. - So questions need to specify some easy to match data in addition to the pure text. - E.g. checksum and repository url for automatic repository approval. -4. Question API has method to set answers as path to JSON file. In such case if question - with known answer is asked, it get immediate response. - Why: To allow user define machine answers in advance. -5. Questions API have property that defines if for questions without answer default one is used or if ask user. - -#### Answers Features - -1. Answers contain values in addition to ids that can be matched. To match -id and values, string or array can be used. Array lists all possible values for matching. -2. if key for value is not specified in answer and question contain it, then value is considerd as matched (so partial answer is possible and also it makes backward compatibility easier) -3. For questions without a defined answer, the default strategy for questions will be used. ( so either ask user or use default answer ) -4. All questions and answers ( along with the source from where it comes ) - will be logged for later audit ( ideally write it directly as answers.yml or at least with answers yml compatible syntax ). But! question can define if any value or answer is sensitive and in such case - it will be replaced in the audit. Example answer from luks encryption password question. - - -#### Use cases and their solutions - -1. I am running an unattended installation for the first time and would like to see what questions appear to be able to modify it to -to my needs for mass deployment. -> There is audit which contain logs the exact questions -with all their params, ids, etc. and the answer used with a note if it is answer from answers files, user or default. -Sensitive answers or params will be replaced, so the user has to explicitly specify it again in the file. -2. I run a modified ISO that points to my own software repository. I want it to automatically use my own - GPG key that I know in advance. -> Use answers.yml file -3. I am doing a mass deployment in an environment where the previous requirement was to encrypt luks with a random password - and this partition should not be reused. Also mass deployment should not be blocked by questions. -> Use answers.yml and explicitely specify to skip luks questions. And define to use - default answer instead of asking user. -4. I have my own vendor iso and want to pre-configure installer using CLI before showing web UI. And some actions can/will - questions that I want to answer before user sees UI -> Use answers.yml file - -### Question Types - -| class | description | possible answers | available data | notes | -|--- |--- |--- |--- |--- | -| `autoyast.unsupported` | When there are unsupported elements in an AutoYaST profile | `Abort` `Continue` | `planned` elements to be supported in the future, `unsupported` unsupported elements | | -| `software.medium_error` | When there is issue with access to medium | `Retry` `Skip` | `url` with url where failed access happen | | -| `software.unsigned_file` | When file from repository is not digitally signed. If it should be used | `Yes` `No` | `filename` with name of file | | -| `software.import_gpg` | When signature is sign with unknown GPG key | `Trust` `Skip` | `id` of key `name` of key and `fingerprint` of key | | -| `storage.activate_multipath` | When it looks like system has multipath and if it should be activated | `yes` `no` | | Here it is used lower case. It should be unified. | -| `storage.commit_error` | When some storage actions failed and if it should continue | `yes` `no` | | Also here it is lowercase | -| `storage.luks_activation` | When LUKS encrypted device is detected and it needs password to probe it | `skip` `decrypt` | `device` name, `label` of device, `size` of device and `attempt` the number of attempt | Answer contain additional field password that has to be filled if answer is `decrypt`. Attempt data can be used to limit passing wrong password. | - diff --git a/rust/agama-cli/src/config.rs b/rust/agama-cli/src/config.rs index 13afa5337e..598f80cd2c 100644 --- a/rust/agama-cli/src/config.rs +++ b/rust/agama-cli/src/config.rs @@ -31,7 +31,6 @@ use anyhow::{anyhow, Context}; use clap::Subcommand; use console::style; use fluent_uri::Uri; -use serde_json::json; use tempfile::Builder; use tokio::time::sleep; @@ -175,10 +174,7 @@ async fn patch_config( http_client: &BaseHTTPClient, model: &api::Config, ) -> Result<(), anyhow::Error> { - let model_json = json!(model); - let patch = api::Patch { - update: Some(model_json), - }; + let patch = api::Patch::with_update(model)?; http_client.patch_void("/v2/config", &patch).await?; Ok(()) } diff --git a/rust/agama-lib/src/questions/http_client.rs b/rust/agama-lib/src/questions/http_client.rs index 8403100121..044ed04371 100644 --- a/rust/agama-lib/src/questions/http_client.rs +++ b/rust/agama-lib/src/questions/http_client.rs @@ -21,7 +21,7 @@ use std::time::Duration; use agama_utils::api::{ - patch::{self, Patch}, + patch::Patch, question::{ Answer, AnswerRule, Config as QuestionsConfig, Policy, Question, QuestionSpec, UpdateQuestion, @@ -39,7 +39,7 @@ pub enum QuestionsHTTPClientError { #[error("Unknown question with ID {0}")] UnknownQuestion(u32), #[error(transparent)] - Patch(#[from] patch::Error), + Json(#[from] serde_json::Error), } pub struct HTTPClient { diff --git a/rust/agama-utils/src/api/patch.rs b/rust/agama-utils/src/api/patch.rs index 6c401ce7cf..dad619e888 100644 --- a/rust/agama-utils/src/api/patch.rs +++ b/rust/agama-utils/src/api/patch.rs @@ -22,22 +22,17 @@ use crate::api::config::Config; use serde::{Deserialize, Serialize}; use serde_json::Value; -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error(transparent)] - Json(#[from] serde_json::Error), -} - /// Patch for the config. #[derive(Deserialize, Serialize, utoipa::ToSchema)] #[serde(rename_all = "camelCase")] pub struct Patch { /// Update for the current config. + #[schema(value_type = Option)] pub update: Option, } impl Patch { - pub fn with_update(config: &Config) -> Result { + pub fn with_update(config: &Config) -> Result { Ok(Self { update: Some(serde_json::to_value(config)?), }) diff --git a/rust/package/agama.changes b/rust/package/agama.changes index 36af300af9..a730ea48b0 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Thu Apr 9 06:53:34 UTC 2026 - Imobach Gonzalez Sosa + +- Fix OpenAPI specification for PATCH /config (gh#agama-project/agama#3368). + ------------------------------------------------------------------- Tue Apr 7 16:55:22 UTC 2026 - Ladislav Slezák