immucore/pkg/op/mount.go
2024-03-20 11:48:51 +01:00

91 lines
2.6 KiB
Go

package op
import (
"context"
"errors"
"fmt"
"time"
"github.com/containerd/containerd/mount"
"github.com/kairos-io/immucore/internal/constants"
internalUtils "github.com/kairos-io/immucore/internal/utils"
"github.com/kairos-io/immucore/pkg/schema"
"github.com/rs/zerolog"
)
// MountOPWithFstab creates and executes a mount operation.
// returns the fstab entries created and an error if any.
func MountOPWithFstab(what, where, t string, options []string, timeout time.Duration) (schema.FsTabs, error) {
var fstab schema.FsTabs
l := internalUtils.Log.With().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Logger()
// Not sure why this defaults to debuglevel when creating a sublogger, so make sure we set it properly
debug := len(internalUtils.ReadCMDLineArg("rd.immucore.debug")) > 0
if debug {
l = l.Level(zerolog.DebugLevel)
}
c := context.Background()
cc := time.After(timeout)
for {
select {
default:
// check fs type just-in-time before running the OP
if t != "tmpfs" {
fsType := internalUtils.DiskFSType(what)
// If not empty and it does not match
if fsType != "" && t != fsType {
t = fsType
}
}
err := internalUtils.CreateIfNotExists(where)
if err != nil {
l.Err(err).Msg("Creating dir")
continue
}
time.Sleep(1 * time.Second)
mountPoint := mount.Mount{
Type: t,
Source: what,
Options: options,
}
tmpFstab := internalUtils.MountToFstab(mountPoint)
tmpFstab.File = internalUtils.CleanSysrootForFstab(where)
op := MountOperation{
MountOption: mountPoint,
FstabEntry: *tmpFstab,
Target: where,
PrepareCallback: func() error {
_ = internalUtils.Fsck(what)
return nil
},
}
err = op.Run()
// If no error on mounting or error is already mounted, as that affects the sysroot
// for some reason it reports that its already mounted (systemd is mounting it behind our back!).
if err == nil || err != nil && errors.Is(err, constants.ErrAlreadyMounted) {
fstab = append(fstab, tmpFstab)
} else {
l.Debug().Err(err).Msg("Mount not added to fstab")
}
// only continue the loop if it's an error and not an already mounted error
if err != nil && !errors.Is(err, constants.ErrAlreadyMounted) {
l.Warn().Err(err).Send()
continue
}
l.Info().Msg("mount done")
return fstab, nil
case <-c.Done():
e := fmt.Errorf("context canceled")
l.Err(e).Msg("mount canceled")
return fstab, e
case <-cc:
e := fmt.Errorf("timeout exhausted")
l.Err(e).Msg("Mount timeout")
return fstab, e
}
}
}