fix(machined): Clean up installation process
This also includes a fix for #955 which had the unintended side effect of breaking image creation ( since it would attempt to grow the filesystem always ). The refactor standardizes around looking for the DATA and ESP labels to discover any existing installations/filesystems. If none are found, an installation will proceed -- for both image creation and bare metal. During bootup, the DATA partition will always attempt to expand/grow. This also introduces a new phase to verify the installation through the existance of /boot/installed ( migrated from install stage ). Signed-off-by: Brad Beam <brad.beam@talos-systems.com>
This commit is contained in:
parent
3383e72d37
commit
da1f73249f
@ -25,6 +25,7 @@ policies:
|
||||
- init
|
||||
- initramfs
|
||||
- kernel
|
||||
- machined
|
||||
- proxyd
|
||||
- osctl
|
||||
- osd
|
||||
|
39
internal/app/machined/internal/phase/rootfs/check_install.go
Normal file
39
internal/app/machined/internal/phase/rootfs/check_install.go
Normal file
@ -0,0 +1,39 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package rootfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// CheckInstall represents the CheckInstall task.
|
||||
type CheckInstall struct{}
|
||||
|
||||
// NewCheckInstallTask initializes and returns a CheckInstall task.
|
||||
func NewCheckInstallTask() phase.Task {
|
||||
return &CheckInstall{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *CheckInstall) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.standard
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *CheckInstall) standard(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
_, err = os.Stat(filepath.Join(constants.BootMountPoint, "installed"))
|
||||
return err
|
||||
}
|
@ -13,6 +13,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/installer"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager/owned"
|
||||
"github.com/talos-systems/talos/pkg/blockdevice/probe"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
@ -88,9 +91,27 @@ func (b *BareMetal) Initialize(data *userdata.UserData) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
// Attempt to discover a previous installation
|
||||
// An err case should only happen if no partitions
|
||||
// with matching labels were found
|
||||
var mountpoints *mount.Points
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
// No previous installation was found, attempt an install
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
}
|
||||
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m := manager.NewManager(mountpoints)
|
||||
if err = m.MountAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -10,6 +10,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/installer"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager/owned"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
@ -49,9 +52,27 @@ func (p *Packet) Initialize(data *userdata.UserData) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
// Attempt to discover a previous installation
|
||||
// An err case should only happen if no partitions
|
||||
// with matching labels were found
|
||||
var mountpoints *mount.Points
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
// No previous installation was found, attempt an install
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
}
|
||||
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m := manager.NewManager(mountpoints)
|
||||
if err = m.MountAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -77,6 +77,10 @@ func run() (err error) {
|
||||
"platform tasks",
|
||||
platform.NewPlatformTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"installation verification",
|
||||
rootfs.NewCheckInstallTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"overlay mounts",
|
||||
rootfs.NewMountOverlayTask(),
|
||||
|
@ -132,7 +132,7 @@ func WriteSyslinuxCfg(base, path string, syslinuxcfg *Cfg) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("writing syslinux.cfg to disk")
|
||||
log.Printf("writing %s to disk", path)
|
||||
if err = ioutil.WriteFile(path, wr.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package installer
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
@ -19,7 +18,6 @@ import (
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager/owned"
|
||||
"github.com/talos-systems/talos/pkg/blockdevice/probe"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"github.com/talos-systems/talos/pkg/version"
|
||||
@ -72,34 +70,12 @@ func (i *Installer) Install() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.data.Install.Boot != nil {
|
||||
var ok bool
|
||||
if ok, err = exists(i.data.Install.Boot.InstallDevice.Device); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok {
|
||||
log.Println("found existing installation")
|
||||
var mountpoints *mount.Points
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := manager.NewManager(mountpoints)
|
||||
if err = m.MountAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = VerifyBootDevice(i.data); err != nil {
|
||||
return errors.Wrap(err, "failed to prepare boot device")
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the target device(s) can satisify the requested options.
|
||||
|
||||
if err = VerifyBootDevice(i.data); err != nil {
|
||||
return errors.Wrap(err, "failed to prepare boot device")
|
||||
}
|
||||
|
||||
if err = VerifyDataDevice(i.data); err != nil {
|
||||
return errors.Wrap(err, "failed to prepare data device")
|
||||
}
|
||||
@ -118,16 +94,18 @@ func (i *Installer) Install() (err error) {
|
||||
|
||||
// Mount the partitions.
|
||||
|
||||
var mountpoints *mount.Points
|
||||
if i.data.Install.Boot != nil {
|
||||
mountpoints, err = owned.MountPointsForDevice(i.data.Install.Boot.InstallDevice.Device)
|
||||
mountpoints := mount.NewMountPoints()
|
||||
// look for mountpoints across all target devices
|
||||
for dev := range i.manifest.Targets {
|
||||
var mp *mount.Points
|
||||
mp, err = owned.MountPointsForDevice(dev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
iter := mp.Iter()
|
||||
for iter.Next() {
|
||||
mountpoints.Set(iter.Key(), iter.Value())
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,6 +114,9 @@ func (i *Installer) Install() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
defer m.UnmountAll()
|
||||
|
||||
// Install the assets.
|
||||
|
||||
for _, targets := range i.manifest.Targets {
|
||||
@ -216,37 +197,3 @@ func wipe(manifest *manifest.Manifest) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func exists(devpath string) (bool, error) {
|
||||
var (
|
||||
err error
|
||||
dev *probe.ProbedBlockDevice
|
||||
)
|
||||
|
||||
if dev, err = probe.DevForFileSystemLabel(devpath, constants.BootPartitionLabel); err == nil {
|
||||
// nolint: errcheck
|
||||
defer dev.Close()
|
||||
if dev.SuperBlock != nil {
|
||||
mountpoint := mount.NewMountPoint(dev.Path, "/tmp", dev.SuperBlock.Type(), 0, "")
|
||||
if err = mountpoint.Mount(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
if err = mountpoint.Unmount(); err != nil {
|
||||
log.Printf("WARNING: failed to unmount %s from /tmp", dev.Path)
|
||||
}
|
||||
}()
|
||||
_, err = os.Stat(filepath.Join("tmp", "installed"))
|
||||
switch {
|
||||
case err == nil:
|
||||
return true, nil
|
||||
case os.IsNotExist(err):
|
||||
return false, nil
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
@ -205,10 +205,11 @@ func (t *Target) Partition(bd *blockdevice.BlockDevice) (err error) {
|
||||
|
||||
// Format creates a filesystem on the device/partition.
|
||||
func (t *Target) Format() error {
|
||||
log.Printf("formatting partition %s - %s\n", t.PartitionName, t.Label)
|
||||
if t.Label == constants.BootPartitionLabel {
|
||||
log.Printf("formatting partition %s - %s as %s\n", t.PartitionName, t.Label, "fat")
|
||||
return vfat.MakeFS(t.PartitionName, vfat.WithLabel(t.Label))
|
||||
}
|
||||
log.Printf("formatting partition %s - %s as %s\n", t.PartitionName, t.Label, "xfs")
|
||||
opts := []xfs.Option{xfs.WithForce(t.Force)}
|
||||
if t.Label != "" {
|
||||
opts = append(opts, xfs.WithLabel(t.Label))
|
||||
|
@ -15,15 +15,17 @@ import (
|
||||
)
|
||||
|
||||
// MountPointsForDevice returns the mountpoints required to boot the system.
|
||||
// This function is called exclusively during installations ( both image
|
||||
// creation and bare metall installs ). This is why we want to look up
|
||||
// device by specified disk as well as why we don't want to grow any
|
||||
// filesystems.
|
||||
func MountPointsForDevice(devpath string) (mountpoints *mount.Points, err error) {
|
||||
mountpoints = mount.NewMountPoints()
|
||||
for _, name := range []string{constants.DataPartitionLabel, constants.BootPartitionLabel} {
|
||||
opts := []mount.Option{}
|
||||
var target string
|
||||
switch name {
|
||||
case constants.DataPartitionLabel:
|
||||
target = constants.DataMountPoint
|
||||
opts = append(opts, mount.WithResize(true))
|
||||
case constants.BootPartitionLabel:
|
||||
target = constants.BootMountPoint
|
||||
}
|
||||
@ -37,7 +39,7 @@ func MountPointsForDevice(devpath string) (mountpoints *mount.Points, err error)
|
||||
}
|
||||
return nil, errors.Errorf("probe device for filesystem %s: %v", name, err)
|
||||
}
|
||||
mountpoint := mount.NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "", opts...)
|
||||
mountpoint := mount.NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "")
|
||||
mountpoints.Set(name, mountpoint)
|
||||
}
|
||||
|
||||
@ -45,6 +47,8 @@ func MountPointsForDevice(devpath string) (mountpoints *mount.Points, err error)
|
||||
}
|
||||
|
||||
// MountPointsFromLabels returns the mountpoints required to boot the system.
|
||||
// Since this function is called exclusively during boot time, this is when
|
||||
// we want to grow the data filesystem.
|
||||
func MountPointsFromLabels() (mountpoints *mount.Points, err error) {
|
||||
mountpoints = mount.NewMountPoints()
|
||||
for _, name := range []string{constants.DataPartitionLabel, constants.BootPartitionLabel} {
|
||||
@ -60,13 +64,14 @@ func MountPointsFromLabels() (mountpoints *mount.Points, err error) {
|
||||
|
||||
var dev *probe.ProbedBlockDevice
|
||||
if dev, err = probe.GetDevWithFileSystemLabel(name); err != nil {
|
||||
// A bootloader is not always required.
|
||||
if name == constants.BootPartitionLabel {
|
||||
// A bootloader is not always required.
|
||||
log.Println("WARNING: no ESP partition was found")
|
||||
continue
|
||||
}
|
||||
return nil, errors.Errorf("find device with label %s: %v", name, err)
|
||||
}
|
||||
|
||||
mountpoint := mount.NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "", opts...)
|
||||
mountpoints.Set(name, mountpoint)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user