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

storage: Anaconda mode #19352

Merged
merged 2 commits into from
Jan 2, 2024

Conversation

mvollmer
Copy link
Member

@mvollmer mvollmer commented Sep 19, 2023

Anaconda code: https://github.com/mvollmer/anaconda-webui/tree/cockpit-storage

Demo: https://www.youtube.com/watch?v=x3KfKJhBxD0

Next steps after this PR:

  • Discourage the user from actually mounting new filesystems by only offering "Format only" in the format dialog.

@mvollmer mvollmer added the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Sep 19, 2023
@mvollmer
Copy link
Member Author

mvollmer commented Sep 20, 2023

@jkonecny12, please check this out! (start with the demo)

@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 2 times, most recently from 3480ea7 to a1f76ce Compare September 21, 2023 10:28
@mvollmer mvollmer changed the title storage: Anaconda mount point prefix storage: Anaconda mode Sep 21, 2023
doc/anaconda.md Outdated
However, Cockpit (via UDisks2) will still write the new mount point
configuration into the real /etc/fstab (_not_ /sysroot/etc/fstab).

Anaconda will read the real /etc/fstab and reverse engineer the
Copy link

Choose a reason for hiding this comment

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

@vojtechtrefny @VladimirSlavik @poncovka I think Blivet has some support for fstab parsing, right ? I just wonder what else could be there in fstab & if we can't get into a situation where we can't tell what we want to forward to the target system & what now.

Choose a reason for hiding this comment

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

Blivet doesn't have support for parsing fstab yet, but it is planned. But I think it would be better to not write to fstab -- in the "anaconda" mode Cockpit could simply write the mount points to a custom configuration file, all we need in Anaconda is a simple device -> mountpoint "mapping", we don't need the full fstab entry. We could avoid a lot of potential issues by not writing to fstab on the live image (which is not empty by the way).

Copy link

Choose a reason for hiding this comment

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

We (now speaking as a udisks developer) could also add a new option/type to AddConfigurationItem to be able to write to a fstab in a different location than the default /etc/fstab.

Copy link
Member Author

Choose a reason for hiding this comment

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

We (now speaking as a udisks developer) could also add a new option/type to AddConfigurationItem to be able to write to a fstab in a different location than the default /etc/fstab.

I think that would only help if UDisks2 would also watch and read that different location. If modifying the real /etc/fstab is not acceptable, I think I would rather change Cockpit Storage to maintain its own "virtual fstab" (in Browser storage?) and use that instead of the UDisks2 API.

Copy link
Member Author

Choose a reason for hiding this comment

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

We could avoid a lot of potential issues by not writing to fstab on the live image (which is not empty by the way).

What issues do you see?

I can't think of any, tbh. Cockpit Storage will of course not corrupt /etc/fstab, if that is one of your concerns.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cockpit now stores a mountpoint -> device map for Anaconda.

Choose a reason for hiding this comment

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

I think that would only help if UDisks2 would also watch and read that different location.

I guess we could do that, but that would be something too anaconda-specific and I am not sure if @tbzatek would be happy about it.

What issues do you see?

My main issue is with the existing entries in fstab and potential for Anaconda to mix these up with the "installer" entries created by Cockpit.

I am also not sure how well Cockpit (or UDisks to be more precise) handles btrfs subvolumes in fstab, but that's a different story.

There must be Python code for parsing fstab files

Anaconda has some functions for parsing fstab and we are working on more generic support in blivet (see storaged-project/blivet#1119)

but Anaconda probably also needs to look into udev to find the block device that holds a filesystem with a given UUID.

Blivet has this covered.

Can the "simple device" also be a device mapper device, like "/dev/dm-2"? Can Anaconda figure out from there that this is a LVM2 logical volume, for example?

Yes, we (blivet) can identify a device by name, uuid, all the /dev symlinks, basically everything.

In [2]: b.devicetree.resolve_device("/dev/dm-2")
Out[2]: 
LVMLogicalVolumeDevice instance (0x7f53ec3957d0) --
  name = fedora_aida-root  status = True  id = 78
  ...

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that would only help if UDisks2 would also watch and read that different location.

I guess we could do that, but that would be something too anaconda-specific and I am not sure if @tbzatek would be happy about it.

What issues do you see?

My main issue is with the existing entries in fstab and potential for Anaconda to mix these up with the "installer" entries created by Cockpit.

Does Anaconda already look into fstab, or are you referring to Anaconda getting confused during my proposed 'reverse engineering'? If the latter, I think this becomes moot now that Cockpit provides Anaconda with a separate mount-point -> device mapping.

I am also not sure how well Cockpit (or UDisks to be more precise) handles btrfs subvolumes in fstab, but that's a different story.

Once Cockpit supports btrfs, it will handle the subvolumes correctly, see #16408. But currently it is indeed pretty bad at it.

Can the "simple device" also be a device mapper device, like "/dev/dm-2"? Can Anaconda figure out from there that this is a LVM2 logical volume, for example?

Yes, we (blivet) can identify a device by name, uuid, all the /dev symlinks, basically everything.

Nice!

Copy link

Choose a reason for hiding this comment

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

I think that would only help if UDisks2 would also watch and read that different location.

I guess we could do that, but that would be something too anaconda-specific and I am not sure if @tbzatek would be happy about it.

@tbzatek would not be so happy with this I'm afraid.

What issues do you see?

My main issue is with the existing entries in fstab and potential for Anaconda to mix these up with the "installer" entries created by Cockpit.

I have no idea how entries from multiple sources will be visualized (on the D-Bus interface). Besides, the whole RFE seems a little off the UDisks project target.

However, if something like this is about to be needed, we need to think in bigger picture. There are various files that we watch and/or modify. In some cases where these files are consumed by other libraries we pull in - a problem with different prefix in the build time sometimes causes unexpected issues.

Which brings me into another question - should this be considered with (not actually planned yet) mount namespace support? Would this be interesting for your use case?

Feel free to detach this conversation to a separate ticket.

Copy link
Member Author

Choose a reason for hiding this comment

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

[...] Besides, the whole RFE seems a little off the UDisks project target.

Our idea was that we don't want to change UDisks2 at all, or run it in a special way. All should be done in the top-most UI layers of Cockpit.

I still think this is achievable.

Cockpit would write to /etc/fstab (via the UDisks API) for its own bookkeeping benefits. Nobody else needs to pay any attention to it.

@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 2 times, most recently from 004ffbb to 7592ccb Compare September 22, 2023 09:42
pkg/storaged/client.js Fixed Show fixed Hide fixed
pkg/storaged/client.js Fixed Show fixed Hide fixed
@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 3 times, most recently from 037df3d to ce99530 Compare September 22, 2023 12:25
pkg/storaged/anaconda.jsx Fixed Show fixed Hide fixed
pkg/storaged/anaconda.jsx Fixed Show fixed Hide fixed
@mvollmer mvollmer temporarily deployed to gh-cockpituous October 19, 2023 10:53 — with GitHub Actions Inactive
pkg/storaged/pages/other.jsx Fixed Show fixed Hide fixed
pkg/storaged/pages/drive.jsx Fixed Show fixed Hide fixed
pkg/storaged/create-pages.jsx Fixed Show fixed Hide fixed
pkg/storaged/client.js Fixed Show fixed Hide fixed
@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 2 times, most recently from fc2eaea to a1208d9 Compare November 28, 2023 08:02
@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 5 times, most recently from e252280 to f55a870 Compare December 5, 2023 12:05
@mvollmer mvollmer removed the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Dec 5, 2023
Copy link
Member

@martinpitt martinpitt left a comment

Choose a reason for hiding this comment

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

Some remaining tiny nits, but from my POV this is basically ready to go. Then @KKoukiou can start playing around with it from the main-builds COPR.

test/verify/check-storage-anaconda Outdated Show resolved Hide resolved
test/verify/check-storage-anaconda Show resolved Hide resolved
test/verify/check-storage-anaconda Show resolved Hide resolved
martinpitt
martinpitt previously approved these changes Dec 13, 2023
Copy link
Member

@martinpitt martinpitt left a comment

Choose a reason for hiding this comment

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

🚀 as this remains fully malleable for the time being.

@mvollmer
Copy link
Member Author

Upps, I have found a bug: leaving the "Mount point" field empty results in "/" being used as the mount point. Instead it should keep the meaning of "no mount point specified" and either be an error, or lead to skipping of fstab updates.

@mvollmer mvollmer added needswork no-test For doc/workflow changes, or experiments which don't need a full CI run, and removed needswork labels Dec 13, 2023
@mvollmer
Copy link
Member Author

Changes since last review:

client.add_mount_point_prefix = (dir) => {
    const mpp = client.anaconda?.mount_point_prefix;
-    if (mpp) {
+    if (mpp && dir != "") {
        if (dir == "/")
            dir = mpp;
        else
            dir = mpp + dir;
    }
    return dir;
};

And the bug fix in storage: Only action failures should disable the apply button

@mvollmer
Copy link
Member Author

Pixels need to updated.

@mvollmer mvollmer force-pushed the storage-mount-point-prefix branch 2 times, most recently from 5f933e4 to 8eb1cc7 Compare December 13, 2023 11:53
@mvollmer mvollmer removed the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Dec 13, 2023
Copy link
Member

@martinpitt martinpitt left a comment

Choose a reason for hiding this comment

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

i386 unit test has some trouble, retried.

client.anaconda = null;
}

console.log("ANACONDA", client.anaconda);
Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, this runs unconditionally... it's better to remove it I guess.

@@ -242,6 +247,10 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
if (old_opts == undefined)
old_opts = initial_mount_options(client, block);

old_dir = client.strip_mount_point_prefix(old_dir);
if (old_dir === false)
return Promise.reject(_("This device can not be used for the installation target."));
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

Comment on lines +746 to +748
} catch {
console.warn("Can't parse cockpit_anaconda configuration as JSON");
client.anaconda = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

These 3 added lines are not executed by any test. Details


if (dir && mpp) {
if (dir.indexOf(mpp) != 0)
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

const mpp = client.anaconda?.mount_point_prefix;
if (mpp && dir != "") {
if (dir == "/")
dir = mpp;
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

if (dir == "/")
dir = mpp;
else
dir = mpp + dir;
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

Comment on lines +1110 to +1111
"stratis-pool-member": _("member of Stratis pool"),
mounted: _("Filesystem outside the target"),
Copy link
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details

if (use.usage == "mounted") {
location = client.strip_mount_point_prefix(location);
if (location === false)
location = _("(Not part of target)");
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

if (mount_point) {
mp_text = client.strip_mount_point_prefix(mount_point);
if (mp_text == false)
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

@@ -47,6 +47,10 @@ export function mounting_dialog(client, block, mode, forced_options) {
const [old_config, old_dir, old_opts, old_parents] = get_fstab_config(block, true);
const options = old_config ? old_opts : initial_tab_options(client, block, true);

const old_dir_for_display = client.strip_mount_point_prefix(old_dir);
if (old_dir_for_display === false)
return Promise.reject(_("This device can not be used for the installation target."));
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

@@ -107,7 +110,7 @@ function create_fs(pool) {
}),
SelectOne("at_boot", _("At boot"),
{
value: "nofail",
value: client.in_anaconda_mode() ? "local" : "nofail",
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

@mvollmer mvollmer merged commit 5a3c197 into cockpit-project:main Jan 2, 2024
92 of 94 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants