mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
fix(oci): FileBrowser Quantum opens the folder it is given
This commit is contained in:
@@ -304,7 +304,7 @@
|
|||||||
"mode": "0644",
|
"mode": "0644",
|
||||||
"owner": "mapped-application-user",
|
"owner": "mapped-application-user",
|
||||||
"only_if_missing": true,
|
"only_if_missing": true,
|
||||||
"content": "server:\n port: 80\n cacheDir: /home/filebrowser/data/tmp\n sources:\n - path: /folder\n config:\n defaultEnabled: true\nauth:\n adminUsername: admin\n"
|
"content": "http:\n port: 80\nserver:\n cacheDir: /home/filebrowser/data/tmp\n sources:\n - path: /folder\n config:\n defaultEnabled: true\nauth:\n adminUsername: admin\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"startup_healthcheck": {
|
"startup_healthcheck": {
|
||||||
|
|||||||
@@ -304,7 +304,7 @@
|
|||||||
"mode": "0644",
|
"mode": "0644",
|
||||||
"owner": "mapped-application-user",
|
"owner": "mapped-application-user",
|
||||||
"only_if_missing": true,
|
"only_if_missing": true,
|
||||||
"content": "server:\n port: 80\n cacheDir: /home/filebrowser/data/tmp\n sources:\n - path: /folder\n config:\n defaultEnabled: true\nauth:\n adminUsername: admin\n"
|
"content": "http:\n port: 80\nserver:\n cacheDir: /home/filebrowser/data/tmp\n sources:\n - path: /folder\n config:\n defaultEnabled: true\nauth:\n adminUsername: admin\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"startup_healthcheck": {
|
"startup_healthcheck": {
|
||||||
|
|||||||
@@ -330,6 +330,8 @@ INSTALL_COMPLETE=0
|
|||||||
PRESERVE_FAILED_CT=0
|
PRESERVE_FAILED_CT=0
|
||||||
VOLUME_SEED_STAGE_ROOT=""
|
VOLUME_SEED_STAGE_ROOT=""
|
||||||
VOLUME_SEED_TARGETS=()
|
VOLUME_SEED_TARGETS=()
|
||||||
|
# The volumes that have just been filled with what the image has at their path.
|
||||||
|
VOLUME_SEEDED_NOW=()
|
||||||
VOLUME_SEED_STAGES=()
|
VOLUME_SEED_STAGES=()
|
||||||
VOLUME_SEED_MOUNT_TYPES=()
|
VOLUME_SEED_MOUNT_TYPES=()
|
||||||
CANONICAL_INPUT_DIR=""
|
CANONICAL_INPUT_DIR=""
|
||||||
@@ -553,12 +555,23 @@ apply_volume_seeds() {
|
|||||||
|| { oci_log "Could not seed the persistent volume from the image: $target"; failed=1; break; }
|
|| { oci_log "Could not seed the persistent volume from the image: $target"; failed=1; break; }
|
||||||
rm -rf -- "$stage" \
|
rm -rf -- "$stage" \
|
||||||
|| { oci_log "Could not remove the temporary image data: $target"; failed=1; break; }
|
|| { oci_log "Could not remove the temporary image data: $target"; failed=1; break; }
|
||||||
|
VOLUME_SEEDED_NOW+=("$target")
|
||||||
oci_log "Image data copied into the new persistent volume: $target"
|
oci_log "Image data copied into the new persistent volume: $target"
|
||||||
done
|
done
|
||||||
cleanup_volume_seed_staging || { oci_log "Could not remove the temporary image-volume staging directory"; failed=1; }
|
cleanup_volume_seed_staging || { oci_log "Could not remove the temporary image-volume staging directory"; failed=1; }
|
||||||
(( failed == 0 ))
|
(( failed == 0 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Whether a path sits in a volume that has just been filled from the image.
|
||||||
|
# What is there is the copy the image ships, not a file the user kept.
|
||||||
|
filled_from_the_image() {
|
||||||
|
local path=$1 target
|
||||||
|
for target in "${VOLUME_SEEDED_NOW[@]}"; do
|
||||||
|
[[ $path == "$target"/* ]] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
prepare_file_mount_target() {
|
prepare_file_mount_target() {
|
||||||
local requested_target=$1
|
local requested_target=$1
|
||||||
local rootfs="/var/lib/lxc/${VMID}/rootfs"
|
local rootfs="/var/lib/lxc/${VMID}/rootfs"
|
||||||
@@ -1162,8 +1175,13 @@ apply_installer_profile() {
|
|||||||
rm -f "$merged_file"
|
rm -f "$merged_file"
|
||||||
fi
|
fi
|
||||||
if [[ $(jq -r '.only_if_missing // false' <<<"$item") == true && -e $destination ]]; then
|
if [[ $(jq -r '.only_if_missing // false' <<<"$item") == true && -e $destination ]]; then
|
||||||
oci_log "Keeping the existing persistent file: $path"
|
if ! filled_from_the_image "$path"; then
|
||||||
continue
|
oci_log "Keeping the existing persistent file: $path"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# The file of the recipe is the starting configuration: it takes the
|
||||||
|
# place of the one the image ships, never of one the user already had.
|
||||||
|
oci_log "The generated file replaces the one of the image: $path"
|
||||||
fi
|
fi
|
||||||
install -D -m "$mode" /dev/null "$destination" || { failed=1; break; }
|
install -D -m "$mode" /dev/null "$destination" || { failed=1; break; }
|
||||||
jq -er '.content' <<<"$item" >"$destination" || { failed=1; break; }
|
jq -er '.content' <<<"$item" >"$destination" || { failed=1; break; }
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
"""A new volume starts with what the image has at its path, and a recipe may
|
||||||
|
write its own starting file in it. The file of the recipe wins over the copy of
|
||||||
|
the image; a file the user already had, in a reused volume or a host
|
||||||
|
directory, is kept."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
sys.path.insert(0, str(ROOT / "src"))
|
||||||
|
|
||||||
|
from proxmenux_oci.catalog import Catalog
|
||||||
|
|
||||||
|
INSTALLER = (ROOT / "remote/install_oci.sh").read_text()
|
||||||
|
|
||||||
|
|
||||||
|
def function(name):
|
||||||
|
found = re.search(rf"^{name}\(\) \{{\n.*?^\}}\n", INSTALLER, re.S | re.M)
|
||||||
|
assert found, name
|
||||||
|
return found.group(0)
|
||||||
|
|
||||||
|
|
||||||
|
class GeneratedFileTests(unittest.TestCase):
|
||||||
|
def filled(self, path, *volumes):
|
||||||
|
script = f'VOLUME_SEEDED_NOW=({" ".join(volumes)})\n{function("filled_from_the_image")}\nfilled_from_the_image "$1" && echo yes || echo no'
|
||||||
|
done = subprocess.run(["bash", "-c", script, "bash", path], capture_output=True, text=True, check=False)
|
||||||
|
self.assertEqual(done.stderr, "")
|
||||||
|
return done.stdout.strip()
|
||||||
|
|
||||||
|
@unittest.skipUnless(shutil.which("bash"), "bash is needed")
|
||||||
|
def test_a_file_in_a_volume_just_filled_is_the_copy_of_the_image(self):
|
||||||
|
self.assertEqual(self.filled("/home/filebrowser/data/config.yaml", "/home/filebrowser/data"), "yes")
|
||||||
|
self.assertEqual(self.filled("/config/app/settings.yml", "/data", "/config"), "yes")
|
||||||
|
|
||||||
|
@unittest.skipUnless(shutil.which("bash"), "bash is needed")
|
||||||
|
def test_a_file_anywhere_else_is_not(self):
|
||||||
|
self.assertEqual(self.filled("/home/filebrowser/data/config.yaml"), "no")
|
||||||
|
self.assertEqual(self.filled("/home/filebrowser/database/config.yaml", "/home/filebrowser/data"), "no")
|
||||||
|
self.assertEqual(self.filled("/home/filebrowser/data", "/home/filebrowser/data"), "no")
|
||||||
|
|
||||||
|
def test_only_a_volume_that_was_filled_is_recorded(self):
|
||||||
|
body = function("apply_volume_seeds")
|
||||||
|
copied = body.index('cp -a -- "${stage}/." "${destination}/"')
|
||||||
|
self.assertLess(copied, body.index('VOLUME_SEEDED_NOW+=("$target")'))
|
||||||
|
# A host directory that already holds data is kept and not recorded.
|
||||||
|
self.assertLess(body.index("Keeping existing host data without seeding it"), copied)
|
||||||
|
|
||||||
|
def test_the_recipe_file_is_written_over_the_copy_of_the_image_only(self):
|
||||||
|
step = INSTALLER[INSTALLER.index("generated_count=$(jq"):INSTALLER.index("generated_created=$((generated_created + 1))")]
|
||||||
|
self.assertLess(step.index("apply_volume_seeds"), step.index("only_if_missing"))
|
||||||
|
kept = step.index('if ! filled_from_the_image "$path"; then')
|
||||||
|
self.assertLess(kept, step.index("Keeping the existing persistent file"))
|
||||||
|
self.assertLess(step.index("Keeping the existing persistent file"), step.index("The generated file replaces the one of the image"))
|
||||||
|
|
||||||
|
def test_filebrowser_quantum_serves_the_folder_it_mounts(self):
|
||||||
|
template = Catalog(ROOT).compose("filebrowser-quantum")
|
||||||
|
volumes = [item["container_path"] for item in template["container_contract"]["volumes"]]
|
||||||
|
generated = template["proxmox"]["installer_profile"]["generated_files"][0]
|
||||||
|
served = re.search(r"sources:\s*\n\s*- path: (\S+)", generated["content"]).group(1)
|
||||||
|
self.assertIn(served, volumes)
|
||||||
|
self.assertTrue(any(generated["container_path"].startswith(volume + "/") for volume in volumes))
|
||||||
|
self.assertTrue(generated["only_if_missing"])
|
||||||
|
# FileBrowser Quantum 2 reads the port under http, not under server.
|
||||||
|
self.assertRegex(generated["content"], r"(?m)^http:\n port: 80$")
|
||||||
|
self.assertNotRegex(generated["content"], r"(?m)^server:\n port:")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user