From 3c5bfbb4736c86f493a665dbfe63a6e2d20acb3d Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 15 Mar 2021 17:29:27 +0300 Subject: [PATCH] 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 --- cmd/installer/pkg/install/manifest.go | 66 +++------- cmd/installer/pkg/install/manifest_test.go | 134 ++------------------- cmd/installer/pkg/install/target.go | 50 +++++++- pkg/machinery/constants/constants.go | 3 - 4 files changed, 73 insertions(+), 180 deletions(-) diff --git a/cmd/installer/pkg/install/manifest.go b/cmd/installer/pkg/install/manifest.go index d402e11ca..afa152cee 100644 --- a/cmd/installer/pkg/install/manifest.go +++ b/cmd/installer/pkg/install/manifest.go @@ -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 -} diff --git a/cmd/installer/pkg/install/manifest_test.go b/cmd/installer/pkg/install/manifest_test.go index 050d6d2e0..76855e5be 100644 --- a/cmd/installer/pkg/install/manifest_test.go +++ b/cmd/installer/pkg/install/manifest_test.go @@ -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)) -} diff --git a/cmd/installer/pkg/install/target.go b/cmd/installer/pkg/install/target.go index ea7b1a6e2..14793b75a 100644 --- a/cmd/installer/pkg/install/target.go +++ b/cmd/installer/pkg/install/target.go @@ -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 { diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index 9442bc4eb..b94236f45 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -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"