mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-09-17 15:27:58 +00:00
Add support for common and recovery folders in sysext
Signed-off-by: Itxaka <itxaka@kairos.io>
This commit is contained in:
@@ -32,6 +32,8 @@ const (
|
|||||||
sysextDir = "/var/lib/kairos/extensions/"
|
sysextDir = "/var/lib/kairos/extensions/"
|
||||||
sysextDirActive = "/var/lib/kairos/extensions/active"
|
sysextDirActive = "/var/lib/kairos/extensions/active"
|
||||||
sysextDirPassive = "/var/lib/kairos/extensions/passive"
|
sysextDirPassive = "/var/lib/kairos/extensions/passive"
|
||||||
|
sysextDirRecovery = "/var/lib/kairos/extensions/recovery"
|
||||||
|
sysextDirCommon = "/var/lib/kairos/extensions/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SysExtension represents a system extension
|
// SysExtension represents a system extension
|
||||||
@@ -54,6 +56,12 @@ func ListSystemExtensions(cfg *config.Config, bootState string) ([]SysExtension,
|
|||||||
case "passive":
|
case "passive":
|
||||||
cfg.Logger.Debug("Listing passive system extensions")
|
cfg.Logger.Debug("Listing passive system extensions")
|
||||||
return getDirExtensions(cfg, sysextDirPassive)
|
return getDirExtensions(cfg, sysextDirPassive)
|
||||||
|
case "recovery":
|
||||||
|
cfg.Logger.Debug("Listing recovery system extensions")
|
||||||
|
return getDirExtensions(cfg, sysextDirRecovery)
|
||||||
|
case "common":
|
||||||
|
cfg.Logger.Debug("Listing common system extensions")
|
||||||
|
return getDirExtensions(cfg, sysextDirCommon)
|
||||||
default:
|
default:
|
||||||
cfg.Logger.Debug("Listing all system extensions (Enabled or not)")
|
cfg.Logger.Debug("Listing all system extensions (Enabled or not)")
|
||||||
return getDirExtensions(cfg, sysextDir)
|
return getDirExtensions(cfg, sysextDir)
|
||||||
@@ -124,6 +132,10 @@ func EnableSystemExtension(cfg *config.Config, ext, bootState string, now bool)
|
|||||||
targetDir = sysextDirActive
|
targetDir = sysextDirActive
|
||||||
case "passive":
|
case "passive":
|
||||||
targetDir = sysextDirPassive
|
targetDir = sysextDirPassive
|
||||||
|
case "recovery":
|
||||||
|
targetDir = sysextDirRecovery
|
||||||
|
case "common":
|
||||||
|
targetDir = sysextDirCommon
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("boot state %s not supported", bootState)
|
return fmt.Errorf("boot state %s not supported", bootState)
|
||||||
}
|
}
|
||||||
@@ -157,7 +169,7 @@ func EnableSystemExtension(cfg *config.Config, ext, bootState string, now bool)
|
|||||||
_, stateMatches := cfg.Fs.Stat(fmt.Sprintf("/run/cos/%s_mode", bootState))
|
_, stateMatches := cfg.Fs.Stat(fmt.Sprintf("/run/cos/%s_mode", bootState))
|
||||||
// TODO: Check in UKI?
|
// TODO: Check in UKI?
|
||||||
cfg.Logger.Logger.Debug().Str("boot_state", bootState).Str("filecheck", fmt.Sprintf("/run/cos/%s_state", bootState)).Msg("Checking boot state")
|
cfg.Logger.Logger.Debug().Str("boot_state", bootState).Str("filecheck", fmt.Sprintf("/run/cos/%s_state", bootState)).Msg("Checking boot state")
|
||||||
if stateMatches == nil {
|
if stateMatches == nil || bootState == "common" {
|
||||||
err = cfg.Fs.Symlink(filepath.Join(targetDir, extension.Name), filepath.Join("/run/extensions", extension.Name))
|
err = cfg.Fs.Symlink(filepath.Join(targetDir, extension.Name), filepath.Join("/run/extensions", extension.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create symlink for %s: %w", extension.Name, err)
|
return fmt.Errorf("failed to create symlink for %s: %w", extension.Name, err)
|
||||||
@@ -188,6 +200,10 @@ func DisableSystemExtension(cfg *config.Config, ext string, bootState string, no
|
|||||||
targetDir = sysextDirActive
|
targetDir = sysextDirActive
|
||||||
case "passive":
|
case "passive":
|
||||||
targetDir = sysextDirPassive
|
targetDir = sysextDirPassive
|
||||||
|
case "recovery":
|
||||||
|
targetDir = sysextDirRecovery
|
||||||
|
case "common":
|
||||||
|
targetDir = sysextDirCommon
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("boot state %s not supported", bootState)
|
return fmt.Errorf("boot state %s not supported", bootState)
|
||||||
}
|
}
|
||||||
@@ -213,7 +229,7 @@ func DisableSystemExtension(cfg *config.Config, ext string, bootState string, no
|
|||||||
// This is to avoid disabling the extension in the wrong boot state
|
// This is to avoid disabling the extension in the wrong boot state
|
||||||
_, stateMatches := cfg.Fs.Stat(fmt.Sprintf("/run/cos/%s_mode", bootState))
|
_, stateMatches := cfg.Fs.Stat(fmt.Sprintf("/run/cos/%s_mode", bootState))
|
||||||
cfg.Logger.Logger.Debug().Str("boot_state", bootState).Str("filecheck", fmt.Sprintf("/run/cos/%s_mode", bootState)).Msg("Checking boot state")
|
cfg.Logger.Logger.Debug().Str("boot_state", bootState).Str("filecheck", fmt.Sprintf("/run/cos/%s_mode", bootState)).Msg("Checking boot state")
|
||||||
if stateMatches == nil {
|
if stateMatches == nil || bootState == "common" {
|
||||||
// Remove the symlink from /run/extensions if is in there
|
// Remove the symlink from /run/extensions if is in there
|
||||||
cfg.Logger.Logger.Debug().Str("stat", filepath.Join("/run/extensions", extension.Name)).Msg("Checking if symlink exists")
|
cfg.Logger.Logger.Debug().Str("stat", filepath.Join("/run/extensions", extension.Name)).Msg("Checking if symlink exists")
|
||||||
_, stat := cfg.Fs.Readlink(filepath.Join("/run/extensions", extension.Name))
|
_, stat := cfg.Fs.Readlink(filepath.Join("/run/extensions", extension.Name))
|
||||||
@@ -279,21 +295,15 @@ func RemoveSystemExtension(cfg *config.Config, extension string, now bool) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Check if the extension is enabled in active or passive
|
// Check if the extension is enabled in active or passive
|
||||||
enabledActive, err := GetSystemExtension(cfg, extension, "active")
|
for _, state := range []string{"active", "passive", "recovery", "common"} {
|
||||||
|
enabled, err := GetSystemExtension(cfg, extension, state)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Remove the symlink
|
// Remove the symlink
|
||||||
if err := cfg.Fs.Remove(enabledActive.Location); err != nil {
|
if err := cfg.Fs.Remove(enabled.Location); err != nil {
|
||||||
return fmt.Errorf("failed to remove symlink for %s: %w", enabledActive.Name, err)
|
return fmt.Errorf("failed to remove symlink for %s: %w", enabled.Name, err)
|
||||||
}
|
}
|
||||||
cfg.Logger.Infof("System extension %s disabled from active", enabledActive.Name)
|
cfg.Logger.Infof("System extension %s disabled from %s", enabled.Name, state)
|
||||||
}
|
}
|
||||||
enabledPassive, err := GetSystemExtension(cfg, extension, "passive")
|
|
||||||
if err == nil {
|
|
||||||
// Remove the symlink
|
|
||||||
if err := cfg.Fs.Remove(enabledPassive.Location); err != nil {
|
|
||||||
return fmt.Errorf("failed to remove symlink for %s: %w", enabledPassive.Name, err)
|
|
||||||
}
|
|
||||||
cfg.Logger.Infof("System extension %s disabled from passive", enabledPassive.Name)
|
|
||||||
}
|
}
|
||||||
// Remove the extension
|
// Remove the extension
|
||||||
if err := cfg.Fs.RemoveAll(installed.Location); err != nil {
|
if err := cfg.Fs.RemoveAll(installed.Location); err != nil {
|
||||||
|
@@ -95,6 +95,18 @@ var _ = Describe("Sysext Actions test", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(extensions).To(BeEmpty())
|
Expect(extensions).To(BeEmpty())
|
||||||
})
|
})
|
||||||
|
It("should return no extensions for recovery enabled extensions", func() {
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
extensions, err := action.ListSystemExtensions(config, "recovery")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
})
|
||||||
|
It("should return no extensions for common enabled extensions", func() {
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
extensions, err := action.ListSystemExtensions(config, "common")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
Describe("With empty dir", func() {
|
Describe("With empty dir", func() {
|
||||||
It("should return no extensions", func() {
|
It("should return no extensions", func() {
|
||||||
@@ -112,6 +124,16 @@ var _ = Describe("Sysext Actions test", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(extensions).To(BeEmpty())
|
Expect(extensions).To(BeEmpty())
|
||||||
})
|
})
|
||||||
|
It("should return no extensions for recovery enabled extensions", func() {
|
||||||
|
extensions, err := action.ListSystemExtensions(config, "recovery")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
})
|
||||||
|
It("should return no extensions for common enabled extensions", func() {
|
||||||
|
extensions, err := action.ListSystemExtensions(config, "common")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
Describe("With dir with files", func() {
|
Describe("With dir with files", func() {
|
||||||
It("should not return files that are not valid extensions", func() {
|
It("should not return files that are not valid extensions", func() {
|
||||||
@@ -178,6 +200,12 @@ var _ = Describe("Sysext Actions test", func() {
|
|||||||
extensions, err = action.ListSystemExtensions(config, "passive")
|
extensions, err = action.ListSystemExtensions(config, "passive")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(extensions).To(BeEmpty())
|
Expect(extensions).To(BeEmpty())
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "recovery")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "common")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
// Enable it for passive
|
// Enable it for passive
|
||||||
err = action.EnableSystemExtension(config, "valid.raw", "passive", false)
|
err = action.EnableSystemExtension(config, "valid.raw", "passive", false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@@ -199,6 +227,18 @@ var _ = Describe("Sysext Actions test", func() {
|
|||||||
Location: "/var/lib/kairos/extensions/active/valid.raw",
|
Location: "/var/lib/kairos/extensions/active/valid.raw",
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
// Enable it for recovery
|
||||||
|
err = action.EnableSystemExtension(config, "valid.raw", "recovery", false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// Passive should have the extension
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "recovery")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(Equal([]action.SysExtension{
|
||||||
|
{
|
||||||
|
Name: "valid.raw",
|
||||||
|
Location: "/var/lib/kairos/extensions/recovery/valid.raw",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
})
|
})
|
||||||
It("should enable an installed extension and reload the system with it", func() {
|
It("should enable an installed extension and reload the system with it", func() {
|
||||||
@@ -242,6 +282,43 @@ var _ = Describe("Sysext Actions test", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(readlink).To(Equal(realPath))
|
Expect(readlink).To(Equal(realPath))
|
||||||
})
|
})
|
||||||
|
It("should enable an installed extension and reload the system with it if its a common one", func() {
|
||||||
|
err = config.Fs.WriteFile("/var/lib/kairos/extensions/valid.raw", []byte("valid"), 0644)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
extensions, err := action.ListSystemExtensions(config, "common")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// This basically returns an error if the command is not executed
|
||||||
|
Expect(runner.IncludesCmds([][]string{
|
||||||
|
{"systemctl", "restart", "systemd-sysext"},
|
||||||
|
})).To(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
// Enable it for common
|
||||||
|
err = action.EnableSystemExtension(config, "valid.raw", "common", true)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// Should have refreshed the systemd-sysext
|
||||||
|
Expect(runner.IncludesCmds([][]string{
|
||||||
|
{"systemctl", "restart", "systemd-sysext"},
|
||||||
|
})).ToNot(HaveOccurred())
|
||||||
|
// Should be enabled
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "common")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(Equal([]action.SysExtension{
|
||||||
|
{
|
||||||
|
Name: "valid.raw",
|
||||||
|
Location: "/var/lib/kairos/extensions/common/valid.raw",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
// Active and Passive should be empty
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "active")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
extensions, err = action.ListSystemExtensions(config, "passive")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(extensions).To(BeEmpty())
|
||||||
|
// Symlink should be created in /run/extensions
|
||||||
|
_, err = config.Fs.Stat("/run/extensions/valid.raw")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
It("should enable an installed extension and NOT reload the system with it if we are on the wrong boot state", func() {
|
It("should enable an installed extension and NOT reload the system with it if we are on the wrong boot state", func() {
|
||||||
err = config.Fs.WriteFile("/var/lib/kairos/extensions/valid.raw", []byte("valid"), 0644)
|
err = config.Fs.WriteFile("/var/lib/kairos/extensions/valid.raw", []byte("valid"), 0644)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Reference in New Issue
Block a user