mirror of
https://github.com/kairos-io/immucore.git
synced 2025-09-01 14:46:31 +00:00
Rework workflow (#77)
This makes immucore run more in parallel rather than block everything else. We just tell sysroot.mount that eventually it will be mounted and to wait for a bit. This allows us to be more flexible where to run and run in parallel in cases like cdrom in which we may do things but we need the sysroot to be mounted already but not from us. Also adds the initramfs stage directly in immucore and merges all the dracut config into one Dont create sysroot, just add a timeout override so it waits for us Dont block on the service, just make sure to finish before initrd.target Fix mounts from cmdline More proper log Store logs under the /run/immucore dir Store rootfs and initramfs logs separated Do not log the full stages in INFO level Run initramfs stage in immucore directly on boot and cd/netboot Drop systemd requirement from dracut module Signed-off-by: Itxaka itxaka.garcia@spectrocloud.com
This commit is contained in:
191
internal/utils/chroot.go
Normal file
191
internal/utils/chroot.go
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright © 2022 SUSE LLC
|
||||
Copyright © 2023 Kairos authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Chroot represents the struct that will allow us to run commands inside a given chroot.
|
||||
type Chroot struct {
|
||||
path string
|
||||
defaultMounts []string
|
||||
activeMounts []string
|
||||
}
|
||||
|
||||
func NewChroot(path string) *Chroot {
|
||||
return &Chroot{
|
||||
path: path,
|
||||
defaultMounts: []string{"/dev", "/proc", "/sys", "/run", "/tmp"},
|
||||
activeMounts: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// ChrootedCallback runs the given callback in a chroot environment.
|
||||
func ChrootedCallback(path string, bindMounts map[string]string, callback func() error) error {
|
||||
chroot := NewChroot(path)
|
||||
return chroot.RunCallback(callback)
|
||||
}
|
||||
|
||||
// Prepare will mount the defaultMounts as bind mounts, to be ready when we run chroot.
|
||||
func (c *Chroot) Prepare() error {
|
||||
var err error
|
||||
|
||||
if len(c.activeMounts) > 0 {
|
||||
return errors.New("there are already active mountpoints for this instance")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for _, mnt := range c.defaultMounts {
|
||||
mountPoint := filepath.Join(c.path, mnt)
|
||||
err = CreateIfNotExists(mountPoint)
|
||||
if err != nil {
|
||||
Log.Err(err).Str("what", mountPoint).Msg("Creating dir")
|
||||
return err
|
||||
}
|
||||
err = syscall.Mount(mnt, mountPoint, "bind", syscall.MS_BIND|syscall.MS_REC, "")
|
||||
if err != nil {
|
||||
Log.Err(err).Str("where", mountPoint).Str("what", mnt).Msg("Mounting chroot bind")
|
||||
return err
|
||||
}
|
||||
c.activeMounts = append(c.activeMounts, mountPoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close will unmount all active mounts created in Prepare on reverse order.
|
||||
func (c *Chroot) Close() error {
|
||||
failures := []string{}
|
||||
for len(c.activeMounts) > 0 {
|
||||
curr := c.activeMounts[len(c.activeMounts)-1]
|
||||
Log.Debug().Str("what", curr).Msg("Unmounting from chroot")
|
||||
c.activeMounts = c.activeMounts[:len(c.activeMounts)-1]
|
||||
err := syscall.Unmount(curr, 0)
|
||||
if err != nil {
|
||||
Log.Err(err).Str("what", curr).Msg("Error unmounting")
|
||||
failures = append(failures, curr)
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
c.activeMounts = failures
|
||||
return fmt.Errorf("failed closing chroot environment. Unmount failures: %v", failures)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunCallback runs the given callback in a chroot environment.
|
||||
func (c *Chroot) RunCallback(callback func() error) (err error) {
|
||||
var currentPath string
|
||||
var oldRootF *os.File
|
||||
|
||||
// Store current path
|
||||
currentPath, err = os.Getwd()
|
||||
if err != nil {
|
||||
Log.Err(err).Msg("Failed to get current path")
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
tmpErr := os.Chdir(currentPath)
|
||||
if err == nil && tmpErr != nil {
|
||||
err = tmpErr
|
||||
}
|
||||
}()
|
||||
|
||||
// Store current root
|
||||
oldRootF, err = os.Open("/")
|
||||
if err != nil {
|
||||
Log.Err(err).Msg("Can't open current root")
|
||||
return err
|
||||
}
|
||||
defer oldRootF.Close()
|
||||
|
||||
if len(c.activeMounts) == 0 {
|
||||
err = c.Prepare()
|
||||
if err != nil {
|
||||
Log.Err(err).Msg("Can't mount default mounts")
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
tmpErr := c.Close()
|
||||
if err == nil {
|
||||
err = tmpErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Change to new dir before running chroot!
|
||||
err = syscall.Chdir(c.path)
|
||||
if err != nil {
|
||||
Log.Err(err).Str("path", c.path).Msg("Can't chdir")
|
||||
return err
|
||||
}
|
||||
|
||||
err = syscall.Chroot(c.path)
|
||||
if err != nil {
|
||||
Log.Err(err).Str("path", c.path).Msg("Can't chroot")
|
||||
return err
|
||||
}
|
||||
|
||||
// Restore to old root
|
||||
defer func() {
|
||||
tmpErr := oldRootF.Chdir()
|
||||
if tmpErr != nil {
|
||||
Log.Err(tmpErr).Str("path", oldRootF.Name()).Msg("Can't change to old root dir")
|
||||
if err == nil {
|
||||
err = tmpErr
|
||||
}
|
||||
} else {
|
||||
tmpErr = syscall.Chroot(".")
|
||||
if tmpErr != nil {
|
||||
Log.Err(tmpErr).Str("path", oldRootF.Name()).Msg("Can't chroot back to old root")
|
||||
if err == nil {
|
||||
err = tmpErr
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return callback()
|
||||
}
|
||||
|
||||
// Run executes a command inside a chroot.
|
||||
func (c *Chroot) Run(command string) (string, error) {
|
||||
var err error
|
||||
var out []byte
|
||||
callback := func() error {
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
cmd.Env = os.Environ()
|
||||
out, err = cmd.CombinedOutput()
|
||||
return err
|
||||
}
|
||||
err = c.RunCallback(callback)
|
||||
if err != nil {
|
||||
Log.Err(err).Str("cmd", command).Msg("Cant run command on chroot")
|
||||
}
|
||||
return string(out), err
|
||||
}
|
@@ -182,7 +182,6 @@ func CommandWithPath(c string) (string, error) {
|
||||
pathAppend = fmt.Sprintf("%s:%s", pathAppend, splitted[1])
|
||||
}
|
||||
}
|
||||
Log.Debug().Str("content", pathAppend).Msg("PATH")
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("PATH=%s", pathAppend))
|
||||
o, err := cmd.CombinedOutput()
|
||||
return string(o), err
|
||||
|
@@ -3,7 +3,9 @@ package utils
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kairos-io/immucore/internal/constants"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
@@ -16,7 +18,8 @@ func CloseLogFiles() {
|
||||
|
||||
func SetLogger() {
|
||||
var loggers []io.Writer
|
||||
logFile, err := os.Create("/run/immucore.log")
|
||||
_ = os.MkdirAll(constants.LogDir, os.ModeDir|os.ModePerm)
|
||||
logFile, err := os.Create(filepath.Join(constants.LogDir, "immucore.log"))
|
||||
if err == nil {
|
||||
loggers = append(loggers, zerolog.ConsoleWriter{Out: logFile})
|
||||
}
|
||||
|
@@ -169,9 +169,8 @@ func Fsck(device string) error {
|
||||
cmd := strings.Join(args, " ")
|
||||
Log.Debug().Str("cmd", cmd).Msg("fsck command")
|
||||
out, e := CommandWithPath(cmd)
|
||||
Log.Debug().Str("output", out).Msg("fsck output")
|
||||
if e != nil {
|
||||
Log.Warn().Str("error", e.Error()).Str("what", device).Msg("fsck")
|
||||
Log.Debug().Err(e).Str("out", out).Str("what", device).Msg("fsck")
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
Reference in New Issue
Block a user