Skip to content

Commit

Permalink
fix: add a check for overlay mounts in installer pre-flight checks
Browse files Browse the repository at this point in the history
Overlay mount in `mountinfo` don't show up as mounts for any particular
block device, so the existing check doesn't catch them.

This was discovered as our current master can't upgrade because of
overlay mount for `/opt` and `apid` image in `/opt/apid` (which will be
fixed in a separate PR).

Without the check, installer fails on resetting partition table for the
disk effectively wiping the node (`device or resource busy` error).

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
  • Loading branch information
smira authored and talos-bot committed Apr 5, 2021
1 parent df8649c commit bd5ae1e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
22 changes: 22 additions & 0 deletions cmd/installer/pkg/install/manifest.go
Expand Up @@ -39,6 +39,8 @@ type Device struct {

ResetPartitionTable bool
Zero bool

SkipOverlayMountsCheck bool
}

// NewManifest initializes and returns a Manifest.
Expand Down Expand Up @@ -95,6 +97,8 @@ func NewManifest(label string, sequence runtime.Sequence, bootPartitionFound boo

ResetPartitionTable: opts.Force,
Zero: opts.Zero,

SkipOverlayMountsCheck: sequence == runtime.SequenceNoop,
}

// Initialize any slices we need. Note that a boot partition is not
Expand Down Expand Up @@ -170,6 +174,8 @@ func (m *Manifest) Execute() (err error) {
}

// checkMounts verifies that no active mounts in any mount namespace exist for the device.
//
//nolint:gocyclo
func (m *Manifest) checkMounts(device Device) error {
matches, err := filepath.Glob("/proc/*/mountinfo")
if err != nil {
Expand Down Expand Up @@ -198,6 +204,22 @@ func (m *Manifest) checkMounts(device Device) error {
continue
}

if !device.SkipOverlayMountsCheck && fields[len(fields)-2] == "overlay" {
// parsing options (last column) in the overlay mount line which looks like:
// 163 70 0:52 /apid / ro,relatime - overlay overlay rw,lowerdir=/opt,upperdir=/var/system/overlays/opt-diff,workdir=/var/system/overlays/opt-workdir

options := strings.Split(fields[len(fields)-1], ",")

for _, option := range options {
parts := strings.SplitN(option, "=", 2)
if len(parts) == 2 {
if strings.HasPrefix(parts[1], "/var/") {
return fmt.Errorf("found overlay mount in %q: %s", path, scanner.Text())
}
}
}
}

if fields[len(fields)-2] == device.Device {
return fmt.Errorf("found active mount in %q for %q: %s", path, device.Device, scanner.Text())
}
Expand Down
25 changes: 25 additions & 0 deletions cmd/installer/pkg/install/manifest_test.go
Expand Up @@ -233,6 +233,11 @@ func (suite *manifestSuite) TestExecuteManifestClean() {
})
suite.Require().NoError(err)

// in the tests overlay mounts should be ignored
dev := manifest.Devices[suite.loopbackDevice.Name()]
dev.SkipOverlayMountsCheck = true
manifest.Devices[suite.loopbackDevice.Name()] = dev

suite.Assert().NoError(manifest.Execute())

suite.verifyBlockdevice(manifest, "", "A", false, false)
Expand All @@ -249,6 +254,11 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
})
suite.Require().NoError(err)

// in the tests overlay mounts should be ignored
dev := manifest.Devices[suite.loopbackDevice.Name()]
dev.SkipOverlayMountsCheck = true
manifest.Devices[suite.loopbackDevice.Name()] = dev

suite.Assert().NoError(manifest.Execute())

suite.verifyBlockdevice(manifest, "", "A", false, false)
Expand All @@ -264,6 +274,11 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
})
suite.Require().NoError(err)

// in the tests overlay mounts should be ignored
dev = manifest.Devices[suite.loopbackDevice.Name()]
dev.SkipOverlayMountsCheck = true
manifest.Devices[suite.loopbackDevice.Name()] = dev

suite.Assert().NoError(manifest.Execute())

suite.verifyBlockdevice(manifest, "A", "B", true, false)
Expand All @@ -280,6 +295,11 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
})
suite.Require().NoError(err)

// in the tests overlay mounts should be ignored
dev := manifest.Devices[suite.loopbackDevice.Name()]
dev.SkipOverlayMountsCheck = true
manifest.Devices[suite.loopbackDevice.Name()] = dev

suite.Assert().NoError(manifest.Execute())

suite.verifyBlockdevice(manifest, "", "A", false, false)
Expand All @@ -294,6 +314,11 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
})
suite.Require().NoError(err)

// in the tests overlay mounts should be ignored
dev = manifest.Devices[suite.loopbackDevice.Name()]
dev.SkipOverlayMountsCheck = true
manifest.Devices[suite.loopbackDevice.Name()] = dev

suite.Assert().NoError(manifest.Execute())

suite.verifyBlockdevice(manifest, "A", "B", true, true)
Expand Down
Expand Up @@ -808,8 +808,9 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
}

m.Devices[disk.Device()] = installer.Device{
Device: disk.Device(),
ResetPartitionTable: true,
Device: disk.Device(),
ResetPartitionTable: true,
SkipOverlayMountsCheck: true,
}

for _, part := range disk.Partitions() {
Expand Down

0 comments on commit bd5ae1e

Please sign in to comment.