From eb898118f35ff717d9c6f4d3598c1732661435f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 16 Jul 2024 13:47:01 +0100 Subject: [PATCH 01/15] schema: extend with basic storage settings --- rust/agama-lib/share/profile.schema.json | 295 ++++++++++++++++------- 1 file changed, 213 insertions(+), 82 deletions(-) diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index 11381e2da1..dec0c82f54 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -303,6 +303,44 @@ "type": "object", "additionalProperties": false, "properties": { + "boot": { + "$ref": "#/$defs/boot" + }, + "drives": { + "title": "Section describing drives (disks, BIOS RAIDs and multipath devices)", + "type": "array", + "items": { + "title": "Drive description", + "type": "object", + "additionalProperties": false, + "properties": { + "search": { + "description": "The search is applied only to drive devices", + "$ref": "#/$defs/search" + }, + "encrypt": { + "description": "The device is encrypted only if the current partitions are deleted and no new partitions are created", + "$ref": "#/$defs/encrypt" + }, + "format": { + "description": "The device is formatted only if the current partitions are deleted and no new partitions are created", + "$ref": "#/$defs/format" + }, + "mount": { + "description": "The device is mounted only if it is formatted", + "$ref": "#/$defs/mount" + }, + "ptableType": { + "title": "Partition table type", + "description": "The partition table is created only if all the current partitions are deleted", + "enum": ["gpt", "msdos", "dasd"] + }, + "partitions": { + "$ref": "#/$defs/partitions" + } + } + } + }, "guided": { "title": "Settings to execute a Guided Proposal", "type": "object", @@ -347,42 +385,10 @@ ] }, "boot": { - "title": "Configuration of the boot settings", - "type": "object", - "additionalProperties": false, - "required": ["configure"], - "properties": { - "configure": { - "title": "Whether to configure partitions for booting", - "type": "boolean" - }, - "device": { - "title": "Device to use for booting", - "description": "The installation device is used by default for booting", - "type": "string", - "examples": ["/dev/vda"] - } - } + "$ref": "#/$defs/boot" }, "encryption": { - "title": "Encryption settings", - "type": "object", - "additionalProperties": false, - "required": ["password"], - "properties": { - "password": { - "title": "Passphrase to use when creating new encryption devices", - "type": "string" - }, - "method": { - "title": "Method used to create the encryption devices", - "enum": ["luks2", "tpm_fde"] - }, - "pbkdFunction": { - "title": "Password-based key derivation function to use for LUKS2", - "enum": ["pbkdf2", "argon2i", "argon2id"] - } - } + "$ref": "#/$defs/encrypt" }, "space": { "title": "Policy to find space for the new partitions", @@ -461,53 +467,11 @@ "required": ["mount"], "properties": { "mount": { - "title": "Mount point", - "type": "object", - "additionalProperties": false, - "required": ["path"], - "properties": { - "path": { - "title": "Mount path", - "type": "string" - }, - "options": { - "title": "Options to add to the fourth field of fstab", - "type": "array", - "items": { "type": "string" } - } - } + "$ref": "#/$defs/mount" }, "filesystem": { "title": "File system of the volume", - "anyOf": [ - { - "title": "File system type", - "enum": [ - "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", - "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" - ] - }, - { - "title": "Btrfs file system", - "description": "Indicates properties of the Btrfs file system", - "type": "object", - "additionalProperties": false, - "required": ["btrfs"], - "properties": { - "btrfs": { - "title": "Specification of a Btrfs file system", - "type": "object", - "additionalProperties": false, - "properties": { - "snapshots": { - "title": "Whether Btrfs snapshots should be configured", - "type": "boolean" - } - } - } - } - } - ] + "$ref": "#/$defs/filesystemValue" }, "size": { "title": "Size limits", @@ -625,13 +589,16 @@ }, "legacyAutoyastStorage": { "title": "Legacy AutoYaST storage settings", - "description": "Accepts all options of the AutoYaST profile (XML to JSON)", - "type": "object" + "description": "Accepts all options of the AutoYaST partitioning section (XML to JSON)", + "type": "array", + "items": { + "type": "object" + } } }, "$defs": { "sizeString": { - "title": "Human readable size (e.g., '2 GiB')", + "title": "Human readable size", "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?(\\s*([KkMmGgTtPpEeZzYy][iI]?)?[Bb])?$", "examples": ["2 GiB", "1.5 TB", "1TIB", "1073741824 b", "1073741824"] @@ -639,13 +606,177 @@ "sizeInteger": { "title": "Size in bytes", "type": "integer", - "minimum": 0 + "minimum": 0, + "examples": [1024, 2048] }, "sizeValue": { "anyOf": [ { "$ref": "#/$defs/sizeString" }, { "$ref": "#/$defs/sizeInteger" } ] + }, + "filesystemValue": { + "anyOf": [ + { + "title": "File system type", + "enum": [ + "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", + "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" + ] + }, + { + "title": "Btrfs file system", + "description": "Indicates properties of the Btrfs file system", + "type": "object", + "additionalProperties": false, + "required": ["btrfs"], + "properties": { + "btrfs": { + "title": "Specification of a Btrfs file system", + "type": "object", + "additionalProperties": false, + "properties": { + "snapshots": { + "title": "Whether Btrfs snapshots should be configured", + "type": "boolean" + } + } + } + } + } + ] + }, + "boot": { + "title": "Boot options", + "type": "object", + "additionalProperties": false, + "required": ["configure"], + "properties": { + "configure": { + "title": "Whether to configure partitions for booting", + "type": "boolean" + }, + "device": { + "title": "Device to use for booting", + "description": "The installation device is used by default for booting", + "type": "string", + "examples": ["/dev/vda"] + } + } + }, + "search": { + "title": "Search options", + "type": "object", + "additionalProperties": false, + "required": ["name"], + "properties": { + "name": { + "title": "Device name", + "type": "string", + "examples": ["/dev/vda"] + } + } + }, + "encrypt": { + "title": "Encryption options", + "type": "object", + "additionalProperties": false, + "required": ["password"], + "properties": { + "password": { + "title": "Passphrase to use when creating a new encryption device", + "type": "string" + }, + "method": { + "title": "Method used to create the encryption device", + "enum": ["luks2", "tpm_fde"] + }, + "pbkdFunction": { + "title": "Password-based key derivation function to use for LUKS2", + "enum": ["pbkdf2", "argon2i", "argon2id"] + } + } + }, + "format": { + "title": "Format options", + "type": "object", + "additionalProperties": false, + "required": ["filesystem"], + "properties": { + "filesystem": { + "title": "File system to use for formatting the device", + "$ref": "#/$defs/filesystemValue" + }, + "label": { + "title": "File system label", + "type": "string" + }, + "mkfsOptions": { + "title": "Options for creating the file system", + "type": "array", + "items": { "type": "string" } + } + } + }, + "mount": { + "title": "Mount options", + "type": "object", + "additionalProperties": false, + "required": ["path"], + "properties": { + "path": { + "title": "Mount path", + "type": "string", + "examples": ["/dev/vda"] + }, + "options": { + "title": "Options to add to the fourth field of fstab", + "type": "array", + "items": { "type": "string" } + } + } + }, + "partitions": { + "title": "Partitions to create, reuse or delete", + "type": "array", + "items": { + "title": "Partition options", + "type": "object", + "additionalProperties": false, + "properties": { + "search": { + "description": "The search is applied only to the partitions of the selected device", + "$ref": "#/$defs/search" + }, + "create": { + "title": "Options to create the partition", + "description": "These options are ignored if the partition already exists", + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "title": "Partition ID", + "enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "biosBoot"] + }, + "type": { + "title": "Partition type", + "enum": ["primary", "logical"] + } + } + }, + "encrypt": { + "description": "The partition is encrypted only if it is going to be created", + "$ref": "#/$defs/encrypt" + }, + "format": { + "$ref": "#/$defs/format" + }, + "mount": { + "description": "The partition is mounted only if it is formatted", + "$ref": "#/$defs/mount" + } + } + } } } } From 2607aaa3f815dc0aac10f923c890da7865c401a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 16 Jul 2024 13:47:49 +0100 Subject: [PATCH 02/15] schema: add/update examples --- rust/agama-lib/share/examples/autoyast.json | 8 ++ .../share/examples/storage-guided.json | 63 ++++++++++ rust/agama-lib/share/examples/storage.json | 114 ++++++++++-------- 3 files changed, 132 insertions(+), 53 deletions(-) create mode 100644 rust/agama-lib/share/examples/autoyast.json create mode 100644 rust/agama-lib/share/examples/storage-guided.json diff --git a/rust/agama-lib/share/examples/autoyast.json b/rust/agama-lib/share/examples/autoyast.json new file mode 100644 index 0000000000..4eb5099b8f --- /dev/null +++ b/rust/agama-lib/share/examples/autoyast.json @@ -0,0 +1,8 @@ +{ + "legacyAutoyastStorage": [ + { + "device": "/dev/vdc", + "use": "all" + } + ] +} diff --git a/rust/agama-lib/share/examples/storage-guided.json b/rust/agama-lib/share/examples/storage-guided.json new file mode 100644 index 0000000000..573aed64d2 --- /dev/null +++ b/rust/agama-lib/share/examples/storage-guided.json @@ -0,0 +1,63 @@ +{ + "storage": { + "guided": { + "target": { + "disk": "/dev/vdc" + }, + "boot": { + "configure": true, + "device": "/dev/vda" + }, + "encryption": { + "password": "notsecret", + "method": "luks2", + "pbkdFunction": "argon2i" + }, + "space": { + "policy": "custom", + "actions": [ + { "resize": "/dev/vda" }, + { "forceDelete": "/dev/vdb1" } + ] + }, + "volumes": [ + { + "mount": { + "path": "/", + "options": ["ro"] + }, + "filesystem": { + "btrfs": { + "snapshots": true + } + }, + "size": [1024, "5 Gib"], + "target": "default" + }, + { + "mount": { + "path": "/home" + }, + "filesystem": "xfs", + "size": { + "min": "5 GiB", + "max": "20 GiB" + }, + "target": { + "newVg": "/dev/vda" + } + }, + { + "mount": { + "path": "swap" + }, + "filesystem": "swap", + "size": "8 GiB", + "target": { + "newPartition": "/dev/vda" + } + } + ] + } + } +} diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index 573aed64d2..5ea9bc85f6 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -1,63 +1,71 @@ { "storage": { - "guided": { - "target": { - "disk": "/dev/vdc" - }, - "boot": { - "configure": true, - "device": "/dev/vda" - }, - "encryption": { - "password": "notsecret", - "method": "luks2", - "pbkdFunction": "argon2i" - }, - "space": { - "policy": "custom", - "actions": [ - { "resize": "/dev/vda" }, - { "forceDelete": "/dev/vdb1" } - ] - }, - "volumes": [ - { - "mount": { - "path": "/", - "options": ["ro"] - }, - "filesystem": { - "btrfs": { - "snapshots": true - } - }, - "size": [1024, "5 Gib"], - "target": "default" + "boot": { + "configure": true, + "device": "/dev/vda" + }, + "drives": [ + { + "search": { + "name": "/dev/vda" }, - { - "mount": { - "path": "/home" + "ptableType": "gpt", + "partitions": [ + { + "search": { "name": "/dev/vda2" }, + "format": { + "filesystem": { + "btrfs": { + "snapshots": true + } + } + }, + "mount": { + "path": "/", + "options": ["ro"] + } }, - "filesystem": "xfs", - "size": { - "min": "5 GiB", - "max": "20 GiB" + { + "encrypt": { + "password": "notsecret", + "method": "luks2" + }, + "format": { + "filesystem": "xfs" + }, + "mount": { + "path": "/home" + } }, - "target": { - "newVg": "/dev/vda" + { + "encrypt": { + "password": "notsecret", + "method": "luks2" + }, + "format": { + "filesystem": "swap" + }, + "mount": { + "path": "swap" + } } + ] + }, + { + "search": { + "name": "/dev/vdb" }, - { - "mount": { - "path": "swap" - }, - "filesystem": "swap", - "size": "8 GiB", - "target": { - "newPartition": "/dev/vda" - } + "encrypt": { + "password": "notsecret", + "method": "luks2" + }, + "format": { + "filesystem": "ext4" + }, + "mount": { + "path": "/var/log" } - ] - } + } + ] } } From cc362643ff9e8a1a6d31c5dedde0db67bdbfcfb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 16 Jul 2024 14:59:04 +0100 Subject: [PATCH 03/15] rust: changelog --- rust/package/agama.changes | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust/package/agama.changes b/rust/package/agama.changes index a3bcd66804..b2f5eefe21 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Aug 27 13:57:35 UTC 2024 - José Iván López González + +- Schema definition for basic storage settings + (gh#openSUSE/agama#1455). + ------------------------------------------------------------------- Mon Aug 26 11:19:27 UTC 2024 - Martin Vidner @@ -190,7 +196,7 @@ Fri Jun 7 05:58:48 UTC 2024 - Michal Filka - self-signed certificate contains hostname - self-signed certificate is stored into default location - before creating new self-signed certificate a default location - (/etc/agama.d/ssl) is checked for a certificate + (/etc/agama.d/ssl) is checked for a certificate - gh#openSUSE/agama#1228 ------------------------------------------------------------------- From 47d9350d28a1291462268e946876e9bda1199606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Wed, 17 Jul 2024 15:01:12 +0100 Subject: [PATCH 04/15] schema: add missing size --- rust/agama-lib/share/examples/storage.json | 8 ++++++++ rust/agama-lib/share/profile.schema.json | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index 5ea9bc85f6..a08abecdd6 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -26,6 +26,11 @@ } }, { + "create": { + "id": "linux", + "type": "primary", + "size": "10 GiB" + }, "encrypt": { "password": "notsecret", "method": "luks2" @@ -38,6 +43,9 @@ } }, { + "create": { + "size": "2 GiB" + }, "encrypt": { "password": "notsecret", "method": "luks2" diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index dec0c82f54..2fdb146647 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -761,6 +761,10 @@ "type": { "title": "Partition type", "enum": ["primary", "logical"] + }, + "size": { + "title": "Partition size", + "$ref": "#/$defs/sizeValue" } } }, From d3da3aac6b1557eb7aa7202e522e8ab7df66e841 Mon Sep 17 00:00:00 2001 From: Ancor Gonzalez Sosa Date: Tue, 23 Jul 2024 16:25:41 +0200 Subject: [PATCH 05/15] JSON Schema: remove partition type --- rust/agama-lib/share/examples/storage.json | 1 - rust/agama-lib/share/profile.schema.json | 4 ---- 2 files changed, 5 deletions(-) diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index a08abecdd6..eba286eb4a 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -28,7 +28,6 @@ { "create": { "id": "linux", - "type": "primary", "size": "10 GiB" }, "encrypt": { diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index 2fdb146647..6172488ff4 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -758,10 +758,6 @@ "title": "Partition ID", "enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "biosBoot"] }, - "type": { - "title": "Partition type", - "enum": ["primary", "logical"] - }, "size": { "title": "Partition size", "$ref": "#/$defs/sizeValue" From e754dbb5137bea56f76bba4d74d45106d9e5fec3 Mon Sep 17 00:00:00 2001 From: Ancor Gonzalez Sosa Date: Thu, 25 Jul 2024 15:54:49 +0200 Subject: [PATCH 06/15] Doc: update information on the settings for storage --- doc/auto_storage.md | 238 +++++++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 125 deletions(-) diff --git a/doc/auto_storage.md b/doc/auto_storage.md index e7cd92ebea..ac05e24b0a 100644 --- a/doc/auto_storage.md +++ b/doc/auto_storage.md @@ -37,14 +37,14 @@ Storage volumeGroups mdRaids btrfsRaids - bcacheDevices nfsMounts - guided + boot [BootSettings] + encryption [EncryptionSettings] ``` Thus, a `storage` section can contain several entries describing how to configure the corresponding -storage devices and an extra entry used to execute the Guided Proposal in top of the scenario -described by the device entries. +storage devices and a couple of extra entries to setup some general aspects that influence the final +layout. Each volume group, RAID, bcache device or NFS share can represent a new logical device to be created or an existing device from the system to be processed. Entries below `drives` represent devices @@ -55,22 +55,33 @@ found at the system, since Agama cannot create that kind of devices. In fact, a single entry can represent several devices from the system. That is explained in depth at the section "searching existing devices" of this document. +On the first versions of Agama, an alternative syntax will be accepted including only one `guided` +entry. + +``` +Storage + guided +``` + +That allows to rely on the YaST component known as `GuidedProposal`. That alternative will be +removed as soon as all the capabilities of that `GuidedProposal` could be expressed in terms of a +regular storage configuration like the one explained above. + ## Entries for Describing the Devices The formal specification of the previous section can be extended as we dive into the structure. ``` Drive - search: [] + search [] alias [] - encrypt [] - format [] - mount [] + encryption [] + filesystem [] ptableType [] partitions [] VolumeGroup - search: [] + search [] alias [] name [] peSize [] @@ -79,21 +90,20 @@ VolumeGroup delete [] MdRaid - search: [] + search [] alias [] name level [] chunkSize [] devices [<[]>] - encrypt [] - format [] - mount [] + encryption [] + filesystem [Filesystem] ptableType [] partitions [] delete [] BtrfsRaid - search: [] + search [] alias [] dataRaidLevel metadataRaidLevel @@ -109,14 +119,12 @@ NFS mount [] Partition - search: [] + search [] alias [] id [] - type [] size [] - encrypt [EncryptAction] - format [] - mount [] + encryption [Encryption] + filesystem [] delete [] LogicalVolume @@ -128,12 +136,12 @@ LogicalVolume usedPool [] stripes [] stripSize [] - encrypt [] - format [] - mount [] + encryption [Encryption] + filesystem [] delete [] -EncryptAction +Encryption + reuse method key [] pdkdf [] @@ -141,12 +149,11 @@ EncryptAction cipher [] keySize [] -FormatAction - filesystem +Filesystem + reuse + type label [] mkfsOptions [] - -MountAction path mountOptions [] mountBy [] @@ -162,6 +169,17 @@ Size <'default'|string|SizeRange> SizeRange min max + +BootSettings + configure + device + +EncryptionSettings + method + key [] + pdkdf [] + cipher [] + keySize [] ``` To illustrate how all that fits together, let's see the following example in which the first disk of @@ -177,7 +195,7 @@ it) to allocate two file systems. "alias": "pv", "id": "lvm", "size": { "min": "12 GiB" }, - "encrypt": { + "encryption": { "method": "luks2", "key": "my secret passphrase" } @@ -192,13 +210,11 @@ it) to allocate two file systems. "logicalVolumes": [ { "size": { "min": "10 GiB" }, - "format": { "filesystem": "btrfs" }, - "mount": { "path": "/" } + "filesystem": { "path": "/", "type": "btrfs" } }, { "size": "2 GiB", - "format": { "filesystem": "swap" }, - "mount": { "path": "swap" } + "format": { "path": "swap", "type": "swap" } } ] } @@ -237,6 +253,11 @@ represent a size. The following two possibilities are also under consideration. - `{ "gib": 40 }` - `{ "value": 40, "units": "gib" }` +Resizing is also an open topic. We may not be able to easily combine a resize operation with aspects +like ranges (min and max) or automatic sizes. We also need to define how to specify something like +"shink as much as needed to allocate the other partitions". See the section below about deleting and +shrinking. + ## Searching Existing Devices Many sections in the profile are used to describe how some devices must be created, modified or even @@ -516,23 +537,53 @@ system (so the same conditions can be matched by a disk, a partition, an LVM dev } ``` -## Partitions needed for Booting +## Partitions Needed for Booting -When relying on the Agama proposal (see below), there are some options to configure whether (and -where) Agama should calculate and create the extra partitions needed for booting. +Using a `boot` entry makes it possible to configure whether (and where, using an alias) Agama +should calculate and create the extra partitions needed for booting. -If the proposal is not used, Agama will always try to calculate and create those partitions taking -the location of the root file system as a reference. That's the same approach that AutoYaST has -followed for years. +## Keeping an Existing File System or Encryption Layer -## Using the Automatic Proposal +The entries for both `encryption` and `filesystem` contain a flag `reuse` with a default value of +false. It can be used in combination with `search` to specify the device must not be re-encrypted +or re-formatted. + +## Deleting and Shrinking Existing Devices -Agama can rely on the process known as Guided Proposal to calculate all the needed partitions, LVM -devices and file systems based on some general product settings and some user preferences. That -mechanism can also be used as part of the profile and will be executed as a last step, after -processing all the explicit sections that describe devices. +The storage proposal must make possible to define what to do with existing partitions and logical +volumes. Even with existing MD RAIDs or LVM volume groups. -The `guided` section conforms to the following specification. +In order to provide the same capabilities than the Guided proposal (see below) it must be possible +to specify that a given partition (or LVM logical volume) must be: + + - Deleted if needed to make space for the newly defined devices + - Deleted in all cases + - Shrunk to the necessary size to make space for new devices + - Shrunk to a given size, maybe a range, in all cases (not really possible in the current Guided + Proposal) + +It would be desirable to have the possibility of expressing some combinations of the above, like +"try to shrink it to make space but proceed to delete it if shrinking it is not enough". + +For partitions that are marked to be deleted (either mandatory or on demand), it makes no sense to +specify any other usage (like declaring a file system on it). But resizing a partition is more on +the grey area. Often some partitions or logical volumes are resized only to make space for the +declared devices. But since resizing is not a destructive operation it can also make sense to +declare a given partition must be resized and then formatted. + +The exact syntax to specify all the possible actions is still under discussion. The current document +shows how a `delete` attribute could be used in combination with `search` to specify the devices to +delete. An alternative could be to have separate section for each device to specify how to delete +and/or shrink its partitions or logical volumes, instead of integrating that information into the +corresponding `partitions` or `logical_volumes` attributes. + +## Using the Automatic Proposal + +On the first implementations, Agama can rely on the process known as Guided Proposal to calculate +all the needed partitions, LVM devices and file systems based on some general product settings and +some user preferences. That mechanism is offered as a temporary alternative to the more descriptive +syntax explained at previous sections of this document and it's implemented via a `guided` section +that conforms to the following specification. ``` Guided @@ -545,22 +596,13 @@ Guided TargetDevice TargetDisk - disk + disk TargetNewLvm - newLvmVg <[]> + newLvmVg TargetReusedLvm - reusedLvmVg - -BootSettings - configure - device - -EncryptionSettings - password - method - pbkdFunction + reusedLvmVg Volume mountPath @@ -575,16 +617,16 @@ Volume VolumeTarget <'default'|NewPartition|NewVg|UseDevice|UseFilesystem> NewPartition - newPartition + newPartition NewVg - newVg + newVg UseDevice - device + device UseFilesystem - filesystem + filesystem ``` The `device` can be specified in several ways. The simplest one is using one of the strings "disk" @@ -606,16 +648,13 @@ And this will do the same, but creating a new LVM volume group on that first can } ``` -It's also possible to use an alias to specify a concrete disk... +It's also possible to use a device name to specify a concrete disk... ```json "storage": { - "drives": [ - { "alias": "target" } - ], "guided": { "device": { - "disk": "target" + "disk": "/dev/sda" } } } @@ -625,39 +664,16 @@ or to specify the set of disks where the LVM physical volumes can be created. ```json "storage": { - "drives": [ - { - "alias": "nvme", - "search": { "condition": { "property": "driver", "value": "nvme" } } - } - ], "guided": { "device": { - "newLvmVg": ["nvme"] - } - } -} -``` - -The alias can correspond to devices that are created by Agama itself. - -```json -"storage": { - "mdRaids": [ - { - "alias": "newMd" - "devices": [ "..." ], - "level": "raid1" + "newLvmVg": ["/dev/vda", "/dev/vdb"] } - ], - "guided": { - "device": { "disk": "newMd" } } } ``` -Apart from specifying the main target device, aliases can be used wherever a device is expected, eg. -when indicating a special target for a given volume. +Apart from specifying the main target device, device names must be used wherever a device is +expected, eg. when indicating a special target for a given volume. In principle, the list of volumes will have the same format than the existing HTTP API used by the UI for calculating the storage proposal. That is, if the list is not provided the default @@ -666,37 +682,9 @@ with default values. In the future we may consider more advanced mechanisms to i some given volumes or to customize a single volume without having to provide the full list of volume mount paths. -Combining the `guided` section with other possible sections in the profile makes it possible to -achieve the same results than using the Agama user interface with only one exception. The Agama UI -allows to indicate that a given set of partitions can be resized if needed to allocate the volumes, -without actually indicating how much those partitions should be resized. The Guided Proposal -algorithm decides whether to resize and how much based on the other settings. Currently there is no -way to express that in the auto-installation profile. - -### Under Discussion - -It could also be possible to accept a `search` element in all places in which an alias can be used. - -```json -"storage": { - "guided": { - "device": { - "newLvmVg": [ - { "search": { "condition": { "property": "driver", "value": "nvme" } } } - ] - } - } -} -``` - -Even combining that with the string-based syntax suggested for `search`. - -```json -"storage": { - "guided": { - "device": { - "disk": { "search": "/dev/sda" } - } - } -} -``` +The `guided` section makes it possible to achieve the same results than using the Agama user +interface with only one exception. The Agama UI allows to indicate that a given set of partitions +can be resized if needed to allocate the volumes, without actually indicating how much those +partitions should be resized. The Guided Proposal algorithm decides whether to resize and how much +based on the other settings. Currently there is no way to express that in the auto-installation +profile. From 2b4665b24af0b2a96e762cb23f1d2ba55a737215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Thu, 25 Jul 2024 16:08:52 +0100 Subject: [PATCH 07/15] schema: declarative version - Adapt to new agreed format. --- rust/agama-lib/share/examples/storage.json | 56 ++- rust/agama-lib/share/profile.schema.json | 421 ++++++++++++--------- 2 files changed, 258 insertions(+), 219 deletions(-) diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index eba286eb4a..66fb372648 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -13,46 +13,36 @@ "partitions": [ { "search": { "name": "/dev/vda2" }, - "format": { - "filesystem": { - "btrfs": { - "snapshots": true - } - } - }, - "mount": { + "filesystem": { + "reuse": false, + "type": "btrfs", + "btrfsOptions": { + "snapshots": true + }, "path": "/", - "options": ["ro"] + "mountOptions": ["ro"] } }, { - "create": { - "id": "linux", - "size": "10 GiB" - }, - "encrypt": { - "password": "notsecret", + "id": "linux", + "size": "10 GiB", + "encryption": { + "key": "notsecret", "method": "luks2" }, - "format": { - "filesystem": "xfs" - }, - "mount": { + "filesystem": { + "type": "xfs", "path": "/home" } }, { - "create": { - "size": "2 GiB" - }, - "encrypt": { - "password": "notsecret", + "size": "2 GiB", + "encryption": { + "key": "notsecret", "method": "luks2" }, - "format": { - "filesystem": "swap" - }, - "mount": { + "filesystem": { + "type": "swap", "path": "swap" } } @@ -62,14 +52,12 @@ "search": { "name": "/dev/vdb" }, - "encrypt": { - "password": "notsecret", + "encryption": { + "key": "notsecret", "method": "luks2" }, - "format": { - "filesystem": "ext4" - }, - "mount": { + "filesystem": { + "type": "ext4", "path": "/var/log" } } diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index 6172488ff4..ecf8656657 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -299,7 +299,7 @@ } }, "storage": { - "title": "Storage settings", + "title": "Storage settings.", "type": "object", "additionalProperties": false, "properties": { @@ -307,75 +307,87 @@ "$ref": "#/$defs/boot" }, "drives": { - "title": "Section describing drives (disks, BIOS RAIDs and multipath devices)", + "title": "Section describing drives (disks, BIOS RAIDs and multipath devices).", "type": "array", "items": { - "title": "Drive description", - "type": "object", - "additionalProperties": false, - "properties": { - "search": { - "description": "The search is applied only to drive devices", - "$ref": "#/$defs/search" - }, - "encrypt": { - "description": "The device is encrypted only if the current partitions are deleted and no new partitions are created", - "$ref": "#/$defs/encrypt" - }, - "format": { - "description": "The device is formatted only if the current partitions are deleted and no new partitions are created", - "$ref": "#/$defs/format" - }, - "mount": { - "description": "The device is mounted only if it is formatted", - "$ref": "#/$defs/mount" - }, - "ptableType": { - "title": "Partition table type", - "description": "The partition table is created only if all the current partitions are deleted", - "enum": ["gpt", "msdos", "dasd"] + "title": "Drive description.", + "anyOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "search": { + "description": "The search is limited to drives scope.", + "$ref": "#/$defs/search" + }, + "encryption": { + "$ref": "#/$defs/encryption" + }, + "filesystem": { + "description": "The partition table (if any) is deleted.", + "$ref": "#/$defs/filesystem" + } + } }, - "partitions": { - "$ref": "#/$defs/partitions" + { + "type": "object", + "additionalProperties": false, + "properties": { + "search": { + "description": "The search is limited to drives scope.", + "$ref": "#/$defs/search" + }, + "encryption": { + "$ref": "#/$defs/encryption" + }, + "ptableType": { + "title": "Partition table type.", + "description": "The partition table is created only if all the current partitions are deleted.", + "enum": ["gpt", "msdos", "dasd"] + }, + "partitions": { + "$ref": "#/$defs/partitions" + } + } } - } + ] } }, "guided": { - "title": "Settings to execute a Guided Proposal", + "title": "Settings to execute a Guided Proposal.", "type": "object", "additionalProperties": false, "properties": { "target": { - "title": "Target device", + "title": "Target device.", "anyOf": [ { "enum": ["disk", "newLvmVg"] }, { - "title": "Disk device for installing", + "title": "Disk device for installing.", "type": "object", "additionalProperties": false, "required": ["disk"], "properties": { "disk": { - "title": "Disk device name", + "title": "Disk device name.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "New LVM for installing", + "title": "New LVM for installing.", "type": "object", "additionalProperties": false, "required": ["newLvmVg"], "properties": { "newLvmVg": { - "title": "Devices in which to create the physical volumes", + "title": "Devices in which to create the physical volumes.", "type": "array", "items": { - "title": "Disk device name", + "title": "Disk device name.", "type": "string", "examples": ["/dev/vda"] } @@ -388,10 +400,25 @@ "$ref": "#/$defs/boot" }, "encryption": { - "$ref": "#/$defs/encrypt" + "title": "Encryption options.", + "type": "object", + "additionalProperties": false, + "required": ["password"], + "properties": { + "password": { + "title": "Passphrase to use when creating a new encryption device.", + "type": "string" + }, + "method": { + "$ref": "#/$defs/encryptionMethod" + }, + "pbkdFunction": { + "$ref": "#/$defs/encryptionPbkdFunction" + } + } }, "space": { - "title": "Policy to find space for the new partitions", + "title": "Policy to find space for the new partitions.", "type": "object", "additionalProperties": false, "properties": { @@ -411,27 +438,27 @@ "required": ["policy", "actions"], "properties": { "actions": { - "title": "Actions to find space if policy is 'custom'", + "title": "Actions to find space if policy is 'custom'.", "type": "array", "items": { "anyOf": [ { - "title": "Delete device", - "description": "Force device deletion", + "title": "Delete device.", + "description": "Force device deletion.", "type": "object", "required": ["forceDelete"], "additionalProperties": false, "properties": { "forceDelete": { - "title": "Device to delete", + "title": "Device to delete.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "Allow shinking", - "description": "Indicate the device can be shrunk in needed", + "title": "Allow shinking.", + "description": "Indicate the device can be shrunk in needed.", "type": "object", "required": ["resize"], "additionalProperties": false, @@ -459,7 +486,7 @@ } }, "volumes": { - "title": "Set of volumes (file systems) to create", + "title": "Set of volumes (file systems) to create.", "type": "array", "items": { "type": "object", @@ -467,112 +494,103 @@ "required": ["mount"], "properties": { "mount": { - "$ref": "#/$defs/mount" + "title": "Mount options.", + "type": "object", + "additionalProperties": false, + "required": ["path"], + "properties": { + "path": { + "title": "Mount path.", + "type": "string", + "examples": ["/dev/vda"] + }, + "options": { + "title": "Options to add to the fourth field of fstab.", + "type": "array", + "items": { "type": "string" } + } + } }, "filesystem": { - "title": "File system of the volume", - "$ref": "#/$defs/filesystemValue" - }, - "size": { - "title": "Size limits", - "description": "Options to indicate the size of a device", + "title": "File system of the volume.", "anyOf": [ { - "title": "Automatic size", - "description": "The size is auto calculated according to the product", - "const": "auto" - }, - { - "title": "Size unit", - "$ref": "#/$defs/sizeValue" - }, - { - "title": "Size range (e.g., [1024, '2 GiB'])", - "description": "Lower size limit and optionally upper size limit", - "type": "array", - "items": { - "$ref": "#/$defs/sizeValue" - }, - "minItems": 1, - "maxItems": 2, - "examples": [[1024, "2 GiB"]] + "$ref": "#/$defs/filesystemType" }, { - "title": "Size range", + "title": "Btrfs file system.", "type": "object", "additionalProperties": false, + "required": ["btrfs"], "properties": { - "min": { - "title": "Mandatory lower size limit", - "$ref": "#/$defs/sizeValue" - }, - "max": { - "title": "Optional upper size limit", - "$ref": "#/$defs/sizeValue" + "btrfs": { + "$ref": "#/$defs/btrfsOptions" } - }, - "required": ["min"] + } } ] }, + "size": { + "$ref": "#/$defs/size" + }, "target": { - "title": "Location of the file system", - "description": "Options to indicate the location of a file system", + "title": "Location of the file system.", + "description": "Options to indicate the location of a file system.", "anyOf": [ { "const": "default" }, { - "title": "New partition", - "description": "The file system is created over a new partition", + "title": "New partition.", + "description": "The file system is created over a new partition.", "type": "object", "required": ["newPartition"], "additionalProperties": false, "properties": { "newPartition": { - "title": "Name of a disk device", + "title": "Name of a disk device.", "type": "string", "examples": ["/dev/vda"] - } + } } }, { - "title": "Dedicated LVM volume group", - "description": "The file system is created over a dedicated LVM", + "title": "Dedicated LVM volume group.", + "description": "The file system is created over a dedicated LVM.", "type": "object", "additionalProperties": false, "required": ["newVg"], "properties": { "newVg": { - "title": "Name of a disk device", + "title": "Name of a disk device.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "Re-used existing device", - "description": "The file system is created over an existing device", + "title": "Re-used existing device.", + "description": "The file system is created over an existing device.", "type": "object", "additionalProperties": false, "required": ["device"], "properties": { "device": { - "title": "Name of a device", + "title": "Name of a device.", "type": "string", "examples": ["/dev/vda1"] } } }, { - "title": "Re-used existing file system", - "description": "An existing file system is reused (without formatting)", + "title": "Re-used existing file system.", + "description": "An existing file system is reused (without formatting).", "type": "object", "additionalProperties": false, "required": ["filesystem"], "properties": { "filesystem": { - "title": "Name of a device containing the file system", + "title": "Name of a device containing the file system.", "type": "string", "examples": ["/dev/vda1"] } @@ -615,165 +633,198 @@ { "$ref": "#/$defs/sizeInteger" } ] }, - "filesystemValue": { + "size": { + "title": "Size options.", "anyOf": [ { - "title": "File system type", - "enum": [ - "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", - "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" - ] + "title": "Automatic size.", + "description": "The size is auto calculated according to the product.", + "const": "auto" + }, + { + "title": "Size unit.", + "$ref": "#/$defs/sizeValue" }, { - "title": "Btrfs file system", - "description": "Indicates properties of the Btrfs file system", + "title": "Size range.", + "description": "Lower size limit and optionally upper size limit.", + "type": "array", + "items": { + "$ref": "#/$defs/sizeValue" + }, + "minItems": 1, + "maxItems": 2, + "examples": [[1024, 2048], ["1 GiB", "5 GiB"], [1024, "2 GiB"], ["2 GiB"]] + }, + { + "title": "Size range.", "type": "object", "additionalProperties": false, - "required": ["btrfs"], + "required": ["min"], "properties": { - "btrfs": { - "title": "Specification of a Btrfs file system", - "type": "object", - "additionalProperties": false, - "properties": { - "snapshots": { - "title": "Whether Btrfs snapshots should be configured", - "type": "boolean" - } - } + "min": { + "title": "Mandatory lower size limit.", + "$ref": "#/$defs/sizeValue" + }, + "max": { + "title": "Optional upper size limit.", + "$ref": "#/$defs/sizeValue" } } } ] }, - "boot": { - "title": "Boot options", + "search": { + "title": "Search options", "type": "object", "additionalProperties": false, - "required": ["configure"], + "required": ["name"], "properties": { - "configure": { - "title": "Whether to configure partitions for booting", - "type": "boolean" - }, - "device": { - "title": "Device to use for booting", - "description": "The installation device is used by default for booting", + "name": { + "title": "Device name", "type": "string", "examples": ["/dev/vda"] } } }, - "search": { - "title": "Search options", + "boot": { + "title": "Boot options.", "type": "object", "additionalProperties": false, - "required": ["name"], + "required": ["configure"], "properties": { - "name": { - "title": "Device name", + "configure": { + "title": "Whether to configure partitions for booting.", + "type": "boolean" + }, + "device": { + "title": "Device to use for booting.", + "description": "The installation device is used by default for booting.", "type": "string", "examples": ["/dev/vda"] } } }, - "encrypt": { - "title": "Encryption options", + "encryptionMethod": { + "title": "Method used to create the encryption device.", + "enum": ["luks2", "tpm_fde"] + }, + "encryptionPbkdFunction": { + "title": "Password-based key derivation function to use for LUKS2.", + "enum": ["pbkdf2", "argon2i", "argon2id"] + }, + "encryption": { + "title": "Encryption options.", "type": "object", "additionalProperties": false, - "required": ["password"], + "required": ["key"], "properties": { - "password": { - "title": "Passphrase to use when creating a new encryption device", + "key": { + "title": "Passphrase to use when creating a new encryption device.", "type": "string" }, "method": { - "title": "Method used to create the encryption device", - "enum": ["luks2", "tpm_fde"] + "$ref": "#/$defs/encryptionMethod" }, "pbkdFunction": { - "title": "Password-based key derivation function to use for LUKS2", - "enum": ["pbkdf2", "argon2i", "argon2id"] + "$ref": "#/$defs/encryptionPbkdFunction" + }, + "label": { + "title": "LUKS label for the encrypted device.", + "type": "string" + }, + "cipher": { + "title": "Cipher used for LUKS encryption.", + "description": "The value must be compatible with the --cipher argument of the command cryptsetup.", + "type": "string" + }, + "key_size": { + "title": "Key size, in bits, used for LUKS encryption.", + "description": "The value has to be a multiple of 8. The possible key sizes are limited by the used cipher.", + "type": "integer" } } }, - "format": { - "title": "Format options", + "filesystemType": { + "title": "File system type.", + "enum": [ + "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", + "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" + ] + }, + "btrfsOptions": { + "title": "Btrfs file system options.", "type": "object", "additionalProperties": false, - "required": ["filesystem"], "properties": { - "filesystem": { - "title": "File system to use for formatting the device", - "$ref": "#/$defs/filesystemValue" - }, - "label": { - "title": "File system label", - "type": "string" - }, - "mkfsOptions": { - "title": "Options for creating the file system", - "type": "array", - "items": { "type": "string" } + "snapshots": { + "title": "Whether Btrfs snapshots should be configured.", + "type": "boolean" } } }, - "mount": { - "title": "Mount options", + "filesystem": { + "title": "File system options.", "type": "object", "additionalProperties": false, - "required": ["path"], "properties": { + "reuse": { + "title": "Whether to reuse the existing file system (if any).", + "type": "boolean", + "default": false + }, + "type": { + "$ref": "#/$defs/filesystemType" + }, + "label": { + "title": "File system label.", + "type": "string" + }, "path": { - "title": "Mount path", + "title": "Mount path.", "type": "string", "examples": ["/dev/vda"] }, - "options": { - "title": "Options to add to the fourth field of fstab", + "btrfsOptions": { + "$ref": "#/$defs/btrfsOptions" + }, + "mkfsOptions": { + "title": "Options for creating the file system.", + "type": "array", + "items": { "type": "string" } + }, + "mountOptions": { + "title": "Options to add to the fourth field of fstab.", "type": "array", "items": { "type": "string" } } } }, "partitions": { - "title": "Partitions to create, reuse or delete", + "title": "Partitions to create, reuse or delete.", "type": "array", "items": { - "title": "Partition options", + "title": "Partition options.", "type": "object", "additionalProperties": false, "properties": { "search": { - "description": "The search is applied only to the partitions of the selected device", + "description": "The search is limited to the partitions of the selected device scope.", "$ref": "#/$defs/search" }, - "create": { - "title": "Options to create the partition", - "description": "These options are ignored if the partition already exists", - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "title": "Partition ID", - "enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "biosBoot"] - }, - "size": { - "title": "Partition size", - "$ref": "#/$defs/sizeValue" - } - } + "id": { + "title": "Partition ID.", + "enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "bios_boot"] }, - "encrypt": { - "description": "The partition is encrypted only if it is going to be created", - "$ref": "#/$defs/encrypt" + "size": { + "$ref": "#/$defs/sizeValue", + "title": "Partition size." }, - "format": { - "$ref": "#/$defs/format" + "encryption": { + "$ref": "#/$defs/encryption" }, - "mount": { - "description": "The partition is mounted only if it is formatted", - "$ref": "#/$defs/mount" + "filesystem": { + "$ref": "#/$defs/filesystem" } } } From f5b9f92aaf012f51ecb21797a14d046335ad4223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Mon, 19 Aug 2024 13:06:22 +0100 Subject: [PATCH 08/15] schema: allow all possible encryption methods --- rust/agama-lib/share/profile.schema.json | 130 +++++++++++++++++------ 1 file changed, 98 insertions(+), 32 deletions(-) diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index ecf8656657..1dd67588f0 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -355,6 +355,8 @@ }, "guided": { "title": "Settings to execute a Guided Proposal.", + "deprecated": true, + "$comment": "Guided settings will be removed from the schema.", "type": "object", "additionalProperties": false, "properties": { @@ -406,11 +408,11 @@ "required": ["password"], "properties": { "password": { - "title": "Passphrase to use when creating a new encryption device.", - "type": "string" + "$ref": "#/$defs/encryptionPassword" }, "method": { - "$ref": "#/$defs/encryptionMethod" + "title": "Method used to encrypt the devices.", + "enum": ["luks2", "tpm_fde"] }, "pbkdFunction": { "$ref": "#/$defs/encryptionPbkdFunction" @@ -705,46 +707,110 @@ } } }, - "encryptionMethod": { - "title": "Method used to create the encryption device.", - "enum": ["luks2", "tpm_fde"] + "encryptionPassword": { + "title": "Passphrase to use when creating a new encryption device.", + "type": "string" + }, + "encryptionCipher": { + "title": "Cipher used for LUKS encryption.", + "description": "The value must be compatible with the --cipher argument of the command cryptsetup.", + "type": "string" + }, + "encryptionKeySize": { + "title": "Key size, in bits, used for LUKS encryption.", + "description": "The value has to be a multiple of 8. The possible key sizes are limited by the used cipher.", + "type": "integer" }, "encryptionPbkdFunction": { "title": "Password-based key derivation function to use for LUKS2.", "enum": ["pbkdf2", "argon2i", "argon2id"] }, - "encryption": { - "title": "Encryption options.", + "encryptionLUKS1": { + "title": "LUKS1 encryption.", "type": "object", "additionalProperties": false, - "required": ["key"], + "required": ["luks1"], "properties": { - "key": { - "title": "Passphrase to use when creating a new encryption device.", - "type": "string" - }, - "method": { - "$ref": "#/$defs/encryptionMethod" - }, - "pbkdFunction": { - "$ref": "#/$defs/encryptionPbkdFunction" - }, - "label": { - "title": "LUKS label for the encrypted device.", - "type": "string" - }, - "cipher": { - "title": "Cipher used for LUKS encryption.", - "description": "The value must be compatible with the --cipher argument of the command cryptsetup.", - "type": "string" - }, - "key_size": { - "title": "Key size, in bits, used for LUKS encryption.", - "description": "The value has to be a multiple of 8. The possible key sizes are limited by the used cipher.", - "type": "integer" + "luks1": { + "type": "object", + "additionalProperties": false, + "required": ["password"], + "properties": { + "password": { + "$ref": "#/$defs/encryptionPassword" + }, + "cipher": { + "$ref": "#/$defs/encryptionCipher" + }, + "keySize": { + "$ref": "#/$defs/encryptionKeySize" + } + } } } }, + "encryptionLUKS2": { + "title": "LUKS2 encryption.", + "type": "object", + "additionalProperties": false, + "required": ["luks2"], + "properties": { + "luks2": { + "type": "object", + "additionalProperties": false, + "required": ["password"], + "properties": { + "password": { + "$ref": "#/$defs/encryptionPassword" + }, + "cipher": { + "$ref": "#/$defs/encryptionCipher" + }, + "keySize": { + "$ref": "#/$defs/encryptionKeySize" + }, + "pbkdFunction": { + "$ref": "#/$defs/encryptionPbkdFunction" + }, + "label": { + "title": "LUKS label for the encrypted device.", + "type": "string" + } + } + } + } + }, + "encryptionPervasiveLUKS2": { + "title": "LUKS2 pervasive encryption.", + "type": "object", + "additionalProperties": false, + "required": ["pervasiveLuks2"], + "properties": { + "pervasiveLuks2": { + "type": "object", + "additionalProperties": false, + "required": ["password"], + "properties": { + "password": { + "$ref": "#/$defs/encryptionPassword" + } + } + } + } + }, + "encryptionSwap": { + "title": "Swap encryption.", + "enum": ["protected_swap", "secure_swap", "random_swap"] + }, + "encryption": { + "title": "Encryption options.", + "anyOf": [ + { "$ref": "#/$defs/encryptionLUKS1" }, + { "$ref": "#/$defs/encryptionLUKS2" }, + { "$ref": "#/$defs/encryptionPervasiveLUKS2" }, + { "$ref": "#/$defs/encryptionSwap" } + ] + }, "filesystemType": { "title": "File system type.", "enum": [ From d437c38b6dca729fad16ca7d7710b1893a97c9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Mon, 19 Aug 2024 16:12:33 +0100 Subject: [PATCH 09/15] schema: update examples --- rust/agama-lib/share/examples/profile_tw.json | 2 +- rust/agama-lib/share/examples/storage.json | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust/agama-lib/share/examples/profile_tw.json b/rust/agama-lib/share/examples/profile_tw.json index ab3f5d564f..c783a9972d 100644 --- a/rust/agama-lib/share/examples/profile_tw.json +++ b/rust/agama-lib/share/examples/profile_tw.json @@ -26,7 +26,7 @@ }, "root": { "password": "nots3cr3t", - "sshKey": "..." + "sshPublicKey": "..." }, "network": { "connections": [ diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index 66fb372648..afb83ccb05 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -13,6 +13,11 @@ "partitions": [ { "search": { "name": "/dev/vda2" }, + "encryption": { + "luks1": { + "password": "notsecret" + } + }, "filesystem": { "reuse": false, "type": "btrfs", @@ -27,8 +32,10 @@ "id": "linux", "size": "10 GiB", "encryption": { - "key": "notsecret", - "method": "luks2" + "luks2": { + "password": "notsecret", + "label": "data" + } }, "filesystem": { "type": "xfs", @@ -37,10 +44,7 @@ }, { "size": "2 GiB", - "encryption": { - "key": "notsecret", - "method": "luks2" - }, + "encryption": "random_swap", "filesystem": { "type": "swap", "path": "swap" @@ -52,10 +56,6 @@ "search": { "name": "/dev/vdb" }, - "encryption": { - "key": "notsecret", - "method": "luks2" - }, "filesystem": { "type": "ext4", "path": "/var/log" From a9819bcb72b2cfef54c80ad5570165fa7756e882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 20 Aug 2024 06:51:31 +0100 Subject: [PATCH 10/15] schema: restore btrfs schema --- rust/agama-lib/share/examples/storage.json | 7 +-- rust/agama-lib/share/profile.schema.json | 63 ++++++++++------------ 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index afb83ccb05..6ca4a04824 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -20,9 +20,10 @@ }, "filesystem": { "reuse": false, - "type": "btrfs", - "btrfsOptions": { - "snapshots": true + "type": { + "btrfs": { + "snapshots": true + } }, "path": "/", "mountOptions": ["ro"] diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index 1dd67588f0..baa9e1eadb 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -514,23 +514,7 @@ } }, "filesystem": { - "title": "File system of the volume.", - "anyOf": [ - { - "$ref": "#/$defs/filesystemType" - }, - { - "title": "Btrfs file system.", - "type": "object", - "additionalProperties": false, - "required": ["btrfs"], - "properties": { - "btrfs": { - "$ref": "#/$defs/btrfsOptions" - } - } - } - ] + "$ref": "#/$defs/filesystemType" }, "size": { "$ref": "#/$defs/size" @@ -812,22 +796,34 @@ ] }, "filesystemType": { - "title": "File system type.", - "enum": [ - "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", - "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" - ] - }, - "btrfsOptions": { - "title": "Btrfs file system options.", - "type": "object", - "additionalProperties": false, - "properties": { - "snapshots": { - "title": "Whether Btrfs snapshots should be configured.", - "type": "boolean" + "title": "File system type", + "anyOf": [ + { + "enum": [ + "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", + "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" + ] + }, + { + "title": "Btrfs file system", + "type": "object", + "additionalProperties": false, + "required": ["btrfs"], + "properties": { + "btrfs": { + "type": "object", + "additionalProperties": false, + "properties": { + "snapshots": { + "title": "Btrfs snapshots", + "description": "Whether Btrfs snapshots should be configured.", + "type": "boolean" + } + } + } + } } - } + ] }, "filesystem": { "title": "File system options.", @@ -851,9 +847,6 @@ "type": "string", "examples": ["/dev/vda"] }, - "btrfsOptions": { - "$ref": "#/$defs/btrfsOptions" - }, "mkfsOptions": { "title": "Options for creating the file system.", "type": "array", From 24c0adf6f2f542a19e50a74d2e5c4ee657a405b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 20 Aug 2024 09:26:45 +0100 Subject: [PATCH 11/15] schema: improve titles and descriptions --- rust/agama-lib/share/profile.schema.json | 178 +++++++++++++---------- 1 file changed, 100 insertions(+), 78 deletions(-) diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index baa9e1eadb..3476414f14 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -299,7 +299,7 @@ } }, "storage": { - "title": "Storage settings.", + "title": "Storage settings", "type": "object", "additionalProperties": false, "properties": { @@ -307,12 +307,14 @@ "$ref": "#/$defs/boot" }, "drives": { - "title": "Section describing drives (disks, BIOS RAIDs and multipath devices).", + "title": "Drive devices", + "description": "Section describing drives (disks, BIOS RAIDs and multipath devices).", "type": "array", "items": { - "title": "Drive description.", "anyOf": [ { + "title": "Unpartitioned drive", + "description": "Drive without a partition table (e.g., directly formatted).", "type": "object", "additionalProperties": false, "properties": { @@ -330,6 +332,7 @@ } }, { + "title": "Partitioned drive", "type": "object", "additionalProperties": false, "properties": { @@ -341,7 +344,7 @@ "$ref": "#/$defs/encryption" }, "ptableType": { - "title": "Partition table type.", + "title": "Partition table type", "description": "The partition table is created only if all the current partitions are deleted.", "enum": ["gpt", "msdos", "dasd"] }, @@ -354,42 +357,44 @@ } }, "guided": { - "title": "Settings to execute a Guided Proposal.", - "deprecated": true, - "$comment": "Guided settings will be removed from the schema.", + "title": "Guided proposal settings", + "$comment": "Guided settings will be removed from this schema.", "type": "object", "additionalProperties": false, "properties": { "target": { - "title": "Target device.", "anyOf": [ { + "title": "Target for installing", + "description": "Indicates whether to install in a disk or a new LVM.", "enum": ["disk", "newLvmVg"] }, { - "title": "Disk device for installing.", + "title": "Target disk", + "description": "Indicates to install in a specific disk device.", "type": "object", "additionalProperties": false, "required": ["disk"], "properties": { "disk": { - "title": "Disk device name.", + "title": "Device name", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "New LVM for installing.", + "title": "New LVM", + "description": "Indicates to install in a new LVM created over some specific devices.", "type": "object", "additionalProperties": false, "required": ["newLvmVg"], "properties": { "newLvmVg": { - "title": "Devices in which to create the physical volumes.", + "description": "List of devices in which to create the physical volumes.", "type": "array", "items": { - "title": "Disk device name.", + "title": "Device name", "type": "string", "examples": ["/dev/vda"] } @@ -402,7 +407,8 @@ "$ref": "#/$defs/boot" }, "encryption": { - "title": "Encryption options.", + "title": "Encryption", + "description": "Indicates the options for encrypting the new partitions.", "type": "object", "additionalProperties": false, "required": ["password"], @@ -411,7 +417,8 @@ "$ref": "#/$defs/encryptionPassword" }, "method": { - "title": "Method used to encrypt the devices.", + "title": "Encryption method", + "description": "Method used to encrypt the devices.", "enum": ["luks2", "tpm_fde"] }, "pbkdFunction": { @@ -420,7 +427,8 @@ } }, "space": { - "title": "Policy to find space for the new partitions.", + "title": "Space policy", + "description": "Indicates how to find space for the new partitions.", "type": "object", "additionalProperties": false, "properties": { @@ -440,33 +448,34 @@ "required": ["policy", "actions"], "properties": { "actions": { - "title": "Actions to find space if policy is 'custom'.", + "title": "Custom actions", + "description": "Indicates what to do with specific devices.", "type": "array", "items": { "anyOf": [ { - "title": "Delete device.", - "description": "Force device deletion.", + "title": "Force delete", + "description": "Indicates to delete a specific device.", "type": "object", "required": ["forceDelete"], "additionalProperties": false, "properties": { "forceDelete": { - "title": "Device to delete.", + "description": "Name of the device to delete.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "Allow shinking.", - "description": "Indicate the device can be shrunk in needed.", + "title": "Allow shinking", + "description": "Indicates whether a specific device can be shrunk if needed.", "type": "object", "required": ["resize"], "additionalProperties": false, "properties": { "resize": { - "title": "Device to allow resizing", + "description": "Name of the shrinkable device.", "type": "string", "examples": ["/dev/vda"] } @@ -488,7 +497,8 @@ } }, "volumes": { - "title": "Set of volumes (file systems) to create.", + "title": "System volumes", + "description": "List of volumes (file systems) to create.", "type": "array", "items": { "type": "object", @@ -496,20 +506,23 @@ "required": ["mount"], "properties": { "mount": { - "title": "Mount options.", + "title": "Mount properties", "type": "object", "additionalProperties": false, "required": ["path"], "properties": { "path": { - "title": "Mount path.", + "title": "Mount path", "type": "string", "examples": ["/dev/vda"] }, "options": { - "title": "Options to add to the fourth field of fstab.", + "title": "Mount options", + "description": "Options to add to the fourth field of fstab.", "type": "array", - "items": { "type": "string" } + "items": { + "type": "string" + } } } }, @@ -520,63 +533,65 @@ "$ref": "#/$defs/size" }, "target": { - "title": "Location of the file system.", - "description": "Options to indicate the location of a file system.", + "title": "Volume target", + "description": "Options to indicate the location of a volume.", "anyOf": [ { + "title": "Default target", + "description": "The volume is created in the target device for installing.", "const": "default" }, { - "title": "New partition.", - "description": "The file system is created over a new partition.", + "title": "New partition", + "description": "The volume is created over a new partition in a specific disk.", "type": "object", "required": ["newPartition"], "additionalProperties": false, "properties": { "newPartition": { - "title": "Name of a disk device.", + "description": "Name of a disk device.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "Dedicated LVM volume group.", - "description": "The file system is created over a dedicated LVM.", + "title": "Dedicated LVM volume group", + "description": "The volume is created over a new dedicated LVM.", "type": "object", "additionalProperties": false, "required": ["newVg"], "properties": { "newVg": { - "title": "Name of a disk device.", + "description": "Name of a disk device.", "type": "string", "examples": ["/dev/vda"] } } }, { - "title": "Re-used existing device.", - "description": "The file system is created over an existing device.", + "title": "Re-used existing device", + "description": "The volume is created over an existing device.", "type": "object", "additionalProperties": false, "required": ["device"], "properties": { "device": { - "title": "Name of a device.", + "description": "Name of a device.", "type": "string", "examples": ["/dev/vda1"] } } }, { - "title": "Re-used existing file system.", + "title": "Re-used existing file system", "description": "An existing file system is reused (without formatting).", "type": "object", "additionalProperties": false, "required": ["filesystem"], "properties": { "filesystem": { - "title": "Name of a device containing the file system.", + "description": "Name of a device containing the file system.", "type": "string", "examples": ["/dev/vda1"] } @@ -593,7 +608,7 @@ }, "legacyAutoyastStorage": { "title": "Legacy AutoYaST storage settings", - "description": "Accepts all options of the AutoYaST partitioning section (XML to JSON)", + "description": "Accepts all options of the AutoYaST partitioning section (i.e., XML to JSON)", "type": "array", "items": { "type": "object" @@ -620,19 +635,18 @@ ] }, "size": { - "title": "Size options.", + "title": "Size options", "anyOf": [ { - "title": "Automatic size.", + "title": "Automatic size", "description": "The size is auto calculated according to the product.", "const": "auto" }, { - "title": "Size unit.", "$ref": "#/$defs/sizeValue" }, { - "title": "Size range.", + "title": "Size range (tuple systax)", "description": "Lower size limit and optionally upper size limit.", "type": "array", "items": { @@ -643,17 +657,17 @@ "examples": [[1024, 2048], ["1 GiB", "5 GiB"], [1024, "2 GiB"], ["2 GiB"]] }, { - "title": "Size range.", + "title": "Size range", "type": "object", "additionalProperties": false, "required": ["min"], "properties": { "min": { - "title": "Mandatory lower size limit.", + "title": "Mandatory lower size limit", "$ref": "#/$defs/sizeValue" }, "max": { - "title": "Optional upper size limit.", + "title": "Optional upper size limit", "$ref": "#/$defs/sizeValue" } } @@ -674,43 +688,46 @@ } }, "boot": { - "title": "Boot options.", + "title": "Boot options", + "description": "Allows configuring boot partitions automatically.", "type": "object", "additionalProperties": false, "required": ["configure"], "properties": { "configure": { - "title": "Whether to configure partitions for booting.", + "title": "Configure boot", + "description": "Whether to configure partitions for booting.", "type": "boolean" }, "device": { - "title": "Device to use for booting.", - "description": "The installation device is used by default for booting.", + "title": "Boot device", + "description": "The target installation device is used by default.", "type": "string", "examples": ["/dev/vda"] } } }, "encryptionPassword": { - "title": "Passphrase to use when creating a new encryption device.", + "title": "Encryption password", + "description": "Password to use when creating a new encryption device.", "type": "string" }, "encryptionCipher": { - "title": "Cipher used for LUKS encryption.", + "title": "LUKS cipher", "description": "The value must be compatible with the --cipher argument of the command cryptsetup.", "type": "string" }, "encryptionKeySize": { - "title": "Key size, in bits, used for LUKS encryption.", - "description": "The value has to be a multiple of 8. The possible key sizes are limited by the used cipher.", + "title": "LUKS key size", + "description": "The value (in bits) has to be a multiple of 8. The possible key sizes are limited by the used cipher.", "type": "integer" }, "encryptionPbkdFunction": { - "title": "Password-based key derivation function to use for LUKS2.", + "title": "LUKS2 password-based key derivation", "enum": ["pbkdf2", "argon2i", "argon2id"] }, "encryptionLUKS1": { - "title": "LUKS1 encryption.", + "title": "LUKS1 encryption", "type": "object", "additionalProperties": false, "required": ["luks1"], @@ -734,7 +751,7 @@ } }, "encryptionLUKS2": { - "title": "LUKS2 encryption.", + "title": "LUKS2 encryption", "type": "object", "additionalProperties": false, "required": ["luks2"], @@ -757,7 +774,7 @@ "$ref": "#/$defs/encryptionPbkdFunction" }, "label": { - "title": "LUKS label for the encrypted device.", + "title": "LUKS2 label", "type": "string" } } @@ -765,7 +782,7 @@ } }, "encryptionPervasiveLUKS2": { - "title": "LUKS2 pervasive encryption.", + "title": "LUKS2 pervasive encryption", "type": "object", "additionalProperties": false, "required": ["pervasiveLuks2"], @@ -783,11 +800,10 @@ } }, "encryptionSwap": { - "title": "Swap encryption.", + "title": "Swap encryptions", "enum": ["protected_swap", "secure_swap", "random_swap"] }, "encryption": { - "title": "Encryption options.", "anyOf": [ { "$ref": "#/$defs/encryptionLUKS1" }, { "$ref": "#/$defs/encryptionLUKS2" }, @@ -796,9 +812,9 @@ ] }, "filesystemType": { - "title": "File system type", "anyOf": [ { + "title": "File system type", "enum": [ "bcachefs", "btrfs", "exfat", "ext2", "ext3", "ext4", "f2fs", "jfs", "nfs", "nilfs2", "ntfs", "reiserfs", "swap", "tmpfs", "vfat", "xfs" @@ -816,7 +832,7 @@ "properties": { "snapshots": { "title": "Btrfs snapshots", - "description": "Whether Btrfs snapshots should be configured.", + "description": "Whether to configrue Btrfs snapshots.", "type": "boolean" } } @@ -826,12 +842,13 @@ ] }, "filesystem": { - "title": "File system options.", + "title": "File system options", "type": "object", "additionalProperties": false, "properties": { "reuse": { - "title": "Whether to reuse the existing file system (if any).", + "title": "Reuse file system", + "description": "Whether to reuse the existing file system (if any).", "type": "boolean", "default": false }, @@ -839,31 +856,36 @@ "$ref": "#/$defs/filesystemType" }, "label": { - "title": "File system label.", + "title": "File system label", "type": "string" }, "path": { - "title": "Mount path.", + "title": "Mount path", "type": "string", "examples": ["/dev/vda"] }, "mkfsOptions": { - "title": "Options for creating the file system.", + "title": "mkfs options", + "description": "Options for creating the file system.", "type": "array", - "items": { "type": "string" } + "items": { + "type": "string" + } }, "mountOptions": { - "title": "Options to add to the fourth field of fstab.", + "title": "Mount options", + "description": "Options to add to the fourth field of fstab.", "type": "array", "items": { "type": "string" } } } }, "partitions": { - "title": "Partitions to create, reuse or delete.", + "title": "Partitions", + "description": "Partitions to create, reuse or delete.", "type": "array", "items": { - "title": "Partition options.", + "title": "Partition options", "type": "object", "additionalProperties": false, "properties": { @@ -872,12 +894,12 @@ "$ref": "#/$defs/search" }, "id": { - "title": "Partition ID.", + "title": "Partition ID", "enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "bios_boot"] }, "size": { - "$ref": "#/$defs/sizeValue", - "title": "Partition size." + "title": "Partition size", + "$ref": "#/$defs/sizeValue" }, "encryption": { "$ref": "#/$defs/encryption" From 0c4f1f39a0cb2e70259871b1e77fa2f91b7f29b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 20 Aug 2024 09:56:15 +0100 Subject: [PATCH 12/15] doc: update auto storage --- doc/auto_storage.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/doc/auto_storage.md b/doc/auto_storage.md index ac05e24b0a..46145433f5 100644 --- a/doc/auto_storage.md +++ b/doc/auto_storage.md @@ -15,7 +15,7 @@ JSON validation will be performed for it. ### Implementation Considerations for AutoYaST Specification In principle, implementing the legacy AutoYaST module is as simple as converting the corresponding -section of the profile into a `Y2Storage::PartitioningSection` object and use +section of the profile into a `Y2Storage::PartitioningSection` object and use `Y2Storage::AutoInstProposal` to calculate the result. But there are some special cases in which AutoYaST fallbacks to read some settings from the YaST @@ -142,12 +142,24 @@ LogicalVolume Encryption reuse - method - key [] - pdkdf [] - label [] + type + +EncryptionType + +EncryptionLUKS1 + password + keySize [] cipher [] + +EncryptionLUKS2 + password keySize [] + cipher [] + pdkdf [] + label [] + +EncryptionPervasiveLUKS2 + password Filesystem reuse @@ -191,13 +203,12 @@ it) to allocate two file systems. "drives": [ { "partitions": [ - { + { "alias": "pv", "id": "lvm", "size": { "min": "12 GiB" }, "encryption": { - "method": "luks2", - "key": "my secret passphrase" + "luks2": { "password": "my secret passphrase" } } } ] @@ -214,7 +225,7 @@ it) to allocate two file systems. }, { "size": "2 GiB", - "format": { "path": "swap", "type": "swap" } + "filesystem": { "path": "swap", "type": "swap" } } ] } @@ -325,7 +336,7 @@ within them and create new partitions of type RAID. }, "delete": true }, - { + { "alias": "newRaidPart", "id": "raid", "size": { "min": "1 GiB" } @@ -597,7 +608,7 @@ TargetDevice TargetDisk disk - + TargetNewLvm newLvmVg @@ -618,10 +629,10 @@ VolumeTarget <'default'|NewPartition|NewVg|UseDevice|UseFilesystem> NewPartition newPartition - + NewVg newVg - + UseDevice device From 9ec73946c4e5eafc32065e7cc510c083615ad2ec Mon Sep 17 00:00:00 2001 From: Ancor Gonzalez Sosa Date: Thu, 22 Aug 2024 12:00:44 +0200 Subject: [PATCH 13/15] Document the approach for resizing and deleting devices --- doc/auto_storage.md | 156 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 131 insertions(+), 25 deletions(-) diff --git a/doc/auto_storage.md b/doc/auto_storage.md index 46145433f5..686f109c5e 100644 --- a/doc/auto_storage.md +++ b/doc/auto_storage.md @@ -126,6 +126,7 @@ Partition encryption [Encryption] filesystem [] delete [] + deleteIfNeeded [] LogicalVolume search [] @@ -139,7 +140,7 @@ LogicalVolume encryption [Encryption] filesystem [] delete [] - + deleteIfNeeded [] Encryption reuse type @@ -255,6 +256,10 @@ into the following: - If the product does not specify a default volume, the behavior is still not defined (there are several reasonable options). +It is also possible to specify "current" as a size value for partitions and logical volumes that +already exist in the system. The usage of "current" and how it affects resizing the corresponding +devices is explained at a separate section below. + ### Under Discussion As explained, it should be possible to specify the sizes as "default", as a range or as a fixed @@ -264,10 +269,11 @@ represent a size. The following two possibilities are also under consideration. - `{ "gib": 40 }` - `{ "value": 40, "units": "gib" }` -Resizing is also an open topic. We may not be able to easily combine a resize operation with aspects -like ranges (min and max) or automatic sizes. We also need to define how to specify something like -"shink as much as needed to allocate the other partitions". See the section below about deleting and -shrinking. +## Partitions Needed for Booting + +Using a `boot` entry makes it possible to configure whether (and where, using an alias) Agama +should calculate and create the extra partitions needed for booting. If the device is not +specified, Agama will take the location of the root file system as a reference. ## Searching Existing Devices @@ -548,11 +554,6 @@ system (so the same conditions can be matched by a disk, a partition, an LVM dev } ``` -## Partitions Needed for Booting - -Using a `boot` entry makes it possible to configure whether (and where, using an alias) Agama -should calculate and create the extra partitions needed for booting. - ## Keeping an Existing File System or Encryption Layer The entries for both `encryption` and `filesystem` contain a flag `reuse` with a default value of @@ -564,29 +565,134 @@ or re-formatted. The storage proposal must make possible to define what to do with existing partitions and logical volumes. Even with existing MD RAIDs or LVM volume groups. -In order to provide the same capabilities than the Guided proposal (see below) it must be possible -to specify that a given partition (or LVM logical volume) must be: +A `search` section allows to match the definition of a partition or an LVM logical volume with one +(or several) devices existing in the system. In order to provide the same capabilities than the +Guided proposal (see below) it must be possible to specify that a given partition or volume must be: - Deleted if needed to make space for the newly defined devices - Deleted in all cases - Shrunk to the necessary size to make space for new devices - - Shrunk to a given size, maybe a range, in all cases (not really possible in the current Guided + - Shrunk or extended to a given size, maybe a range (not really possible in the current Guided Proposal) -It would be desirable to have the possibility of expressing some combinations of the above, like -"try to shrink it to make space but proceed to delete it if shrinking it is not enough". +It is even possible to express some combinations of the above, like "try to shrink it to make space +but proceed to delete it if shrinking it is not enough". + +Deletion can be achieved with the corresponding `delete` flag or the alternative `deleteIfNeeded`. +If any of those flags are active for a partition, it makes no sense to specify any other usage +(like declaring a file system on it). + +The following example deletes the partition with the label "root" in all cases and, if needed, keeps +deleting other partitions as needed to make space for the new partition of 30 GiB. + +```json +"storage": { + "drives": [ + { + "partitions": [ + { + "search": { + "condition": { "property": "fsLabel", "value": "root" } + }, + "delete": true + }, + { "search": {}, "deleteIfNeeded": true }, + { "size": "30 GiB" } + ] + } + ] +} +``` + +Often some partitions or logical volumes are shrunk only to make space for the declared devices. But +since resizing is not a destructive operation, it can also make sense to declare a given partition +must be resized (shrunk or extended) and then formatted and/or mounted. + +In any case, note that resizing a partition can be limited depending on its content, the filesystem +type, etc. + +Combining `search` and `resize` is enough to indicate Agama is expected to resize a given partition +if possible. The keyword "current" can be used eveywhere a size is expected and it is always +equivalent to the exact original size of the device. The simplest way to use "current" is to just +specify that the matched device should keep its original size. That's the default for searched (and +found) devices if `size` is completely omitted. + +```json +"storage": { + "drives": [ + { + "partitions": [ + { + "search": { + "condition": { "property": "fsLabel", "value": "reuse" } + }, + "size": "current" + } + ] + } + ] +} +``` + +Using "current" for the min and max values of a size allows to specify how a device could be resized +if possible. See the following examples with explanatory filesystem labels. -For partitions that are marked to be deleted (either mandatory or on demand), it makes no sense to -specify any other usage (like declaring a file system on it). But resizing a partition is more on -the grey area. Often some partitions or logical volumes are resized only to make space for the -declared devices. But since resizing is not a destructive operation it can also make sense to -declare a given partition must be resized and then formatted. +```json +"storage": { + "drives": [ + { + "partitions": [ + { + "search": { + "condition": { "property": "fsLabel", "value": "shrinkIfNeeded" } + }, + "size": { "min": 0, "max": "current" } + }, + { + "search": { + "condition": { "property": "fsLabel", "value": "resizeToFixedSize" } + }, + "size": "15 GiB" + }, + { + "search": { + "condition": { "property": "fsLabel", "value": "resizeByRange" } + }, + "size": { "min": "10 GiB", "max": "50 GiB" } + }, + { + "search": { + "condition": { "property": "fsLabel", "value": "growAsMuchAsPossible" } + }, + "size": { "min": "current" } + }, + ] + } + ] +} +``` + +Of course, when the size limits are specified as a combination of "current" and a fixed value, the +user must still make sure that the resulting min is not bigger than the resulting max. + +Both `deleteIfNeeded` and a size range can be combined to indicate that Agama should try to make +space first by shrinking the partitions and deleting them only if shrinking is not enough. -The exact syntax to specify all the possible actions is still under discussion. The current document -shows how a `delete` attribute could be used in combination with `search` to specify the devices to -delete. An alternative could be to have separate section for each device to specify how to delete -and/or shrink its partitions or logical volumes, instead of integrating that information into the -corresponding `partitions` or `logical_volumes` attributes. +```json +"storage": { + "drives": [ + { + "partitions": [ + { + "search": {}, + "size": { "min": 0, "max": "current" }, + "deleteIfNeeded": true + } + ] + } + ] +} +``` ## Using the Automatic Proposal From 5246166d7e0e769197d555bc4d61083debe227d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 27 Aug 2024 14:20:51 +0100 Subject: [PATCH 14/15] schema: add mountBy --- rust/agama-lib/share/examples/storage.json | 1 + rust/agama-lib/share/profile.schema.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/rust/agama-lib/share/examples/storage.json b/rust/agama-lib/share/examples/storage.json index 6ca4a04824..3c80bc5e76 100644 --- a/rust/agama-lib/share/examples/storage.json +++ b/rust/agama-lib/share/examples/storage.json @@ -26,6 +26,7 @@ } }, "path": "/", + "mountBy": "uuid", "mountOptions": ["ro"] } }, diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index 3476414f14..a3b0085f65 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -864,6 +864,10 @@ "type": "string", "examples": ["/dev/vda"] }, + "mountBy": { + "title": "How to mount the device", + "enum": ["device", "id", "label", "path", "uuid"] + }, "mkfsOptions": { "title": "mkfs options", "description": "Options for creating the file system.", From 9ddaa373ba8e2710175c5c118071f274e9593294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Tue, 27 Aug 2024 15:13:29 +0100 Subject: [PATCH 15/15] schema: several fixes from review --- rust/agama-lib/share/profile.schema.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rust/agama-lib/share/profile.schema.json b/rust/agama-lib/share/profile.schema.json index a3b0085f65..d61873f068 100644 --- a/rust/agama-lib/share/profile.schema.json +++ b/rust/agama-lib/share/profile.schema.json @@ -340,9 +340,6 @@ "description": "The search is limited to drives scope.", "$ref": "#/$defs/search" }, - "encryption": { - "$ref": "#/$defs/encryption" - }, "ptableType": { "title": "Partition table type", "description": "The partition table is created only if all the current partitions are deleted.", @@ -358,7 +355,7 @@ }, "guided": { "title": "Guided proposal settings", - "$comment": "Guided settings will be removed from this schema.", + "$comment": "This guided section will be extracted to a separate schema. Only storage and legacyAutoyastStorage will be offered as valid schemas for the storage config.", "type": "object", "additionalProperties": false, "properties": { @@ -646,7 +643,7 @@ "$ref": "#/$defs/sizeValue" }, { - "title": "Size range (tuple systax)", + "title": "Size range (tuple syntax)", "description": "Lower size limit and optionally upper size limit.", "type": "array", "items": {