From a83af037305337b37afc59977575a0e66e757793 Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Thu, 21 Jan 2021 20:49:00 +0300 Subject: [PATCH] refactor: update go-blockdevice and restructure disk interaction code This refactoring is required to simplify the work to be done to support disk encryption. Tried to minimize amount of queries done by `blockdevice` `probe` methods. Instead, where we have `runtime.Runtime` we get all required blockdevices there from blockdevice cache stored in `State().Machine().Disk()`. This opens a way to store encryption settings in the `Partition` objects. Signed-off-by: Artem Chernyshev --- cmd/installer/pkg/install/install.go | 42 +++++---- cmd/installer/pkg/install/verify.go | 21 +++-- cmd/talosctl/cmd/mgmt/cluster/create.go | 39 ++++----- go.mod | 3 +- go.sum | 7 +- .../server/v1alpha1/v1alpha1_server.go | 4 +- .../app/machined/pkg/runtime/disk/disk.go | 6 ++ .../app/machined/pkg/runtime/disk/options.go | 20 +++++ internal/app/machined/pkg/runtime/state.go | 3 +- .../runtime/v1alpha1/bootloader/grub/grub.go | 14 +-- .../pkg/runtime/v1alpha1/bootloader/meta.go | 14 ++- .../runtime/v1alpha1/platform/metal/metal.go | 12 ++- .../v1alpha1/v1alpha1_sequencer_tasks.go | 16 ++-- .../pkg/runtime/v1alpha1/v1alpha1_state.go | 77 +++++++++++----- internal/pkg/mount/system.go | 87 ++++++++++--------- pkg/machinery/go.mod | 6 +- pkg/machinery/go.sum | 13 ++- pkg/provision/providers/docker/node.go | 2 +- pkg/provision/providers/firecracker/node.go | 2 +- pkg/provision/providers/qemu/node.go | 2 +- pkg/provision/request.go | 2 + 21 files changed, 244 insertions(+), 148 deletions(-) create mode 100644 internal/app/machined/pkg/runtime/disk/disk.go create mode 100644 internal/app/machined/pkg/runtime/disk/options.go diff --git a/cmd/installer/pkg/install/install.go b/cmd/installer/pkg/install/install.go index 2c48297035..36d23e3de2 100644 --- a/cmd/installer/pkg/install/install.go +++ b/cmd/installer/pkg/install/install.go @@ -9,7 +9,7 @@ import ( "log" "path/filepath" - "github.com/talos-systems/go-blockdevice/blockdevice/probe" + "github.com/talos-systems/go-blockdevice/blockdevice" "github.com/talos-systems/go-procfs/procfs" "golang.org/x/sys/unix" @@ -113,38 +113,42 @@ func NewInstaller(cmdline *procfs.Cmdline, seq runtime.Sequence, opts *Options) func (i *Installer) probeBootPartition() error { // there's no reason to discover boot partition if the disk is about to be wiped if !i.options.Zero { - if dev, err := probe.DevForFileSystemLabel(i.options.Disk, constants.BootPartitionLabel); err != nil { + dev, err := blockdevice.Open(i.options.Disk) + if err != nil { i.bootPartitionFound = false - } else { - //nolint: errcheck - defer dev.Close() + return err + } + + defer dev.Close() // nolint:errcheck + + if part, err := dev.GetPartition(constants.BootPartitionLabel); err != nil { + i.bootPartitionFound = false + } else { i.bootPartitionFound = true // mount the boot partition temporarily to find the bootloader labels mountpoints := mount.NewMountPoints() - mountpoint := mount.NewMountPoint(dev.Path, constants.BootMountPoint, dev.SuperBlock.Type(), unix.MS_NOATIME|unix.MS_RDONLY, "") + partPath, err := part.Path() + if err != nil { + return err + } + + fsType, err := part.Filesystem() + if err != nil { + return err + } + + mountpoint := mount.NewMountPoint(partPath, constants.BootMountPoint, fsType, unix.MS_NOATIME|unix.MS_RDONLY, "") mountpoints.Set(constants.BootPartitionLabel, mountpoint) if err := mount.Mount(mountpoints); err != nil { - log.Printf("warning: failed to mount boot partition %q: %s", dev.Path, err) + log.Printf("warning: failed to mount boot partition %q: %s", partPath, err) } else { defer mount.Unmount(mountpoints) //nolint: errcheck } } - - // try legacy boot partition - // - // TODO: remove this in Talos 0.8 (only required for upgrading from 0.6) - if !i.bootPartitionFound { - if dev, err := probe.DevForFileSystemLabel(i.options.Disk, constants.LegacyBootPartitionLabel); err == nil { - //nolint: errcheck - defer dev.Close() - - i.bootPartitionFound = true - } - } } var err error diff --git a/cmd/installer/pkg/install/verify.go b/cmd/installer/pkg/install/verify.go index 446daa7da8..7be0c46e90 100644 --- a/cmd/installer/pkg/install/verify.go +++ b/cmd/installer/pkg/install/verify.go @@ -8,7 +8,8 @@ import ( "errors" "fmt" - "github.com/talos-systems/go-blockdevice/blockdevice/probe" + "github.com/talos-systems/go-blockdevice/blockdevice" + "github.com/talos-systems/go-blockdevice/blockdevice/filesystem" "github.com/talos-systems/talos/pkg/machinery/constants" ) @@ -50,9 +51,9 @@ func VerifyBootPartition(opts *Options) (err error) { // VerifyDiskAvailability verifies that no filesystems currently exist with // the labels used by the OS. func VerifyDiskAvailability(devpath, label string) (err error) { - var dev *probe.ProbedBlockDevice + var dev *blockdevice.BlockDevice - if dev, err = probe.DevForFileSystemLabel(devpath, label); err != nil { + if dev, err = blockdevice.Open(devpath); err != nil { // We return here because we only care if we can discover the // device successfully and confirm that the disk is not in use. // TODO(andrewrynhard): We should return a custom error type here @@ -63,8 +64,18 @@ func VerifyDiskAvailability(devpath, label string) (err error) { // nolint: errcheck defer dev.Close() - if dev.SuperBlock != nil { - return fmt.Errorf("target install device %s is not empty, found existing %s file system", label, dev.SuperBlock.Type()) + part, err := dev.GetPartition(label) + if err != nil { + return err + } + + fsType, err := part.Filesystem() + if err != nil { + return err + } + + if fsType != filesystem.Unknown { + return fmt.Errorf("target install device %s is not empty, found existing %s file system", label, fsType) } return nil diff --git a/cmd/talosctl/cmd/mgmt/cluster/create.go b/cmd/talosctl/cmd/mgmt/cluster/create.go index 0e24ddc4f3..46299dc3b9 100644 --- a/cmd/talosctl/cmd/mgmt/cluster/create.go +++ b/cmd/talosctl/cmd/mgmt/cluster/create.go @@ -323,12 +323,13 @@ func create(ctx context.Context) (err error) { var cfg config.Provider nodeReq := provision.NodeRequest{ - Name: fmt.Sprintf("%s-master-%d", clusterName, i+1), - Type: machine.TypeControlPlane, - IP: ips[i], - Memory: memory, - NanoCPUs: nanoCPUs, - Disks: disks, + Name: fmt.Sprintf("%s-master-%d", clusterName, i+1), + Type: machine.TypeControlPlane, + IP: ips[i], + Memory: memory, + NanoCPUs: nanoCPUs, + Disks: disks, + SkipInjectingConfig: skipInjectingConfig, } if i == 0 { @@ -349,21 +350,14 @@ func create(ctx context.Context) (err error) { } } - if !skipInjectingConfig { - nodeReq.Config = cfg - } - + nodeReq.Config = cfg request.Nodes = append(request.Nodes, nodeReq) } for i := 1; i <= workers; i++ { name := fmt.Sprintf("%s-worker-%d", clusterName, i) - var cfg config.Provider - - if !skipInjectingConfig { - cfg = configBundle.Join() - } + cfg := configBundle.Join() ip := ips[masters+i-1] @@ -376,13 +370,14 @@ func create(ctx context.Context) (err error) { request.Nodes = append(request.Nodes, provision.NodeRequest{ - Name: name, - Type: machine.TypeJoin, - IP: ip, - Memory: memory, - NanoCPUs: nanoCPUs, - Disks: disks, - Config: cfg, + Name: name, + Type: machine.TypeJoin, + IP: ip, + Memory: memory, + NanoCPUs: nanoCPUs, + Disks: disks, + Config: cfg, + SkipInjectingConfig: skipInjectingConfig, }) } diff --git a/go.mod b/go.mod index eeb9abfd1b..f6493d5263 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 - github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 + github.com/talos-systems/go-blockdevice v0.1.1-0.20210126125338-5a1c7f768e01 github.com/talos-systems/go-loadbalancer v0.1.0 github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24 github.com/talos-systems/go-retry v0.2.0 @@ -89,7 +89,6 @@ require ( golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.25.0 - gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/freddierice/go-losetup.v1 v1.0.0-20170407175016-fc9adea44124 gopkg.in/fsnotify.v1 v1.4.7 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 88cd8fed35..e0d5d38bd8 100644 --- a/go.sum +++ b/go.sum @@ -860,13 +860,14 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 h1:5TsM3o/yJJF6kakHyPee88D0yWNNDNKZJ2NCX9MFsKk= github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82/go.mod h1:OXCK52Q0dzm88YRG4VdTBdidkPUtqrCxCyW7bUs4DAw= -github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 h1:/yEPl6h6+pK9XIfQEiZ989GDuw6dCUBeinzUcCu6dyY= -github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972/go.mod h1:efEE9wjtgxiovqsZAV39xlOd/AOI/0sLuZqb5jEgeqo= +github.com/talos-systems/go-blockdevice v0.1.1-0.20210126125338-5a1c7f768e01 h1:Efm20xEYOuiSh0Mct8kBudZoS88z5I+fegt5M6Xwqn4= +github.com/talos-systems/go-blockdevice v0.1.1-0.20210126125338-5a1c7f768e01/go.mod h1:DGbop5CJa0PYdhQK9cNVF61pPJNedas1m7Gi/qAnrsM= github.com/talos-systems/go-loadbalancer v0.1.0 h1:MQFONvSjoleU8RrKq1O1Z8CyTCJGd4SLqdAHDlR6o9s= github.com/talos-systems/go-loadbalancer v0.1.0/go.mod h1:D5Qjfz+29WVjONWECZvOkmaLsBb3f5YeWME0u/5HmIc= github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24 h1:fN8vYvlB9XBQ5aImb1vLgR0ZaDwvfZfBMptqkpi3aEg= github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24/go.mod h1:ATyUGFQIW8OnbnmvqefZWVPgL9g+CAmXHfkgny21xX8= github.com/talos-systems/go-retry v0.1.0/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= +github.com/talos-systems/go-retry v0.1.1-0.20201113203059-8c63d290a688/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= github.com/talos-systems/go-retry v0.2.0 h1:YpQHmtTZ2k0i/bBYRIasdVmF0XaiISVJUOrmZ6FzgLU= github.com/talos-systems/go-retry v0.2.0/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= github.com/talos-systems/go-smbios v0.0.0-20200807005123-80196199691e h1:uCp8BfH4Ky2R1XkOKA5pSZpeMMyt0AbH29PIrkoBlaM= @@ -1123,9 +1124,7 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go index 4d44bc453f..af4daf2867 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go @@ -198,12 +198,12 @@ func (s *Server) Rollback(ctx context.Context, in *machine.RollbackRequest) (*ma } if err := func() error { - if err := mount.SystemPartitionMount(constants.BootPartitionLabel); err != nil { + if err := mount.SystemPartitionMount(s.Controller.Runtime(), constants.BootPartitionLabel); err != nil { return fmt.Errorf("error mounting boot partition: %w", err) } defer func() { - if err := mount.SystemPartitionUnmount(constants.BootPartitionLabel); err != nil { + if err := mount.SystemPartitionUnmount(s.Controller.Runtime(), constants.BootPartitionLabel); err != nil { log.Printf("failed unmounting boot partition: %s", err) } }() diff --git a/internal/app/machined/pkg/runtime/disk/disk.go b/internal/app/machined/pkg/runtime/disk/disk.go new file mode 100644 index 0000000000..a4b70b37bb --- /dev/null +++ b/internal/app/machined/pkg/runtime/disk/disk.go @@ -0,0 +1,6 @@ +// 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 disk contains abstract utility function to filter disks in MachineState.Disk call. +package disk diff --git a/internal/app/machined/pkg/runtime/disk/options.go b/internal/app/machined/pkg/runtime/disk/options.go new file mode 100644 index 0000000000..20f5e36c58 --- /dev/null +++ b/internal/app/machined/pkg/runtime/disk/options.go @@ -0,0 +1,20 @@ +// 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 disk + +// Option defines a function that can alter MachineState.Disk() method output. +type Option func(options *Options) + +// Options contains disk selection options. +type Options struct { + Label string +} + +// WithPartitionLabel select a disk which has the partition labeled. +func WithPartitionLabel(label string) Option { + return func(opts *Options) { + opts.Label = label + } +} diff --git a/internal/app/machined/pkg/runtime/state.go b/internal/app/machined/pkg/runtime/state.go index e6384c1159..42f5e5e806 100644 --- a/internal/app/machined/pkg/runtime/state.go +++ b/internal/app/machined/pkg/runtime/state.go @@ -9,6 +9,7 @@ import ( "github.com/talos-systems/os-runtime/pkg/state" "github.com/talos-systems/os-runtime/pkg/state/registry" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk" "github.com/talos-systems/talos/pkg/machinery/config" ) @@ -28,7 +29,7 @@ type Machine interface { // MachineState defines the machined state. type MachineState interface { - Disk() *probe.ProbedBlockDevice + Disk(options ...disk.Option) *probe.ProbedBlockDevice Close() error Installed() bool IsInstallStaged() bool diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go index 5cd2ad7fdc..3c3d8ff665 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go @@ -18,8 +18,7 @@ import ( "strings" "text/template" - "github.com/talos-systems/go-blockdevice/blockdevice/probe" - "github.com/talos-systems/go-blockdevice/blockdevice/util" + "github.com/talos-systems/go-blockdevice/blockdevice" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" "github.com/talos-systems/talos/pkg/machinery/constants" @@ -118,22 +117,23 @@ func (g *Grub) Install(fallback string, config interface{}, sequence runtime.Seq return err } - dev, err := probe.DevForFileSystemLabel(g.BootDisk, constants.BootPartitionLabel) + dev, err := blockdevice.Open(g.BootDisk) if err != nil { - return fmt.Errorf("failed to probe boot partition: %w", err) + return err } // nolint: errcheck defer dev.Close() - blk, err := util.DevnameFromPartname(dev.Path) + // verify that BootDisk has boot partition + _, err = dev.GetPartition(constants.BootPartitionLabel) if err != nil { return err } - loopDevice := strings.HasPrefix(blk, "loop") + blk := dev.Device().Name() - blk = fmt.Sprintf("/dev/%s", blk) + loopDevice := strings.HasPrefix(blk, "/dev/loop") // default: run for GRUB default platform platforms := []string{""} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/meta.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/meta.go index c770b81dab..3e4c8db27e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/meta.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/meta.go @@ -27,13 +27,23 @@ type Meta struct { // NewMeta initializes and returns a `Meta`. func NewMeta() (meta *Meta, err error) { - var f *os.File + var ( + f *os.File + dev *probe.ProbedBlockDevice + ) - f, err = probe.GetPartitionWithName(constants.MetaPartitionLabel) + dev, err = probe.GetDevWithPartitionName(constants.MetaPartitionLabel) if err != nil { return nil, err } + part, err := dev.OpenPartition(constants.MetaPartitionLabel) + if err != nil { + return nil, err + } + + f = part.Device() + adv, err := talos.NewADV(f) if adv == nil && err != nil { // if adv is not nil, but err is nil, it might be missing ADV, ignore it diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal.go index f23ca3ca9c..317c62e381 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal.go @@ -13,6 +13,7 @@ import ( "net/url" "path/filepath" + "github.com/talos-systems/go-blockdevice/blockdevice/filesystem" "github.com/talos-systems/go-blockdevice/blockdevice/probe" "github.com/talos-systems/go-procfs/procfs" "github.com/talos-systems/go-smbios/smbios" @@ -113,7 +114,16 @@ func readConfigFromISO() (b []byte, err error) { // nolint: errcheck defer dev.Close() - if err = unix.Mount(dev.Path, mnt, dev.SuperBlock.Type(), unix.MS_RDONLY, ""); err != nil { + sb, err := filesystem.Probe(dev.Device().Name()) + if err != nil { + return nil, err + } + + if sb == nil { + return nil, fmt.Errorf("failed to get filesystem type") + } + + if err = unix.Mount(dev.Device().Name(), mnt, sb.Type(), unix.MS_RDONLY, ""); err != nil { return nil, fmt.Errorf("failed to mount iso: %w", err) } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index 5560226032..32c55c72db 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -1549,56 +1549,56 @@ func SyncNonVolatileStorageBuffers() { // MountBootPartition mounts the boot partition. func MountBootPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - return mount.SystemPartitionMount(constants.BootPartitionLabel) + return mount.SystemPartitionMount(r, constants.BootPartitionLabel) }, "mountBootPartition" } // UnmountBootPartition unmounts the boot partition. func UnmountBootPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { - return mount.SystemPartitionUnmount(constants.BootPartitionLabel) + return mount.SystemPartitionUnmount(r, constants.BootPartitionLabel) }, "unmountBootPartition" } // MountEFIPartition mounts the EFI partition. func MountEFIPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - return mount.SystemPartitionMount(constants.EFIPartitionLabel) + return mount.SystemPartitionMount(r, constants.EFIPartitionLabel) }, "mountEFIPartition" } // UnmountEFIPartition unmounts the EFI partition. func UnmountEFIPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { - return mount.SystemPartitionUnmount(constants.EFIPartitionLabel) + return mount.SystemPartitionUnmount(r, constants.EFIPartitionLabel) }, "unmountEFIPartition" } // MountStatePartition mounts the system partition. func MountStatePartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - return mount.SystemPartitionMount(constants.StatePartitionLabel, mount.WithSkipIfMounted(true)) + return mount.SystemPartitionMount(r, constants.StatePartitionLabel, mount.WithSkipIfMounted(true)) }, "mountStatePartition" } // UnmountStatePartition unmounts the system partition. func UnmountStatePartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { - return mount.SystemPartitionUnmount(constants.StatePartitionLabel) + return mount.SystemPartitionUnmount(r, constants.StatePartitionLabel) }, "unmountStatePartition" } // MountEphermeralPartition mounts the ephemeral partition. func MountEphermeralPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { - return mount.SystemPartitionMount(constants.EphemeralPartitionLabel) + return mount.SystemPartitionMount(r, constants.EphemeralPartitionLabel, mount.WithResize(true)) }, "mountEphermeralPartition" } // UnmountEphemeralPartition unmounts the ephemeral partition. func UnmountEphemeralPartition(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - return mount.SystemPartitionUnmount(constants.EphemeralPartitionLabel) + return mount.SystemPartitionUnmount(r, constants.EphemeralPartitionLabel) }, "unmountEphemeralPartition" } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go index 8e9b46308b..97e587c806 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go @@ -8,9 +8,11 @@ import ( "errors" "os" + multierror "github.com/hashicorp/go-multierror" "github.com/talos-systems/go-blockdevice/blockdevice/probe" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/adv" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform" @@ -28,7 +30,7 @@ type State struct { // MachineState represents the machine's state. type MachineState struct { - disk *probe.ProbedBlockDevice + disks map[string]*probe.ProbedBlockDevice stagedInstall bool stagedInstallImageRef string @@ -48,13 +50,15 @@ func NewState() (s *State, err error) { machine := &MachineState{} - err = machine.probeDisk() + err = machine.probeDisks() if err != nil { if !errors.Is(err, os.ErrNotExist) { return nil, err } } + machine.probeMeta() + cluster := &ClusterState{} v2State, err := v1alpha2.NewState() @@ -92,26 +96,38 @@ func (s *State) V1Alpha2() runtime.V1Alpha2State { return s.v2 } -func (s *MachineState) probeDisk() error { - if s.disk != nil { - return nil +func (s *MachineState) probeDisks(labels ...string) error { + if len(labels) == 0 { + labels = []string{constants.EphemeralPartitionLabel, constants.BootPartitionLabel, constants.EFIPartitionLabel, constants.StatePartitionLabel} } - var dev *probe.ProbedBlockDevice - - dev, err := probe.GetDevWithFileSystemLabel(constants.EphemeralPartitionLabel) - if err == nil { - s.disk = dev + if s.disks == nil { + s.disks = map[string]*probe.ProbedBlockDevice{} } - if err != nil { - return err + for _, label := range labels { + if _, ok := s.disks[label]; ok { + continue + } + + var dev *probe.ProbedBlockDevice + + dev, err := probe.GetDevWithPartitionName(label) + if err != nil { + return err + } + + s.disks[label] = dev } + return nil +} + +func (s *MachineState) probeMeta() { meta, err := bootloader.NewMeta() if err != nil { // ignore missing meta - return nil + return } defer meta.Close() //nolint: errcheck @@ -134,31 +150,44 @@ func (s *MachineState) probeDisk() error { s.stagedInstallImageRef = stagedInstallImageRef s.stagedInstallOptions = []byte(stagedInstallOptions) } - - return nil } // Disk implements the machine state interface. -func (s *MachineState) Disk() *probe.ProbedBlockDevice { - s.probeDisk() //nolint: errcheck +func (s *MachineState) Disk(options ...disk.Option) *probe.ProbedBlockDevice { + opts := &disk.Options{ + Label: constants.EphemeralPartitionLabel, + } + + for _, opt := range options { + opt(opts) + } + + s.probeDisks(opts.Label) //nolint: errcheck - return s.disk + return s.disks[opts.Label] } // Close implements the machine state interface. func (s *MachineState) Close() error { - if s.disk != nil { - return s.disk.Close() + var result *multierror.Error + + for _, disk := range s.disks { + if err := disk.Close(); err != nil { + e := multierror.Append(result, err) + if e != nil { + return e + } + } } - return nil + return result.ErrorOrNil() } // Installed implements the machine state interface. func (s *MachineState) Installed() bool { - s.probeDisk() //nolint: errcheck - - return s.disk != nil + return s.Disk( + disk.WithPartitionLabel(constants.EphemeralPartitionLabel), + ) != nil } // IsInstallStaged implements the machine state interface. diff --git a/internal/pkg/mount/system.go b/internal/pkg/mount/system.go index 12997f9cad..535335bc31 100644 --- a/internal/pkg/mount/system.go +++ b/internal/pkg/mount/system.go @@ -6,11 +6,13 @@ package mount import ( "fmt" - "log" + "os" - "github.com/talos-systems/go-blockdevice/blockdevice/probe" + "github.com/talos-systems/go-blockdevice/blockdevice" "golang.org/x/sys/unix" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk" "github.com/talos-systems/talos/pkg/machinery/constants" ) @@ -19,40 +21,22 @@ import ( // 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 SystemMountPointsForDevice(devpath string) (mountpoints *Points, err error) { +func SystemMountPointsForDevice(devpath string, opts ...Option) (mountpoints *Points, err error) { mountpoints = NewMountPoints() - for _, name := range []string{constants.EphemeralPartitionLabel, constants.BootPartitionLabel, constants.EFIPartitionLabel, constants.StatePartitionLabel} { - var target string - - switch name { - case constants.EphemeralPartitionLabel: - target = constants.EphemeralMountPoint - case constants.BootPartitionLabel: - target = constants.BootMountPoint - case constants.EFIPartitionLabel: - target = constants.EFIMountPoint - case constants.StatePartitionLabel: - target = constants.StateMountPoint - } - - var dev *probe.ProbedBlockDevice - - if dev, err = probe.DevForFileSystemLabel(devpath, name); err != nil { - if name == constants.BootPartitionLabel { - // A bootloader is not always required. - log.Println("WARNING: no boot partition was found") + bd, err := blockdevice.Open(devpath) + if err != nil { + return nil, err + } - continue - } + defer bd.Close() // nolint:errcheck - return nil, fmt.Errorf("probe device for filesystem %s: %w", name, err) + for _, name := range []string{constants.EphemeralPartitionLabel, constants.BootPartitionLabel, constants.EFIPartitionLabel, constants.StatePartitionLabel} { + mountpoint, err := SystemMountPointForLabel(bd, name, opts...) + if err != nil { + return nil, err } - // nolint: errcheck - defer dev.Close() - - mountpoint := NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "") mountpoints.Set(name, mountpoint) } @@ -60,14 +44,13 @@ func SystemMountPointsForDevice(devpath string) (mountpoints *Points, err error) } // SystemMountPointForLabel returns a mount point for the specified device and label. -func SystemMountPointForLabel(label string, opts ...Option) (mountpoint *Point, err error) { +// nolint:gocyclo +func SystemMountPointForLabel(device *blockdevice.BlockDevice, label string, opts ...Option) (mountpoint *Point, err error) { var target string switch label { case constants.EphemeralPartitionLabel: target = constants.EphemeralMountPoint - - opts = append(opts, WithResize(true)) case constants.BootPartitionLabel: target = constants.BootMountPoint case constants.EFIPartitionLabel: @@ -78,9 +61,12 @@ func SystemMountPointForLabel(label string, opts ...Option) (mountpoint *Point, return nil, fmt.Errorf("unknown label: %q", label) } - var dev *probe.ProbedBlockDevice + partition, err := device.GetPartition(label) + if err != nil && err != os.ErrNotExist { + return nil, err + } - if dev, err = probe.GetDevWithFileSystemLabel(label); err != nil { + if partition == nil { // A boot partitition is not required. if label == constants.BootPartitionLabel { return nil, nil @@ -89,19 +75,31 @@ func SystemMountPointForLabel(label string, opts ...Option) (mountpoint *Point, return nil, fmt.Errorf("failed to find device with label %s: %w", label, err) } - // nolint: errcheck - defer dev.Close() + fsType, err := partition.Filesystem() + if err != nil { + return nil, err + } + + partPath, err := partition.Path() + if err != nil { + return nil, err + } - mountpoint = NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "", opts...) + mountpoint = NewMountPoint(partPath, target, fsType, unix.MS_NOATIME, "", opts...) return mountpoint, nil } // SystemPartitionMount mounts a system partition by the label. -func SystemPartitionMount(label string, opts ...Option) (err error) { +func SystemPartitionMount(r runtime.Runtime, label string, opts ...Option) (err error) { + device := r.State().Machine().Disk(disk.WithPartitionLabel(label)) + if device == nil { + return fmt.Errorf("failed to find device with partition labeled %s", label) + } + mountpoints := NewMountPoints() - mountpoint, err := SystemMountPointForLabel(label, opts...) + mountpoint, err := SystemMountPointForLabel(device.BlockDevice, label, opts...) if err != nil { return err } @@ -120,10 +118,15 @@ func SystemPartitionMount(label string, opts ...Option) (err error) { } // SystemPartitionUnmount unmounts a system partition by the label. -func SystemPartitionUnmount(label string) (err error) { +func SystemPartitionUnmount(r runtime.Runtime, label string) (err error) { + device := r.State().Machine().Disk(disk.WithPartitionLabel(label)) + if device == nil { + return fmt.Errorf("failed to find device with partition labeled %s", label) + } + mountpoints := NewMountPoints() - mountpoint, err := SystemMountPointForLabel(label) + mountpoint, err := SystemMountPointForLabel(device.BlockDevice, label) if err != nil { return err } diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index d213e9bedd..81044755d6 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -12,6 +12,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.4.3 github.com/hashicorp/go-multierror v1.1.0 + github.com/kr/text v0.2.0 // indirect github.com/onsi/ginkgo v1.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 github.com/stretchr/objx v0.2.0 // indirect @@ -20,11 +21,12 @@ require ( github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect - golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect - golang.org/x/text v0.3.3 // indirect + golang.org/x/sys v0.0.0-20201130171929-760e229fe7c5 // indirect + golang.org/x/text v0.3.4 // indirect google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7 google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.25.0 + gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/yaml.v2 v2.2.8 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/pkg/machinery/go.sum b/pkg/machinery/go.sum index aa52e55f88..f17cd6be82 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -14,6 +14,7 @@ github.com/containerd/go-cni v1.0.0 h1:A681A9YQ5Du9V2/gZGk/pTm6g69wF0aGd9qFN9syB github.com/containerd/go-cni v1.0.0/go.mod h1:8n8EnvP0b886Wmqum9jDXlN59aHCIBKgaNYQzcDvJbU= github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -64,6 +65,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -125,11 +128,11 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201130171929-760e229fe7c5 h1:dMDtAap8F/+vsyXblqK90iTzYJjNix5MsXDicSYol6w= +golang.org/x/sys v0.0.0-20201130171929-760e229fe7c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -167,6 +170,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/pkg/provision/providers/docker/node.go b/pkg/provision/providers/docker/node.go index 5936c2aa74..e06e705782 100644 --- a/pkg/provision/providers/docker/node.go +++ b/pkg/provision/providers/docker/node.go @@ -65,7 +65,7 @@ func (p *provisioner) createNodes(ctx context.Context, clusterReq provision.Clus func (p *provisioner) createNode(ctx context.Context, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest, options *provision.Options) (provision.NodeInfo, error) { env := []string{"PLATFORM=container"} - if nodeReq.Config != nil { + if !nodeReq.SkipInjectingConfig { cfg, err := nodeReq.Config.String() if err != nil { return provision.NodeInfo{}, err diff --git a/pkg/provision/providers/firecracker/node.go b/pkg/provision/providers/firecracker/node.go index 2e2ae8a2c2..9b7861fd21 100644 --- a/pkg/provision/providers/firecracker/node.go +++ b/pkg/provision/providers/firecracker/node.go @@ -98,7 +98,7 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe var nodeConfig string - if nodeReq.Config != nil { + if !nodeReq.SkipInjectingConfig { cmdline.Append("talos.config", "{TALOS_CONFIG_URL}") // to be patched by launcher nodeConfig, err = nodeReq.Config.String() diff --git a/pkg/provision/providers/qemu/node.go b/pkg/provision/providers/qemu/node.go index 688af2c75a..46be644c89 100644 --- a/pkg/provision/providers/qemu/node.go +++ b/pkg/provision/providers/qemu/node.go @@ -89,7 +89,7 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe var nodeConfig string - if nodeReq.Config != nil { + if !nodeReq.SkipInjectingConfig { cmdline.Append("talos.config", "{TALOS_CONFIG_URL}") // to be patched by launcher nodeConfig, err = nodeReq.Config.String() diff --git a/pkg/provision/request.go b/pkg/provision/request.go index 04cb4abd78..c5d14c4d58 100644 --- a/pkg/provision/request.go +++ b/pkg/provision/request.go @@ -141,6 +141,8 @@ type NodeRequest struct { Disks []*Disk // Ports Ports []string + // SkipInjectingConfig disables reading configuration from http server + SkipInjectingConfig bool // PXE-booted VMs PXEBooted bool