mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-17 18:41:16 +02:00
fix: don't touch any partitions on upgrade with --preserve
This fixes a case of upgrade from 0.9.0-alpha.4 to 0.9.0-beta.0. With introduced proper partition alignment and physical block size != 512, partitions before ephemeral will be moved around a bit (due to the alignment), and `STATE` partition size might change a bit. If encryption is enabled, contents are preserved as raw bytes, so partition size should be exactly same during restore. Drop code (mostly tests) which handled 0.6 to 0.7 upgrades. On upgrade with preserve don't touch any partitions, at least for 0.8 -> 0.9 layout hasn't changed. Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
This commit is contained in:
parent
891f90fee9
commit
3c5bfbb473
@ -14,10 +14,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/util"
|
||||
"github.com/talos-systems/go-retry/retry"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
|
||||
@ -140,15 +138,16 @@ func NewManifest(label string, sequence runtime.Sequence, bootPartitionFound boo
|
||||
|
||||
ephemeralTarget := EphemeralTarget(opts.Disk, NoFilesystem)
|
||||
|
||||
if opts.Force {
|
||||
ephemeralTarget.Force = true
|
||||
} else {
|
||||
ephemeralTarget.Force = false
|
||||
ephemeralTarget.Skip = true
|
||||
stateTarget.Size = 0 // expand previous partition to cover whatever space is available
|
||||
targets := []*Target{efiTarget, biosTarget, bootTarget, metaTarget, stateTarget, ephemeralTarget}
|
||||
|
||||
if !opts.Force {
|
||||
for _, target := range targets {
|
||||
target.Force = false
|
||||
target.Skip = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, target := range []*Target{efiTarget, biosTarget, bootTarget, metaTarget, stateTarget, ephemeralTarget} {
|
||||
for _, target := range targets {
|
||||
if target == nil {
|
||||
continue
|
||||
}
|
||||
@ -373,6 +372,10 @@ func (m *Manifest) preserveContents(device Device, targets []*Target) (err error
|
||||
anyPreserveContents := false
|
||||
|
||||
for _, target := range targets {
|
||||
if target.Skip {
|
||||
continue
|
||||
}
|
||||
|
||||
if target.PreserveContents {
|
||||
anyPreserveContents = true
|
||||
|
||||
@ -405,6 +408,10 @@ func (m *Manifest) preserveContents(device Device, targets []*Target) (err error
|
||||
}
|
||||
|
||||
for _, target := range targets {
|
||||
if target.Skip {
|
||||
continue
|
||||
}
|
||||
|
||||
if !target.PreserveContents {
|
||||
continue
|
||||
}
|
||||
@ -500,44 +507,3 @@ func (m *Manifest) zeroDevice(device Device) (err error) {
|
||||
|
||||
return bd.Close()
|
||||
}
|
||||
|
||||
// Partition creates a new partition on the specified device.
|
||||
func (t *Target) Partition(pt *gpt.GPT, pos int, bd *blockdevice.BlockDevice) (err error) {
|
||||
if t.Skip {
|
||||
part := pt.Partitions().FindByName(t.Label)
|
||||
if part != nil {
|
||||
log.Printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("partitioning %s - %s %q\n", t.Device, t.Label, humanize.Bytes(t.Size))
|
||||
|
||||
opts := []gpt.PartitionOption{
|
||||
gpt.WithPartitionType(t.PartitionType),
|
||||
gpt.WithPartitionName(t.Label),
|
||||
}
|
||||
|
||||
if t.Size == 0 {
|
||||
opts = append(opts, gpt.WithMaximumSize(true))
|
||||
}
|
||||
|
||||
if t.LegacyBIOSBootable {
|
||||
opts = append(opts, gpt.WithLegacyBIOSBootableAttribute(true))
|
||||
}
|
||||
|
||||
part, err := pt.InsertAt(pos, t.Size, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.PartitionName, err = util.PartPath(t.Device, int(part.Number))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("created %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -16,15 +16,12 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/loopback"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/util"
|
||||
|
||||
"github.com/talos-systems/talos/cmd/installer/pkg/install"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/partition"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
"github.com/talos-systems/talos/pkg/makefs"
|
||||
)
|
||||
|
||||
// Some tests in this package cannot be run under buildkit, as buildkit doesn't propagate partition devices
|
||||
@ -45,11 +42,6 @@ const (
|
||||
gptReserved = 67
|
||||
)
|
||||
|
||||
const (
|
||||
legacyBootSize = 512 * partition.MiB
|
||||
legacyEphemeralSize = diskSize - legacyBootSize - gptReserved*lbaSize
|
||||
)
|
||||
|
||||
func TestManifestSuite(t *testing.T) {
|
||||
suite.Run(t, new(manifestSuite))
|
||||
}
|
||||
@ -99,7 +91,7 @@ func (suite *manifestSuite) skipIfNotRoot() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) verifyBlockdevice(manifest *install.Manifest, current, next string, verifyConfigPersistence, verifyEphemeralPersistence, upgradeFromLegacy bool) {
|
||||
func (suite *manifestSuite) verifyBlockdevice(manifest *install.Manifest, current, next string, verifyConfigPersistence, verifyEphemeralPersistence bool) {
|
||||
bd, err := blockdevice.Open(suite.loopbackDevice.Name())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@ -141,22 +133,14 @@ func (suite *manifestSuite) verifyBlockdevice(manifest *install.Manifest, curren
|
||||
suite.Assert().Equal(constants.StatePartitionLabel, part.Name)
|
||||
suite.Assert().EqualValues(0, part.Attributes)
|
||||
|
||||
if !upgradeFromLegacy {
|
||||
suite.Assert().EqualValues(partition.StateSize/lbaSize, part.Length())
|
||||
} else {
|
||||
suite.Assert().EqualValues((diskSize-legacyEphemeralSize-partition.EFISize-partition.BIOSGrubSize-partition.BootSize-partition.MetaSize)/lbaSize-gptReserved, part.Length())
|
||||
}
|
||||
suite.Assert().EqualValues(partition.StateSize/lbaSize, part.Length())
|
||||
|
||||
part = table.Partitions().Items()[5]
|
||||
suite.Assert().Equal(partition.LinuxFilesystemData, strings.ToUpper(part.Type.String()))
|
||||
suite.Assert().Equal(constants.EphemeralPartitionLabel, part.Name)
|
||||
suite.Assert().EqualValues(0, part.Attributes)
|
||||
|
||||
if !upgradeFromLegacy {
|
||||
suite.Assert().EqualValues((diskSize-partition.EFISize-partition.BIOSGrubSize-partition.BootSize-partition.MetaSize-partition.StateSize)/lbaSize-gptReserved, part.Length())
|
||||
} else {
|
||||
suite.Assert().EqualValues(legacyEphemeralSize/lbaSize, part.Length())
|
||||
}
|
||||
suite.Assert().EqualValues((diskSize-partition.EFISize-partition.BIOSGrubSize-partition.BootSize-partition.MetaSize-partition.StateSize)/lbaSize-gptReserved, part.Length())
|
||||
|
||||
suite.Assert().NoError(bd.Close())
|
||||
|
||||
@ -251,7 +235,7 @@ func (suite *manifestSuite) TestExecuteManifestClean() {
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false, false)
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false)
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) TestExecuteManifestForce() {
|
||||
@ -267,7 +251,7 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false, false)
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false)
|
||||
|
||||
// reinstall
|
||||
|
||||
@ -282,7 +266,7 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "A", "B", true, false, false)
|
||||
suite.verifyBlockdevice(manifest, "A", "B", true, false)
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) TestExecuteManifestPreserve() {
|
||||
@ -298,7 +282,7 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false, false)
|
||||
suite.verifyBlockdevice(manifest, "", "A", false, false)
|
||||
|
||||
// reinstall
|
||||
|
||||
@ -312,47 +296,7 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "A", "B", true, true, false)
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) TestExecuteManifestLegacyForce() {
|
||||
suite.skipUnderBuildkit()
|
||||
|
||||
suite.createTalosLegacyLayout()
|
||||
|
||||
// upgrade with force
|
||||
|
||||
manifest, err := install.NewManifest("A", runtime.SequenceUpgrade, true, &install.Options{
|
||||
Disk: suite.loopbackDevice.Name(),
|
||||
Bootloader: true,
|
||||
Force: true,
|
||||
Board: constants.BoardNone,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "", "", true, false, false)
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) TestExecuteManifestLegacyPreserve() {
|
||||
suite.skipUnderBuildkit()
|
||||
|
||||
suite.createTalosLegacyLayout()
|
||||
|
||||
// upgrade with preserve
|
||||
|
||||
manifest, err := install.NewManifest("A", runtime.SequenceUpgrade, true, &install.Options{
|
||||
Disk: suite.loopbackDevice.Name(),
|
||||
Bootloader: true,
|
||||
Force: false,
|
||||
Board: constants.BoardNone,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Assert().NoError(manifest.Execute())
|
||||
|
||||
suite.verifyBlockdevice(manifest, "", "", true, true, true)
|
||||
suite.verifyBlockdevice(manifest, "A", "B", true, true)
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) TestTargetInstall() {
|
||||
@ -389,65 +333,3 @@ func (suite *manifestSuite) TestTargetInstall() {
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *manifestSuite) createTalosLegacyLayout() {
|
||||
bd, err := blockdevice.Open(suite.loopbackDevice.Name())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
defer bd.Close() //nolint:errcheck
|
||||
|
||||
// create Talos 0.6 partitions
|
||||
table, err := gpt.New(bd.Device())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
partBoot, err := table.Add(512*partition.MiB,
|
||||
gpt.WithLegacyBIOSBootableAttribute(true),
|
||||
gpt.WithPartitionName(constants.LegacyBootPartitionLabel),
|
||||
gpt.WithPartitionType("28732AC1-1FF8-D211-BA4B-00A0C93EC93B"),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
partEphemeral, err := table.Add(0,
|
||||
gpt.WithPartitionName(constants.EphemeralPartitionLabel),
|
||||
gpt.WithPartitionType("0FC63DAF-8483-4772-8E79-3D69D8477DE4"),
|
||||
gpt.WithMaximumSize(true),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(table.Write())
|
||||
|
||||
suite.Require().NoError(bd.Close())
|
||||
|
||||
// format partitions
|
||||
partBootPath, err := util.PartPath(suite.loopbackDevice.Name(), int(partBoot.Number))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(makefs.VFAT(partBootPath))
|
||||
|
||||
partEphemeralPath, err := util.PartPath(suite.loopbackDevice.Name(), int(partEphemeral.Number))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(makefs.XFS(partEphemeralPath, makefs.WithLabel(constants.EphemeralPartitionLabel)))
|
||||
|
||||
// mount partitions temporarily and fill with data
|
||||
tempDir, err := ioutil.TempDir("", "talos")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
defer func() {
|
||||
suite.Assert().NoError(os.RemoveAll(tempDir))
|
||||
}()
|
||||
|
||||
mountpoints := mount.NewMountPoints()
|
||||
mountpoints.Set(constants.LegacyBootPartitionLabel, mount.NewMountPoint(partBootPath, filepath.Join(tempDir, "boot"), partition.FilesystemTypeVFAT, 0, ""))
|
||||
mountpoints.Set(constants.EphemeralPartitionLabel, mount.NewMountPoint(partEphemeralPath, filepath.Join(tempDir, "var"), partition.FilesystemTypeXFS, 0, ""))
|
||||
|
||||
err = mount.Mount(mountpoints)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
defer func() {
|
||||
suite.Assert().NoError(mount.Unmount(mountpoints))
|
||||
}()
|
||||
|
||||
suite.Assert().NoError(ioutil.WriteFile(filepath.Join(tempDir, "boot", "config.yaml"), []byte("#!yaml"), 0o600))
|
||||
suite.Assert().NoError(ioutil.WriteFile(filepath.Join(tempDir, "var", "content"), []byte("data"), 0o600))
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/util"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -161,7 +163,7 @@ func (t *Target) Locate(pt *gpt.GPT) (*gpt.Partition, error) {
|
||||
if part.Name == t.Label {
|
||||
var err error
|
||||
|
||||
t.PartitionName, err = util.PartPath(t.Device, int(part.Number))
|
||||
t.PartitionName, err = part.Path()
|
||||
if err != nil {
|
||||
return part, err
|
||||
}
|
||||
@ -173,6 +175,52 @@ func (t *Target) Locate(pt *gpt.GPT) (*gpt.Partition, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Partition creates a new partition on the specified device.
|
||||
func (t *Target) Partition(pt *gpt.GPT, pos int, bd *blockdevice.BlockDevice) (err error) {
|
||||
if t.Skip {
|
||||
part := pt.Partitions().FindByName(t.Label)
|
||||
if part != nil {
|
||||
log.Printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
|
||||
|
||||
t.PartitionName, err = part.Path()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("partitioning %s - %s %q\n", t.Device, t.Label, humanize.Bytes(t.Size))
|
||||
|
||||
opts := []gpt.PartitionOption{
|
||||
gpt.WithPartitionType(t.PartitionType),
|
||||
gpt.WithPartitionName(t.Label),
|
||||
}
|
||||
|
||||
if t.Size == 0 {
|
||||
opts = append(opts, gpt.WithMaximumSize(true))
|
||||
}
|
||||
|
||||
if t.LegacyBIOSBootable {
|
||||
opts = append(opts, gpt.WithLegacyBIOSBootableAttribute(true))
|
||||
}
|
||||
|
||||
part, err := pt.InsertAt(pos, t.Size, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.PartitionName, err = part.Path()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("created %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Format creates a filesystem on the device/partition.
|
||||
func (t *Target) Format() error {
|
||||
if t.Skip {
|
||||
|
@ -106,9 +106,6 @@ const (
|
||||
// the boot path.
|
||||
BootMountPoint = "/boot"
|
||||
|
||||
// LegacyBootPartitionLabel is the label of the boot partition in older versions of Talos.
|
||||
LegacyBootPartitionLabel = "ESP"
|
||||
|
||||
// EphemeralPartitionLabel is the label of the partition to use for
|
||||
// mounting at the data path.
|
||||
EphemeralPartitionLabel = "EPHEMERAL"
|
||||
|
Loading…
x
Reference in New Issue
Block a user