forked from lix-project/lix-installer
Support create_directory paths being an existing mount (#547)
* Support create_directory paths being an existing mount * Tidy up after install even on mounts * Repair steam deck test * Fixup some nits
This commit is contained in:
parent
9c915b3f6a
commit
675d93c644
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -292,7 +292,6 @@ jobs:
|
|||
backtrace: full
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
planner: steam-deck
|
||||
extra-args: --persistence /home/runner/.ci-test-nix-home
|
||||
- name: Initial uninstall (without a `nix run` first)
|
||||
run: sudo -E /nix/nix-installer uninstall
|
||||
env:
|
||||
|
@ -327,7 +326,6 @@ jobs:
|
|||
backtrace: full
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
planner: steam-deck
|
||||
extra-args: --persistence /home/runner/.ci-test-nix-home
|
||||
- name: echo $PATH
|
||||
run: echo $PATH
|
||||
- name: Test `nix` with `$GITHUB_PATH`
|
||||
|
|
|
@ -96,8 +96,12 @@ let
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d /nix ]; then
|
||||
echo "/nix exists after uninstall"
|
||||
if [ -d /nix/store ]; then
|
||||
echo "/nix/store exists after uninstall"
|
||||
exit 1
|
||||
fi
|
||||
if [ -d /nix/var ]; then
|
||||
echo "/nix/var exists after uninstall"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -173,6 +177,17 @@ let
|
|||
uninstall = installCases.install-default.uninstall;
|
||||
uninstallCheck = installCases.install-default.uninstallCheck;
|
||||
};
|
||||
install-bind-mounted-nix = {
|
||||
preinstall = ''
|
||||
sudo mkdir -p /nix
|
||||
sudo mkdir -p /bind-mount-for-nix
|
||||
sudo mount --bind /bind-mount-for-nix /nix
|
||||
'';
|
||||
install = installCases.install-default.install;
|
||||
check = installCases.install-default.check;
|
||||
uninstall = installCases.install-default.uninstall;
|
||||
uninstallCheck = installCases.install-default.uninstallCheck;
|
||||
};
|
||||
};
|
||||
cureSelfCases = {
|
||||
cure-self-linux-working = {
|
||||
|
|
|
@ -3,11 +3,13 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use nix::unistd::{chown, Group, User};
|
||||
|
||||
use tokio::fs::{create_dir, remove_dir_all};
|
||||
use tokio::fs::{create_dir, remove_dir_all, remove_file};
|
||||
use tokio::process::Command;
|
||||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::{Action, ActionDescription, ActionErrorKind, ActionState};
|
||||
use crate::action::{ActionError, StatefulAction};
|
||||
use crate::execute_command;
|
||||
|
||||
/** Create a directory at the given location, optionally with an owning user, group, and mode.
|
||||
|
||||
|
@ -20,6 +22,7 @@ pub struct CreateDirectory {
|
|||
user: Option<String>,
|
||||
group: Option<String>,
|
||||
mode: Option<u32>,
|
||||
is_mountpoint: bool,
|
||||
force_prune_on_revert: bool,
|
||||
}
|
||||
|
||||
|
@ -36,6 +39,7 @@ impl CreateDirectory {
|
|||
let user = user.into();
|
||||
let group = group.into();
|
||||
let mode = mode.into();
|
||||
let mut is_mountpoint = false;
|
||||
|
||||
let action_state = if path.exists() {
|
||||
let metadata = tokio::fs::metadata(&path)
|
||||
|
@ -84,7 +88,13 @@ impl CreateDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
tracing::debug!("Creating directory `{}` already complete", path.display(),);
|
||||
// Is it a mountpoint?
|
||||
is_mountpoint = path_is_mountpoint(&path).await.map_err(Self::error)?;
|
||||
tracing::debug!(
|
||||
is_mountpoint,
|
||||
"Creating directory `{}` already complete",
|
||||
path.display(),
|
||||
);
|
||||
ActionState::Completed
|
||||
} else {
|
||||
ActionState::Uncompleted
|
||||
|
@ -96,6 +106,7 @@ impl CreateDirectory {
|
|||
user,
|
||||
group,
|
||||
mode,
|
||||
is_mountpoint,
|
||||
force_prune_on_revert,
|
||||
},
|
||||
state: action_state,
|
||||
|
@ -137,9 +148,15 @@ impl Action for CreateDirectory {
|
|||
user,
|
||||
group,
|
||||
mode,
|
||||
is_mountpoint, // If `is_mountpoint = true` the `ActionState` should be completed.
|
||||
force_prune_on_revert: _,
|
||||
} = self;
|
||||
|
||||
if *is_mountpoint {
|
||||
// A `/nix` mount exists, we don't need to do anything.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let gid = if let Some(group) = group {
|
||||
Some(
|
||||
Group::from_name(group.as_str())
|
||||
|
@ -189,20 +206,28 @@ impl Action for CreateDirectory {
|
|||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
is_mountpoint,
|
||||
force_prune_on_revert,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!(
|
||||
"Remove the directory `{}`{}",
|
||||
path.display(),
|
||||
if *force_prune_on_revert {
|
||||
""
|
||||
} else {
|
||||
" if no other contents exists"
|
||||
}
|
||||
),
|
||||
vec![],
|
||||
)]
|
||||
match (is_mountpoint, force_prune_on_revert) {
|
||||
(true, true) => vec![ActionDescription::new(
|
||||
format!("Clean contents of mountpoint `{}`", path.display(),),
|
||||
vec![],
|
||||
)],
|
||||
(true, false) => vec![],
|
||||
(false, _) => vec![ActionDescription::new(
|
||||
format!(
|
||||
"Remove the directory `{}`{}",
|
||||
path.display(),
|
||||
if *force_prune_on_revert {
|
||||
""
|
||||
} else {
|
||||
" if no other contents exists"
|
||||
}
|
||||
),
|
||||
vec![],
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
|
@ -212,22 +237,50 @@ impl Action for CreateDirectory {
|
|||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
is_mountpoint,
|
||||
force_prune_on_revert,
|
||||
} = self;
|
||||
|
||||
let is_empty = path
|
||||
let contents = path
|
||||
.read_dir()
|
||||
.map_err(|e| ActionErrorKind::Read(path.clone(), e))
|
||||
.map_err(Self::error)?
|
||||
.next()
|
||||
.is_none();
|
||||
.collect::<Vec<_>>();
|
||||
let is_empty = contents.is_empty();
|
||||
|
||||
match (is_empty, force_prune_on_revert) {
|
||||
(true, _) | (false, true) => remove_dir_all(path.clone())
|
||||
match (is_mountpoint, is_empty, force_prune_on_revert) {
|
||||
(true, _, true) => {
|
||||
tracing::debug!("Cleaning mountpoint `{}`", path.display());
|
||||
for child_path in contents {
|
||||
let child_path = child_path
|
||||
.map_err(|e| ActionErrorKind::ReadDir(path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
let child_path_path = child_path.path();
|
||||
let child_path_type = child_path
|
||||
.file_type()
|
||||
.map_err(|e| ActionErrorKind::GettingMetadata(child_path_path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
if child_path_type.is_dir() {
|
||||
remove_dir_all(child_path_path.clone())
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Remove(path.clone(), e))
|
||||
.map_err(Self::error)?
|
||||
} else {
|
||||
remove_file(child_path_path)
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Remove(path.clone(), e))
|
||||
.map_err(Self::error)?
|
||||
}
|
||||
}
|
||||
},
|
||||
(true, _, false) => {
|
||||
tracing::debug!("Not cleaning mountpoint `{}`", path.display());
|
||||
},
|
||||
(false, true, _) | (false, false, true) => remove_dir_all(path.clone())
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Remove(path.clone(), e))
|
||||
.map_err(Self::error)?,
|
||||
(false, false) => {
|
||||
(false, false, false) => {
|
||||
tracing::debug!("Not removing `{}`, the folder is not empty", path.display());
|
||||
},
|
||||
};
|
||||
|
@ -236,6 +289,53 @@ impl Action for CreateDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
// There are cleaner ways of doing this (eg `systemctl status $PATH`) however we need a widely supported way.
|
||||
async fn path_is_mountpoint(path: &Path) -> Result<bool, ActionErrorKind> {
|
||||
let path_str = match path.to_str() {
|
||||
Some(path_str) => path_str,
|
||||
None => return Err(ActionErrorKind::PathNoneString(path.to_path_buf())),
|
||||
};
|
||||
|
||||
let mut mount_command = Command::new("mount");
|
||||
mount_command.process_group(0);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mount_command.arg("-d"); // `-d` means `--dry-run`
|
||||
#[cfg(target_os = "linux")]
|
||||
mount_command.arg("-f"); // `-f` means `--fake` not `--force`
|
||||
|
||||
let output = execute_command(&mut mount_command).await?;
|
||||
let output_string = String::from_utf8(output.stdout).map_err(ActionErrorKind::FromUtf8)?;
|
||||
|
||||
for line in output_string.lines() {
|
||||
let mut line_splitter = line.split(" on ");
|
||||
match line_splitter.next() {
|
||||
Some(_device) => (),
|
||||
None => continue,
|
||||
}
|
||||
let destination_and_options = match line_splitter.next() {
|
||||
Some(destination_and_options) => destination_and_options,
|
||||
None => continue,
|
||||
};
|
||||
// Each line on Linux looks like `portal on /run/user/1000/doc type fuse.portal (rw,nosuid,nodev,relatime,user_id=1000,group_id=100)`
|
||||
#[cfg(target_os = "linux")]
|
||||
let split_token = "type";
|
||||
// Each line on MacOS looks like `/dev/disk3s6 on /System/Volumes/VM (apfs, local, noexec, journaled, noatime, nobrowse)`
|
||||
#[cfg(target_os = "macos")]
|
||||
let split_token = "(";
|
||||
|
||||
if let Some(mount_path) = destination_and_options.rsplit(split_token).last() {
|
||||
let trimmed = mount_path.trim();
|
||||
if trimmed == path_str {
|
||||
tracing::trace!("Found mountpoint for `{mount_path}`");
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -36,7 +36,7 @@ impl CreateNixTree {
|
|||
for path in PATHS {
|
||||
// We use `create_dir` over `create_dir_all` to ensure we always set permissions right
|
||||
create_directories.push(
|
||||
CreateDirectory::plan(path, String::from("root"), None, 0o0755, false)
|
||||
CreateDirectory::plan(path, String::from("root"), None, 0o0755, true)
|
||||
.await
|
||||
.map_err(Self::error)?,
|
||||
)
|
||||
|
|
|
@ -525,6 +525,8 @@ pub enum ActionErrorKind {
|
|||
#[from]
|
||||
std::string::FromUtf8Error,
|
||||
),
|
||||
#[error("Path `{}` could not be converted to valid UTF-8 string", .0.display())]
|
||||
PathNoneString(std::path::PathBuf),
|
||||
/// A MacOS (Darwin) plist related error
|
||||
#[error(transparent)]
|
||||
Plist(#[from] plist::Error),
|
||||
|
|
16
tests/fixtures/linux/linux.json
vendored
16
tests/fixtures/linux/linux.json
vendored
|
@ -8,6 +8,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -41,6 +42,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -51,6 +53,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -61,6 +64,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -71,6 +75,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -81,6 +86,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -91,6 +97,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -101,6 +108,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -111,6 +119,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -121,6 +130,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -131,6 +141,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -141,6 +152,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -151,6 +163,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -161,6 +174,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -221,6 +235,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Completed"
|
||||
|
@ -294,6 +309,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
|
15
tests/fixtures/linux/steam-deck.json
vendored
15
tests/fixtures/linux/steam-deck.json
vendored
|
@ -8,6 +8,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -85,6 +86,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -95,6 +97,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -105,6 +108,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -115,6 +119,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -125,6 +130,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -135,6 +141,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -145,6 +152,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -155,6 +163,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -165,6 +174,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -175,6 +185,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -185,6 +196,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -195,6 +207,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -205,6 +218,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -315,6 +329,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
|
14
tests/fixtures/macos/macos.json
vendored
14
tests/fixtures/macos/macos.json
vendored
|
@ -110,6 +110,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -120,6 +121,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -130,6 +132,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -140,6 +143,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -150,6 +154,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -160,6 +165,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -170,6 +176,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -180,6 +187,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -190,6 +198,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -200,6 +209,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -210,6 +220,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -220,6 +231,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -230,6 +242,7 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -350,6 +363,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
|
Loading…
Reference in a new issue