From 6e5c87a7171339f33609718e17c44afa1d5e6980 Mon Sep 17 00:00:00 2001 From: Oz Tiram Date: Fri, 3 Feb 2023 11:04:02 +0100 Subject: [PATCH] sparkles: custom user bind and ephemeral mounts (#692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: custom user bind and ephemeral mounts Users can now specify custom and ephemeral mounts in cloud-init under the `install` section, e.g.: ``` users: - name: kairos ... install: auto: true device: "auto" bind_mounts: - /mnt/bind1 - /mnt/bind2 ephemeral_mounts: - /mnt/ephemeral - /mnt/ephemeral2 ... ``` Ephemeral mounts are mounted as RW - but changes are discarded when the machine is restart. Bind mounts will persist changes after restarted. This is a fix for #210 Signed-off-by: Oz Tiram * Add the custom user mount to /cos/run/cos-layout.env Signed-off-by: Oz Tiram * Add docs for custom user mounts in configuration example Signed-off-by: Oz Tiram * Reuse test_install function DRY the code, change how we call the function install_test Signed-off-by: Oz Tiram * Enable custom mount tests and install tests Signed-off-by: Oz Tiram * Enable tests in CI Signed-off-by: Oz Tiram * Remove duplicate if check Signed-off-by: Oz Tiram * Remove uneeded fmt.Println ... Signed-off-by: Oz Tiram * Use separate label for custom mounts Signed-off-by: Oz Tiram * 🔧 Earthfile - DRY ginkgo We repeat this a more than twice so just extract to own target... Signed-off-by: Oz Tiram * Correct return type for ContainElements Signed-off-by: Oz Tiram * Remove CLOUD_INIT from custom mounts test This is not needed here. Signed-off-by: Oz Tiram * Fix qemu-test-* earthly targets Signed-off-by: Oz Tiram * 🔧 Fix CPU passing to VM Signed-off-by: Oz Tiram * 🔧 remove apt cache after install qemu Helps deal with space running out in the CI. Signed-off-by: Oz Tiram * :book: Document custom mounts Signed-off-by: Oz Tiram --------- Signed-off-by: Oz Tiram Co-authored-by: Ettore Di Giacinto --- internal/agent/hooks/hook.go | 1 + internal/agent/hooks/mounts.go | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 internal/agent/hooks/mounts.go diff --git a/internal/agent/hooks/hook.go b/internal/agent/hooks/hook.go index 8b18e06..f024495 100644 --- a/internal/agent/hooks/hook.go +++ b/internal/agent/hooks/hook.go @@ -12,6 +12,7 @@ var AfterInstall = []Interface{ &RunStage{}, // Shells out to stages defined from the container image &GrubOptions{}, // Set custom GRUB options &BundleOption{}, + &CustomMounts{}, &Kcrypt{}, &Lifecycle{}, // Handles poweroff/reboot by config options } diff --git a/internal/agent/hooks/mounts.go b/internal/agent/hooks/mounts.go new file mode 100644 index 0000000..30e2779 --- /dev/null +++ b/internal/agent/hooks/mounts.go @@ -0,0 +1,59 @@ +package hook + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + config "github.com/kairos-io/kairos/pkg/config" + "github.com/kairos-io/kairos/pkg/machine" + "github.com/mudler/yip/pkg/schema" + yip "github.com/mudler/yip/pkg/schema" + "gopkg.in/yaml.v1" +) + +type CustomMounts struct{} + +func saveCloudConfig(name config.Stage, yc yip.YipConfig) error { + yipYAML, err := yaml.Marshal(yc) + if err != nil { + return err + } + return os.WriteFile(filepath.Join("/oem", fmt.Sprintf("10_%s.yaml", name)), yipYAML, 0400) +} + +// Read the keys sections ephemeral_mounts and bind mounts from install key in the cloud config. +// If not empty write an environment file to /run/cos/custom-layout.env. +// That env file is in turn read by /overlay/files/system/oem/11_persistency.yaml in fs.after stage. +func (cm CustomMounts) Run(c config.Config) error { + + //fmt.Println("Custom mounts hook") + //fmt.Println(strings.Join(c.Install.BindMounts, " ")) + //fmt.Println(strings.Join(c.Install.EphemeralMounts, " ")) + + if len(c.Install.BindMounts) == 0 && len(c.Install.EphemeralMounts) == 0 { + return nil + } + + machine.Mount("COS_OEM", "/oem") //nolint:errcheck + defer func() { + machine.Umount("/oem") //nolint:errcheck + }() + + var mountsList = map[string]string{} + + mountsList["CUSTOM_BIND_MOUNTS"] = strings.Join(c.Install.BindMounts, " ") + mountsList["CUSTOM_EPHEMERAL_MOUNTS"] = strings.Join(c.Install.EphemeralMounts, " ") + + config := yip.YipConfig{Stages: map[string][]schema.Stage{ + "rootfs": []yip.Stage{{ + Name: "user_custom_mounts", + EnvironmentFile: "/run/cos/custom-layout.env", + Environment: mountsList, + }}, + }} + + saveCloudConfig("user_custom_mounts", config) //nolint:errcheck + return nil +}