diff --git a/go.mod b/go.mod index be45e2e2..26388b6a 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,9 @@ require ( github.com/erikgeiser/promptkit v0.9.0 github.com/google/go-containerregistry v0.20.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/jaypipes/ghw v0.13.0 + github.com/jaypipes/ghw v0.13.0 // indirect github.com/joho/godotenv v1.5.1 - github.com/kairos-io/kairos-sdk v0.4.4 + github.com/kairos-io/kairos-sdk v0.4.5 github.com/kairos-io/kcrypt v0.12.2 github.com/labstack/echo/v4 v4.12.0 github.com/mitchellh/mapstructure v1.5.0 @@ -39,6 +39,8 @@ require ( require ( github.com/distribution/reference v0.6.0 github.com/gofrs/uuid v4.4.0+incompatible + github.com/google/go-github/v63 v63.0.0 + github.com/twpayne/go-vfs/v4 v4.3.0 github.com/google/go-github/v65 v65.0.0 github.com/twpayne/go-vfs/v5 v5.0.4 ) @@ -68,7 +70,7 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 // indirect - github.com/containerd/containerd v1.7.21 // indirect + github.com/containerd/containerd v1.7.22 // indirect github.com/containerd/continuity v0.4.2 // indirect github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect @@ -82,7 +84,7 @@ require ( github.com/djherbis/times v1.6.0 // indirect github.com/docker/cli v27.1.1+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v27.2.0+incompatible // indirect + github.com/docker/docker v27.2.1+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -214,7 +216,7 @@ require ( golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/image v0.18.0 // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect diff --git a/go.sum b/go.sum index 8f5af5b1..ded597d3 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHq github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 h1:Ig+OPkE3XQrrl+SKsOqAjlkrBN/zrr+Qpw7rCuDjRCE= github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/containerd/containerd v1.7.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= -github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= +github.com/containerd/containerd v1.7.22 h1:nZuNnNRA6T6jB975rx2RRNqqH2k6ELYKDZfqTHqwyy0= +github.com/containerd/containerd v1.7.22/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= @@ -131,8 +131,8 @@ github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2 github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= -github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -230,6 +230,7 @@ github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE= github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA= +github.com/google/go-github/v65 v65.0.0/go.mod h1:DvrqWo5hvsdhJvHd4WyVF9ttANN3BniqjP8uTFMNb60= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= @@ -278,6 +279,12 @@ github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= github.com/kairos-io/kairos-sdk v0.4.3 h1:gIC/PsWjv9/Z+6RIHRG9IS5MB9gACw1ZjPAi7VydSSo= github.com/kairos-io/kairos-sdk v0.4.3/go.mod h1:bxUPzirl8vNtqB48FJ2835QKio3d3PrHbkAejkibV8I= +github.com/kairos-io/kairos-sdk v0.4.4-0.20240912144533-f312c84d81be h1:cY33zv58Ejwn6u0nBp0ALJYNKlLPD534HHO6SQ6lksk= +github.com/kairos-io/kairos-sdk v0.4.4-0.20240912144533-f312c84d81be/go.mod h1:fPLrvHAStnKR1wGGyNj61prnYsC9QNQCNxnKe/49H54= +github.com/kairos-io/kairos-sdk v0.4.4 h1:FolUGqpdTnYYdLwFEOND97QEp2H/htVjW7pHUOmtxNI= +github.com/kairos-io/kairos-sdk v0.4.4/go.mod h1:OIJYihhuiUOeBXHYj9V3R381SAgc/EaKrFepcBxGroM= +github.com/kairos-io/kairos-sdk v0.4.5 h1:ja3GBPODLPx4X/9dEALncpDIHvFH8TdEBMda0H6O49o= +github.com/kairos-io/kairos-sdk v0.4.5/go.mod h1:OIJYihhuiUOeBXHYj9V3R381SAgc/EaKrFepcBxGroM= github.com/kairos-io/kcrypt v0.12.2 h1:+lr8FGS0AW6D5dWSmaR3+AobL1TBTnOFgCSYctKY+5I= github.com/kairos-io/kcrypt v0.12.2/go.mod h1:7SPiHzNMYl4MlxeB30s1YlHDYByTusu7u1mU5Nvicm0= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -529,6 +536,7 @@ github.com/tredoe/osutil v1.5.0 h1:UGVxbbHRoZi8xXVmbNZ2vgG6XoJ15ndE4LniiQ3rJKg= github.com/tredoe/osutil v1.5.0/go.mod h1:TEzphzUUunysbdDRfdOgqkg10POQbnfIPV50ynqOfIg= github.com/twpayne/go-vfs/v4 v4.3.0 h1:rTqFzzOQ/6ESKTSiwVubHlCBedJDOhQyVSnw8rQNZhU= github.com/twpayne/go-vfs/v4 v4.3.0/go.mod h1:tq2UVhnUepesc0lSnPJH/jQ8HruGhzwZe2r5kDFpEIw= +github.com/twpayne/go-vfs/v5 v5.0.4/go.mod h1:zTPFJUbgsEMFNSWnWQlLq9wh4AN83edZzx3VXbxrS1w= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= @@ -616,8 +624,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -791,6 +799,8 @@ howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/mount-utils v0.31.0 h1:o+a+n6gyZ7MGc6bIERU3LeFTHbLDBiVReaDpWlJotUE= +k8s.io/mount-utils v0.31.0/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU= k8s.io/mount-utils v0.31.1 h1:f8UrH9kRynljmdNGM6BaCvFUON5ZPKDgE+ltmYqI4wA= k8s.io/mount-utils v0.31.1/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= diff --git a/internal/agent/hooks/hooks_test.go b/internal/agent/hooks/hooks_test.go index d91bfb77..ee712389 100644 --- a/internal/agent/hooks/hooks_test.go +++ b/internal/agent/hooks/hooks_test.go @@ -2,7 +2,11 @@ package hook_test import ( "bytes" - "github.com/jaypipes/ghw/pkg/block" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + "os" + "path/filepath" + "testing" + _ "github.com/kairos-io/kairos-agent/v2/internal/agent/hooks" hook "github.com/kairos-io/kairos-agent/v2/internal/agent/hooks" "github.com/kairos-io/kairos-agent/v2/pkg/config" @@ -11,13 +15,11 @@ import ( v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" "github.com/kairos-io/kairos-sdk/collector" sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs/v4" "github.com/twpayne/go-vfs/v4/vfst" - "os" - "path/filepath" - "testing" ) func TestConfig(t *testing.T) { @@ -37,7 +39,7 @@ var _ = Describe("Hooks", func() { var cleanup func() var memLog *bytes.Buffer var extractor *v1mock.FakeImageExtractor - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock var err error Context("SysExtPostInstall", func() { @@ -79,22 +81,23 @@ var _ = Describe("Hooks", func() { ) cfg.Config = collector.Config{} - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", MountPoint: "/efi", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) AfterEach(func() { + ghwTest.Clean() cleanup() }) It("should copy all files with .sysext.raw extension", func() { diff --git a/internal/agent/hooks/sysext.go b/internal/agent/hooks/sysext.go index b152c121..164f1f43 100644 --- a/internal/agent/hooks/sysext.go +++ b/internal/agent/hooks/sysext.go @@ -16,7 +16,7 @@ type SysExtPostInstall struct{} func (b SysExtPostInstall) Run(c config.Config, _ v1.Spec) error { c.Logger.Logger.Debug().Msg("Running SysExtPostInstall hook") // mount efi partition - efiPart, err := partitions.GetEfiPartition() + efiPart, err := partitions.GetEfiPartition(&c.Logger) if err != nil { c.Logger.Errorf("failed to get EFI partition: %s", err) if c.FailOnBundleErrors { diff --git a/internal/agent/install_test.go b/internal/agent/install_test.go index e9a8a00c..da2c1b28 100644 --- a/internal/agent/install_test.go +++ b/internal/agent/install_test.go @@ -2,13 +2,13 @@ package agent import ( v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + "github.com/kairos-io/kairos-sdk/types" "os" "path/filepath" - "github.com/jaypipes/ghw/pkg/block" - "github.com/kairos-io/kairos-agent/v2/pkg/constants" - "github.com/kairos-io/kairos-agent/v2/pkg/config" + "github.com/kairos-io/kairos-agent/v2/pkg/constants" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" "github.com/twpayne/go-vfs/v4/vfst" @@ -63,7 +63,7 @@ var _ = Describe("RunInstall", func() { var err error var fs v1.FS var cleanup func() - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock var cmdline func() ([]byte, error) BeforeEach(func() { @@ -125,47 +125,47 @@ var _ = Describe("RunInstall", func() { }, } - mainDisk := block.Disk{ + mainDisk := types.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*types.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", }, { Name: "device2", FilesystemLabel: "COS_STATE", - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: "COS_PERSISTENT", - Type: "ext4", + FS: "ext4", }, { Name: "device4", FilesystemLabel: "COS_ACTIVE", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_PASSIVE", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_RECOVERY", - Type: "ext4", + FS: "ext4", }, { Name: "device6", FilesystemLabel: "COS_OEM", - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) diff --git a/internal/agent/interactive_install.go b/internal/agent/interactive_install.go index 4221977a..ab8ab40a 100644 --- a/internal/agent/interactive_install.go +++ b/internal/agent/interactive_install.go @@ -12,10 +12,10 @@ import ( "github.com/kairos-io/kairos-agent/v2/pkg/config" events "github.com/kairos-io/kairos-sdk/bus" "github.com/kairos-io/kairos-sdk/collector" + "github.com/kairos-io/kairos-sdk/ghw" "github.com/kairos-io/kairos-sdk/unstructured" "github.com/erikgeiser/promptkit/textinput" - "github.com/jaypipes/ghw" "github.com/kairos-io/kairos-sdk/utils" "github.com/mudler/go-pluggable" "github.com/mudler/yip/pkg/schema" @@ -129,20 +129,17 @@ func InteractiveInstall(debug, spawnShell bool, sourceImgURL string) error { maxSize := float64(0) preferedDevice := "/dev/sda" - block, err := ghw.Block() - if err == nil { - for _, disk := range block.Disks { - // skip useless devices (/dev/ram, /dev/loop, /dev/sr, /dev/zram) - if strings.HasPrefix(disk.Name, "loop") || strings.HasPrefix(disk.Name, "ram") || strings.HasPrefix(disk.Name, "sr") || strings.HasPrefix(disk.Name, "zram") { - continue - } - size := float64(disk.SizeBytes) / float64(GiB) - if size > maxSize { - maxSize = size - preferedDevice = "/dev/" + disk.Name - } - disks = append(disks, fmt.Sprintf("/dev/%s: %s (%.2f GiB) ", disk.Name, disk.Model, float64(disk.SizeBytes)/float64(GiB))) + for _, disk := range ghw.GetDisks(ghw.NewPaths(""), nil) { + // skip useless devices (/dev/ram, /dev/loop, /dev/sr, /dev/zram) + if strings.HasPrefix(disk.Name, "loop") || strings.HasPrefix(disk.Name, "ram") || strings.HasPrefix(disk.Name, "sr") || strings.HasPrefix(disk.Name, "zram") { + continue + } + size := float64(disk.SizeBytes) / float64(GiB) + if size > maxSize { + maxSize = size + preferedDevice = "/dev/" + disk.Name } + disks = append(disks, fmt.Sprintf("/dev/%s: (%.2f GiB) ", disk.Name, float64(disk.SizeBytes)/float64(GiB))) } pterm.Info.Println("Available Disks:") diff --git a/pkg/action/bootentries.go b/pkg/action/bootentries.go index 7f789ad1..c843352c 100644 --- a/pkg/action/bootentries.go +++ b/pkg/action/bootentries.go @@ -2,6 +2,7 @@ package action import ( "fmt" + sdkTypes "github.com/kairos-io/kairos-sdk/types" "os" "path/filepath" "reflect" @@ -15,7 +16,6 @@ import ( "github.com/erikgeiser/promptkit/confirmation" "github.com/erikgeiser/promptkit/selection" "github.com/kairos-io/kairos-agent/v2/pkg/config" - v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" "github.com/kairos-io/kairos-agent/v2/pkg/utils" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions" @@ -75,7 +75,7 @@ func selectBootEntrySystemd(cfg *config.Config, entry string) error { cfg.Logger.Infof("Setting default boot entry to %s", entry) // Get EFI partition - efiPartition, err := partitions.GetEfiPartition() + efiPartition, err := partitions.GetEfiPartition(&cfg.Logger) if err != nil { return err } @@ -270,7 +270,7 @@ func listBootEntriesSystemd(cfg *config.Config) error { cleanup := utils.NewCleanStack() defer func() { err = cleanup.Cleanup(err) }() // Get EFI partition - efiPartition, err := partitions.GetEfiPartition() + efiPartition, err := partitions.GetEfiPartition(&cfg.Logger) if err != nil { return err } @@ -319,7 +319,7 @@ func listBootEntriesSystemd(cfg *config.Config) error { } // ListSystemdEntries reads the systemd-boot entries and returns a list of entries found -func listSystemdEntries(cfg *config.Config, efiPartition *v1.Partition) ([]string, error) { +func listSystemdEntries(cfg *config.Config, efiPartition *sdkTypes.Partition) ([]string, error) { var entries []string err := fsutils.WalkDirFs(cfg.Fs, filepath.Join(efiPartition.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error { if err != nil { diff --git a/pkg/action/bootentries_test.go b/pkg/action/bootentries_test.go index 6104c107..e363dd7d 100644 --- a/pkg/action/bootentries_test.go +++ b/pkg/action/bootentries_test.go @@ -5,13 +5,12 @@ import ( "os" "syscall" - "github.com/jaypipes/ghw/pkg/block" agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" "github.com/kairos-io/kairos-agent/v2/pkg/utils" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" "github.com/kairos-io/kairos-sdk/collector" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" sdkTypes "github.com/kairos-io/kairos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -31,7 +30,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { var cleanup func() var memLog *bytes.Buffer var extractor *v1mock.FakeImageExtractor - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { runner = v1mock.NewFakeRunner() @@ -72,23 +71,24 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { ) config.Config = collector.Config{} - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", MountPoint: "/efi", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) AfterEach(func() { + ghwTest.Clean() cleanup() }) Context("Under Uki", func() { @@ -117,7 +117,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { err = fs.WriteFile("/efi/loader/entries/statereset.conf", []byte("title kairos state reset (auto)\nefi /EFI/kairos/statereset.efi\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) - entries, err := listSystemdEntries(config, &v1.Partition{MountPoint: "/efi"}) + entries, err := listSystemdEntries(config, &sdkTypes.Partition{MountPoint: "/efi"}) Expect(err).ToNot(HaveOccurred()) Expect(entries).To(HaveLen(4)) Expect(entries).To(ContainElement("cos")) @@ -127,10 +127,9 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { }) It("list empty boot entries if there is none", func() { - entries, err := listSystemdEntries(config, &v1.Partition{MountPoint: "/efi"}) + entries, err := listSystemdEntries(config, &sdkTypes.Partition{MountPoint: "/efi"}) Expect(err).ToNot(HaveOccurred()) Expect(entries).To(HaveLen(0)) - }) }) Context("SelectBootEntry", func() { diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 7a8002cc..70d73189 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -20,21 +20,22 @@ import ( "bytes" "fmt" "github.com/diskfs/go-diskfs" - sdkTypes "github.com/kairos-io/kairos-sdk/types" + "os" "path/filepath" "regexp" - agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - "github.com/kairos-io/kairos-sdk/collector" - - "github.com/jaypipes/ghw/pkg/block" "github.com/kairos-io/kairos-agent/v2/pkg/action" + agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" "github.com/kairos-io/kairos-agent/v2/pkg/utils" + fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + "github.com/kairos-io/kairos-sdk/collector" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs/v4" @@ -52,7 +53,7 @@ var _ = Describe("Install action tests", func() { var cloudInit *v1mock.FakeCloudInitRunner var cleanup func() var memLog *bytes.Buffer - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock var extractor *v1mock.FakeImageExtractor BeforeEach(func() { @@ -148,47 +149,47 @@ var _ = Describe("Install action tests", func() { _, err = fs.Create(grubCfg) Expect(err).To(BeNil()) - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", }, { Name: "device2", FilesystemLabel: "COS_STATE", - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: "COS_PERSISTENT", - Type: "ext4", + FS: "ext4", }, { Name: "device4", FilesystemLabel: "COS_ACTIVE", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_PASSIVE", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_RECOVERY", - Type: "ext4", + FS: "ext4", }, { Name: "device6", FilesystemLabel: "COS_OEM", - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() diff --git a/pkg/action/reset_test.go b/pkg/action/reset_test.go index a747b023..fc1531c3 100644 --- a/pkg/action/reset_test.go +++ b/pkg/action/reset_test.go @@ -20,18 +20,19 @@ import ( "bytes" "errors" "fmt" - agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - sdkTypes "github.com/kairos-io/kairos-sdk/types" "path/filepath" "regexp" - "github.com/jaypipes/ghw/pkg/block" "github.com/kairos-io/kairos-agent/v2/pkg/action" + agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" "github.com/kairos-io/kairos-agent/v2/pkg/utils" + "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs/v4" @@ -49,7 +50,7 @@ var _ = Describe("Reset action tests", func() { var cloudInit *v1mock.FakeCloudInitRunner var cleanup func() var memLog *bytes.Buffer - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock var extractor *v1mock.FakeImageExtractor BeforeEach(func() { @@ -97,37 +98,37 @@ var _ = Describe("Reset action tests", func() { _, err = fs.Create(recoveryImg) Expect(err).To(BeNil()) - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", }, { Name: "device2", FilesystemLabel: "COS_STATE", - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: "COS_PERSISTENT", - Type: "ext4", + FS: "ext4", }, { Name: "device4", FilesystemLabel: "COS_OEM", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_RECOVERY", - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 44c57e0a..98ea6f8d 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -24,18 +24,17 @@ import ( "path/filepath" "strings" - "github.com/kairos-io/kairos-sdk/collector" - sdkTypes "github.com/kairos-io/kairos-sdk/types" - "github.com/kairos-io/kairos-agent/v2/internal/agent" - agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - - "github.com/jaypipes/ghw/pkg/block" "github.com/kairos-io/kairos-agent/v2/pkg/action" + agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + "github.com/kairos-io/kairos-sdk/collector" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs/v4" @@ -53,7 +52,7 @@ var _ = Describe("Upgrade Actions test", func() { var cloudInit *v1mock.FakeCloudInitRunner var cleanup func() var memLog *bytes.Buffer - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock var extractor *v1mock.FakeImageExtractor var dummySourceFile string var dummySourceSizeMb int64 @@ -115,39 +114,39 @@ var _ = Describe("Upgrade Actions test", func() { fsutils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.RunningStateDir), constants.DirPerm) fsutils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.LiveDir), constants.DirPerm) - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", }, { Name: "device2", FilesystemLabel: "COS_STATE", - Type: "ext4", + FS: "ext4", MountPoint: constants.RunningStateDir, }, { Name: "loop0", FilesystemLabel: "COS_ACTIVE", - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: "COS_RECOVERY", - Type: "ext4", + FS: "ext4", MountPoint: constants.LiveDir, }, { Name: "device6", FilesystemLabel: "COS_OEM", - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) diff --git a/pkg/cloudinit/cloudinit_test.go b/pkg/cloudinit/cloudinit_test.go index 2130cd64..0e556f1d 100644 --- a/pkg/cloudinit/cloudinit_test.go +++ b/pkg/cloudinit/cloudinit_test.go @@ -20,22 +20,21 @@ import ( "bytes" "errors" "fmt" - "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - sdkTypes "github.com/kairos-io/kairos-sdk/types" "io/ioutil" "log" "os" - "github.com/jaypipes/ghw/pkg/block" - . "github.com/kairos-io/kairos-agent/v2/pkg/cloudinit" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" - "github.com/twpayne/go-vfs/v4/vfst" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/twpayne/go-vfs/v4/vfst" ) // Parted print sample output @@ -159,8 +158,8 @@ stages: pLabel: partLabel `, device)), constants.FilePerm) Expect(err).To(BeNil()) - ghwTest := v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ + ghwTest := ghwMock.GhwMock{} + disk := sdkTypes.Disk{Name: "device", Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "DEV_LABEL", @@ -187,11 +186,11 @@ stages: size: 0 `, device)), constants.FilePerm) Expect(err).To(BeNil()) - ghwTest := v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ + ghwTest := ghwMock.GhwMock{} + disk := sdkTypes.Disk{Name: "device", Partitions: []*sdkTypes.Partition{ { Name: fmt.Sprintf("device%d", partNum), - Type: "ext4", + FS: "ext4", }, }} ghwTest.AddDisk(disk) diff --git a/pkg/config/config.go b/pkg/config/config.go index fff985b0..131a68af 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -52,7 +52,7 @@ type Install struct { Recovery v1.Image `yaml:"recovery-system,omitempty" mapstructure:"recovery-system"` Passive v1.Image `yaml:"passive,omitempty" mapstructure:"recovery-system"` GrubDefEntry string `yaml:"grub-entry-name,omitempty" mapstructure:"grub-entry-name"` - ExtraPartitions v1.PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` + ExtraPartitions sdkTypes.PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` ExtraDirsRootfs []string `yaml:"extra-dirs-rootfs,omitempty" mapstructure:"extra-dirs-rootfs"` Force bool `yaml:"force,omitempty" mapstructure:"force"` } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index ce2cd1b8..a0fcf6ee 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -17,6 +17,7 @@ package config_test import ( "fmt" + sdkTypes "github.com/kairos-io/kairos-sdk/types" "path/filepath" "reflect" "strings" @@ -151,7 +152,7 @@ var _ = Describe("Schema", func() { Size: 10000, }, Partitions: v1.ElementalPartitions{ - OEM: &v1.Partition{ + OEM: &sdkTypes.Partition{ Size: 5120, FS: "ext4", }, diff --git a/pkg/config/spec.go b/pkg/config/spec.go index 9a148d3f..f5d721f3 100644 --- a/pkg/config/spec.go +++ b/pkg/config/spec.go @@ -24,20 +24,19 @@ import ( "reflect" "strings" - "github.com/kairos-io/kairos-sdk/collector" - sdkTypes "github.com/kairos-io/kairos-sdk/types" - - "github.com/google/go-containerregistry/pkg/crane" - "github.com/jaypipes/ghw" - "golang.org/x/sys/unix" - "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions" + "github.com/kairos-io/kairos-sdk/collector" + "github.com/kairos-io/kairos-sdk/ghw" + "github.com/kairos-io/kairos-sdk/types" + + "github.com/google/go-containerregistry/pkg/crane" "github.com/mitchellh/mapstructure" "github.com/sanity-io/litter" "github.com/spf13/viper" + "golang.org/x/sys/unix" ) const ( @@ -143,7 +142,7 @@ func NewInstallSpec(cfg *Config) (*v1.InstallSpec, error) { return spec, nil } -func NewInstallElementalPartitions(log sdkTypes.KairosLogger, spec *v1.InstallSpec) v1.ElementalPartitions { +func NewInstallElementalPartitions(log types.KairosLogger, spec *v1.InstallSpec) v1.ElementalPartitions { pt := v1.ElementalPartitions{} var oemSize uint if spec.Partitions.OEM != nil && spec.Partitions.OEM.Size != 0 { @@ -151,7 +150,7 @@ func NewInstallElementalPartitions(log sdkTypes.KairosLogger, spec *v1.InstallSp } else { oemSize = constants.OEMSize } - pt.OEM = &v1.Partition{ + pt.OEM = &types.Partition{ FilesystemLabel: constants.OEMLabel, Size: oemSize, Name: constants.OEMPartName, @@ -176,7 +175,7 @@ func NewInstallElementalPartitions(log sdkTypes.KairosLogger, spec *v1.InstallSp } } log.Infof("Setting recovery partition size to %dMb", recoverySize) - pt.Recovery = &v1.Partition{ + pt.Recovery = &types.Partition{ FilesystemLabel: constants.RecoveryLabel, Size: recoverySize, Name: constants.RecoveryPartName, @@ -202,7 +201,7 @@ func NewInstallElementalPartitions(log sdkTypes.KairosLogger, spec *v1.InstallSp } } log.Infof("Setting state partition size to %dMb", stateSize) - pt.State = &v1.Partition{ + pt.State = &types.Partition{ FilesystemLabel: constants.StateLabel, Size: stateSize, Name: constants.StatePartName, @@ -216,7 +215,7 @@ func NewInstallElementalPartitions(log sdkTypes.KairosLogger, spec *v1.InstallSp } else { persistentSize = spec.Partitions.Persistent.Size } - pt.Persistent = &v1.Partition{ + pt.Persistent = &types.Partition{ FilesystemLabel: constants.PersistentLabel, Size: persistentSize, Name: constants.PersistentPartName, @@ -238,7 +237,7 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) { cfg.Logger.Warnf("failed reading installation state: %s", err.Error()) } - parts, err := partitions.GetAllPartitions() + parts, err := partitions.GetAllPartitions(&cfg.Logger) if err != nil { return nil, fmt.Errorf("could not read host partitions") } @@ -401,7 +400,7 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) { cfg.Logger.Warnf("failed reading installation state: %s", err.Error()) } - parts, err := partitions.GetAllPartitions() + parts, err := partitions.GetAllPartitions(&cfg.Logger) if err != nil { return nil, fmt.Errorf("could not read host partitions") } @@ -554,7 +553,7 @@ func NewUkiResetSpec(cfg *Config) (spec *v1.ResetUkiSpec, err error) { spec.Partitions.OEM = partitions.GetPartitionViaDM(cfg.Fs, constants.OEMLabel) // Get EFI partition - parts, err := partitions.GetAllPartitions() + parts, err := partitions.GetAllPartitions(&cfg.Logger) if err != nil { return spec, fmt.Errorf("could not read host partitions") } @@ -630,7 +629,7 @@ func NewUkiInstallSpec(cfg *Config) (*v1.InstallUkiSpec, error) { } // Calculate the partitions afterwards so they use the image sizes for the final partition sizes - spec.Partitions.EFI = &v1.Partition{ + spec.Partitions.EFI = &types.Partition{ FilesystemLabel: constants.EfiLabel, Size: constants.ImgSize * 5, // 15Gb for the EFI partition as default Name: constants.EfiPartName, @@ -638,7 +637,7 @@ func NewUkiInstallSpec(cfg *Config) (*v1.InstallUkiSpec, error) { MountPoint: constants.EfiDir, Flags: []string{"esp"}, } - spec.Partitions.OEM = &v1.Partition{ + spec.Partitions.OEM = &types.Partition{ FilesystemLabel: constants.OEMLabel, Size: constants.OEMSize, Name: constants.OEMPartName, @@ -646,7 +645,7 @@ func NewUkiInstallSpec(cfg *Config) (*v1.InstallUkiSpec, error) { MountPoint: constants.OEMDir, Flags: []string{}, } - spec.Partitions.Persistent = &v1.Partition{ + spec.Partitions.Persistent = &types.Partition{ FilesystemLabel: constants.PersistentLabel, Size: constants.PersistentSize, Name: constants.PersistentPartName, @@ -718,16 +717,11 @@ func NewUkiUpgradeSpec(cfg *Config) (*v1.UpgradeUkiSpec, error) { } // Get EFI partition - parts, err := partitions.GetAllPartitions() + spec.EfiPartition, err = partitions.GetEfiPartition(&cfg.Logger) if err != nil { return spec, fmt.Errorf("could not read host partitions") } - for _, p := range parts { - if p.FilesystemLabel == constants.EfiLabel { - spec.EfiPartition = p - break - } - } + // Get free size of partition var stat unix.Statfs_t _ = unix.Statfs(spec.EfiPartition.MountPoint, &stat) @@ -954,7 +948,7 @@ func BootedFrom(runner v1.Runner, label string) bool { } // HasSquashedRecovery returns true if a squashed recovery image is found in the system -func hasSquashedRecovery(config *Config, recovery *v1.Partition) (squashed bool, err error) { +func hasSquashedRecovery(config *Config, recovery *types.Partition) (squashed bool, err error) { mountPoint := recovery.MountPoint if mnt, _ := isMounted(config, recovery); !mnt { tmpMountDir, err := fsutils.TempDir(config.Fs, "", "elemental") @@ -979,7 +973,7 @@ func hasSquashedRecovery(config *Config, recovery *v1.Partition) (squashed bool, return fsutils.Exists(config.Fs, filepath.Join(mountPoint, "cOS", constants.RecoverySquashFile)) } -func isMounted(config *Config, part *v1.Partition) (bool, error) { +func isMounted(config *Config, part *types.Partition) (bool, error) { if part == nil { return false, fmt.Errorf("nil partition") } @@ -1022,29 +1016,21 @@ func detectLargestDevice() string { preferedDevice := "/dev/sda" maxSize := float64(0) - block, err := ghw.Block() - if err == nil { - for _, disk := range block.Disks { - size := float64(disk.SizeBytes) / float64(GiB) - if size > maxSize { - maxSize = size - preferedDevice = "/dev/" + disk.Name - } + for _, disk := range ghw.GetDisks(ghw.NewPaths(""), nil) { + size := float64(disk.SizeBytes) / float64(GiB) + if size > maxSize { + maxSize = size + preferedDevice = "/dev/" + disk.Name } } + return preferedDevice } // DetectPreConfiguredDevice returns a disk that has partitions labeled with // Kairos labels. It can be used to detect a pre-configured device. -func DetectPreConfiguredDevice(logger sdkTypes.KairosLogger) (string, error) { - block, err := ghw.Block() - if err != nil { - logger.Errorf("failed getting block devices: %s", err.Error()) - return "", err - } - - for _, disk := range block.Disks { +func DetectPreConfiguredDevice(logger types.KairosLogger) (string, error) { + for _, disk := range ghw.GetDisks(ghw.NewPaths(""), &logger) { for _, p := range disk.Partitions { if p.FilesystemLabel == "COS_STATE" { return filepath.Join("/", "dev", disk.Name), nil diff --git a/pkg/config/spec_test.go b/pkg/config/spec_test.go index 1439fad5..b5df2068 100644 --- a/pkg/config/spec_test.go +++ b/pkg/config/spec_test.go @@ -18,23 +18,21 @@ package config_test import ( "bytes" - "fmt" "os" "path/filepath" - sdkTypes "github.com/kairos-io/kairos-sdk/types" - "github.com/rs/zerolog" - - "github.com/jaypipes/ghw/pkg/block" - config "github.com/kairos-io/kairos-agent/v2/pkg/config" + "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" "github.com/kairos-io/kairos-sdk/collector" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/sanity-io/litter" + "github.com/rs/zerolog" "github.com/twpayne/go-vfs/v4/vfst" "k8s.io/mount-utils" ) @@ -73,7 +71,6 @@ var _ = Describe("Types", Label("types", "config"), func() { c.Install = &config.Install{} c.Bundles = config.Bundles{} c.Config = collector.Config{} - fmt.Println(litter.Sdump(c)) }) AfterEach(func() { cleanup() @@ -207,7 +204,6 @@ var _ = Describe("Types", Label("types", "config"), func() { spec, err := config.NewInstallSpec(c) Expect(err).ToNot(HaveOccurred()) Expect(spec.Firmware).To(Equal(v1.BIOS)) - fmt.Println(litter.Sdump(spec)) Expect(spec.Active.Source.IsEmpty()).To(BeFalse()) Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File)) Expect(spec.PartTable).To(Equal(v1.GPT)) @@ -217,7 +213,6 @@ var _ = Describe("Types", Label("types", "config"), func() { spec, err := config.NewInstallSpec(c) Expect(err).ToNot(HaveOccurred()) Expect(spec.Firmware).To(Equal(v1.BIOS)) - fmt.Println(litter.Sdump(spec)) Expect(spec.Active.Source.IsEmpty()).To(BeTrue()) Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File)) Expect(spec.PartTable).To(Equal(v1.GPT)) @@ -226,39 +221,39 @@ var _ = Describe("Types", Label("types", "config"), func() { }) Describe("ResetSpec", Label("reset"), func() { Describe("Successful executions", func() { - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: constants.EfiLabel, - Type: "vfat", + FS: "vfat", }, { Name: "device2", FilesystemLabel: constants.OEMLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: constants.RecoveryLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device4", FilesystemLabel: constants.StateLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: constants.PersistentLabel, - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() @@ -312,7 +307,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) Describe("Failures", func() { var bootedFrom string - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { bootedFrom = "" runner.SideEffect = func(cmd string, args ...string) ([]byte, error) { @@ -325,17 +320,17 @@ var _ = Describe("Types", Label("types", "config"), func() { } // Set an empty disk for tests, otherwise reads the hosts hardware - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device4", FilesystemLabel: constants.StateLabel, - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) @@ -354,11 +349,11 @@ var _ = Describe("Types", Label("types", "config"), func() { Expect(err.Error()).To(ContainSubstring("recovery partition not found")) }) It("fails to set defaults if no state partition detected", func() { - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{}, + Partitions: []*sdkTypes.Partition{}, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() defer ghwTest.Clean() @@ -384,40 +379,40 @@ var _ = Describe("Types", Label("types", "config"), func() { }) Describe("UpgradeSpec", Label("upgrade"), func() { Describe("Successful executions", func() { - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: constants.EfiLabel, - Type: "vfat", + FS: "vfat", }, { Name: "device2", FilesystemLabel: constants.OEMLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: constants.RecoveryLabel, - Type: "ext4", + FS: "ext4", MountPoint: constants.LiveDir, }, { Name: "device4", FilesystemLabel: constants.StateLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: constants.PersistentLabel, - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) @@ -454,7 +449,7 @@ var _ = Describe("Types", Label("types", "config"), func() { Describe("Config from cloudconfig", Label("cloud-config"), func() { var bootedFrom string var dir string - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { bootedFrom = "" @@ -494,37 +489,37 @@ cloud-init-paths: err = os.WriteFile(filepath.Join(dir, "cc.yaml"), ccdata, os.ModePerm) Expect(err).ToNot(HaveOccurred()) - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: constants.EfiLabel, - Type: "vfat", + FS: "vfat", }, { Name: "device2", FilesystemLabel: constants.OEMLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device3", FilesystemLabel: constants.RecoveryLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device4", FilesystemLabel: constants.StateLabel, - Type: "ext4", + FS: "ext4", }, { Name: "device5", FilesystemLabel: constants.PersistentLabel, - Type: "ext4", + FS: "ext4", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() @@ -683,7 +678,6 @@ var _ = Describe("GetSourceSize", Label("GetSourceSize"), func() { }) AfterEach(func() { - fmt.Println(memLog.String()) defer os.RemoveAll(tempDir) }) diff --git a/pkg/elemental/elemental.go b/pkg/elemental/elemental.go index 2ccd22e5..95359dcc 100644 --- a/pkg/elemental/elemental.go +++ b/pkg/elemental/elemental.go @@ -19,6 +19,7 @@ package elemental import ( "errors" "fmt" + "github.com/kairos-io/kairos-sdk/types" "os" "path/filepath" "syscall" @@ -46,7 +47,7 @@ func NewElemental(config *agentConfig.Config) *Elemental { } // FormatPartition will format an already existing partition -func (e *Elemental) FormatPartition(part *v1.Partition, opts ...string) error { +func (e *Elemental) FormatPartition(part *types.Partition, opts ...string) error { e.config.Logger.Infof("Formatting '%s' partition", part.FilesystemLabel) return partitioner.FormatDevice(e.config.Runner, part.Path, part.FS, part.FilesystemLabel, opts...) } @@ -125,7 +126,7 @@ func (e *Elemental) PartitionAndFormatDevice(i v1.SharedInstallSpec) error { // MountPartitions mounts configured partitions. Partitions with an unset mountpoint are not mounted. // Note umounts must be handled by caller logic. -func (e Elemental) MountPartitions(parts v1.PartitionList) error { +func (e Elemental) MountPartitions(parts types.PartitionList) error { e.config.Logger.Infof("Mounting disk partitions") var err error @@ -143,7 +144,7 @@ func (e Elemental) MountPartitions(parts v1.PartitionList) error { } // UnmountPartitions unmounts configured partitiosn. Partitions with an unset mountpoint are not unmounted. -func (e Elemental) UnmountPartitions(parts v1.PartitionList) error { +func (e Elemental) UnmountPartitions(parts types.PartitionList) error { e.config.Logger.Infof("Unmounting disk partitions") var err error errMsg := "" @@ -166,7 +167,7 @@ func (e Elemental) UnmountPartitions(parts v1.PartitionList) error { } // MountRWPartition mounts, or remounts if needed, a partition with RW permissions -func (e Elemental) MountRWPartition(part *v1.Partition) (umount func() error, err error) { +func (e Elemental) MountRWPartition(part *types.Partition) (umount func() error, err error) { if mnt, _ := utils.IsMounted(e.config, part); mnt { err = e.MountPartition(part, "remount", "rw") if err != nil { @@ -186,7 +187,7 @@ func (e Elemental) MountRWPartition(part *v1.Partition) (umount func() error, er } // MountPartition mounts a partition with the given mount options -func (e Elemental) MountPartition(part *v1.Partition, opts ...string) error { +func (e Elemental) MountPartition(part *types.Partition, opts ...string) error { e.config.Logger.Debugf("Mounting partition %s", part.FilesystemLabel) err := fsutils.MkdirAll(e.config.Fs, part.MountPoint, cnst.DirPerm) if err != nil { @@ -194,7 +195,7 @@ func (e Elemental) MountPartition(part *v1.Partition, opts ...string) error { } if part.Path == "" { // Lets error out only after 10 attempts to find the device - device, err := utils.GetDeviceByLabel(e.config.Runner, part.FilesystemLabel, 10) + device, err := utils.GetDeviceByLabel(e.config, part.FilesystemLabel, 10) if err != nil { e.config.Logger.Errorf("Could not find a device with label %s", part.FilesystemLabel) return err @@ -210,7 +211,7 @@ func (e Elemental) MountPartition(part *v1.Partition, opts ...string) error { } // UnmountPartition unmounts the given partition or does nothing if not mounted -func (e Elemental) UnmountPartition(part *v1.Partition) error { +func (e Elemental) UnmountPartition(part *types.Partition) error { if mnt, _ := utils.IsMounted(e.config, part); !mnt { e.config.Logger.Debugf("Not unmounting partition, %s doesn't look like mountpoint", part.MountPoint) return nil @@ -453,7 +454,7 @@ func (e *Elemental) CheckActiveDeployment(labels []string) bool { e.config.Logger.Infof("Checking for active deployment") for _, label := range labels { - found, _ := utils.GetDeviceByLabel(e.config.Runner, label, 1) + found, _ := utils.GetDeviceByLabel(e.config, label, 1) if found != "" { e.config.Logger.Debug("there is already an active deployment in the system") return true diff --git a/pkg/elemental/elemental_test.go b/pkg/elemental/elemental_test.go index a340c151..8e6226dc 100644 --- a/pkg/elemental/elemental_test.go +++ b/pkg/elemental/elemental_test.go @@ -20,12 +20,6 @@ import ( "bytes" "errors" "fmt" - "github.com/diskfs/go-diskfs" - "github.com/diskfs/go-diskfs/partition/gpt" - "github.com/gofrs/uuid" - "github.com/kairos-io/kairos-agent/v2/pkg/utils" - sdkTypes "github.com/kairos-io/kairos-sdk/types" - "github.com/sanity-io/litter" "golang.org/x/sys/unix" "os" "path/filepath" @@ -35,18 +29,22 @@ import ( "testing" agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - - "github.com/jaypipes/ghw/pkg/block" - cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/elemental" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/kairos-io/kairos-agent/v2/pkg/utils" + fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + + "github.com/diskfs/go-diskfs" + "github.com/diskfs/go-diskfs/partition/gpt" + "github.com/gofrs/uuid" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/sanity-io/litter" "github.com/twpayne/go-vfs/v4/vfst" - "k8s.io/mount-utils" ) func TestElementalSuite(t *testing.T) { @@ -343,7 +341,7 @@ var _ = Describe("Elemental", Label("elemental"), func() { Describe("FormatPartition", Label("FormatPartition", "partition", "format"), func() { It("Reformats an already existing partition", func() { el := elemental.NewElemental(config) - part := &v1.Partition{ + part := &sdkTypes.Partition{ Path: "/dev/device1", FS: "ext4", FilesystemLabel: "MY_LABEL", @@ -611,8 +609,8 @@ var _ = Describe("Elemental", Label("elemental"), func() { }) Describe("CheckActiveDeployment", Label("check"), func() { It("deployment found", func() { - ghwTest := v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ + ghwTest := ghwMock.GhwMock{} + disk := sdkTypes.Disk{Name: "device", Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: cnst.ActiveLabel, @@ -620,7 +618,7 @@ var _ = Describe("Elemental", Label("elemental"), func() { }} ghwTest.AddDisk(disk) ghwTest.CreateDevices() - defer ghwTest.Clean() + runner.ReturnValue = []byte( fmt.Sprintf( `{"blockdevices": [{"label": "%s", "type": "loop", "path": "/some/device"}]}`, @@ -629,6 +627,8 @@ var _ = Describe("Elemental", Label("elemental"), func() { ) e := elemental.NewElemental(config) Expect(e.CheckActiveDeployment([]string{cnst.ActiveLabel, cnst.PassiveLabel})).To(BeTrue()) + + ghwTest.Clean() }) It("Should not error out", func() { @@ -922,14 +922,3 @@ var _ = Describe("Elemental", Label("elemental"), func() { }) }) }) - -// PathInMountPoints will check if the given path is in the mountPoints list -func pathInMountPoints(mounter mount.Interface, path string) bool { - mountPoints, _ := mounter.List() - for _, m := range mountPoints { - if path == m.Path { - return true - } - } - return false -} diff --git a/pkg/partitioner/disk.go b/pkg/partitioner/disk.go index c0d09c35..0a28adf3 100644 --- a/pkg/partitioner/disk.go +++ b/pkg/partitioner/disk.go @@ -18,7 +18,7 @@ type Disk struct { logger sdkTypes.KairosLogger } -func (d *Disk) NewPartitionTable(partType string, parts v1.PartitionList) error { +func (d *Disk) NewPartitionTable(partType string, parts sdkTypes.PartitionList) error { d.logger.Infof("Creating partition table for partition type %s", partType) var table partition.Table switch partType { @@ -43,7 +43,7 @@ func getSectorEndFromSize(start, size uint64) uint64 { return (size / uint64(diskfs.SectorSize512)) + start - 1 } -func kairosPartsToDiskfsGPTParts(parts v1.PartitionList, diskSize int64) []*gpt.Partition { +func kairosPartsToDiskfsGPTParts(parts sdkTypes.PartitionList, diskSize int64) []*gpt.Partition { var partitions []*gpt.Partition for index, part := range parts { var start uint64 diff --git a/pkg/types/v1/config.go b/pkg/types/v1/config.go index ff3034dc..1c9ed07f 100644 --- a/pkg/types/v1/config.go +++ b/pkg/types/v1/config.go @@ -21,8 +21,9 @@ import ( "path/filepath" "sort" - "github.com/jaypipes/ghw" "github.com/kairos-io/kairos-agent/v2/pkg/constants" + "github.com/kairos-io/kairos-sdk/ghw" + "github.com/kairos-io/kairos-sdk/types" "gopkg.in/yaml.v3" ) @@ -47,7 +48,7 @@ type SharedInstallSpec interface { GetPartTable() string GetTarget() string GetPartitions() ElementalPartitions - GetExtraPartitions() PartitionList + GetExtraPartitions() types.PartitionList } // InstallSpec struct represents all the installation action details @@ -56,7 +57,7 @@ type InstallSpec struct { Firmware string `yaml:"firmware,omitempty" mapstructure:"firmware"` PartTable string `yaml:"part-table,omitempty" mapstructure:"part-table"` Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"` - ExtraPartitions PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` + ExtraPartitions types.PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` NoFormat bool `yaml:"no-format,omitempty" mapstructure:"no-format"` Force bool `yaml:"force,omitempty" mapstructure:"force"` CloudInit []string `yaml:"cloud-init,omitempty" mapstructure:"cloud-init"` @@ -76,19 +77,18 @@ type InstallSpec struct { // if unsolvable inconsistencies are found func (i *InstallSpec) Sanitize() error { // Check if the target device has mounted partitions - block, err := ghw.Block() - if err == nil { - for _, disk := range block.Disks { - if fmt.Sprintf("/dev/%s", disk.Name) == i.Target { - for _, p := range disk.Partitions { - if p.MountPoint != "" { - return fmt.Errorf("target device %s has mounted partitions, please unmount them before installing", i.Target) - } - } + for _, disk := range ghw.GetDisks(ghw.NewPaths(""), nil) { + if fmt.Sprintf("/dev/%s", disk.Name) == i.Target { + for _, p := range disk.Partitions { + if p.MountPoint != "" { + return fmt.Errorf("target device %s has mounted partitions, please unmount them before installing", i.Target) + } } + } } + if i.Active.Source.IsEmpty() && i.Iso == "" { return fmt.Errorf("undefined system source to install") } @@ -129,12 +129,12 @@ func (i *InstallSpec) Sanitize() error { return i.Partitions.SetFirmwarePartitions(i.Firmware, i.PartTable) } -func (i *InstallSpec) ShouldReboot() bool { return i.Reboot } -func (i *InstallSpec) ShouldShutdown() bool { return i.PowerOff } -func (i *InstallSpec) GetTarget() string { return i.Target } -func (i *InstallSpec) GetPartTable() string { return i.PartTable } -func (i *InstallSpec) GetPartitions() ElementalPartitions { return i.Partitions } -func (i *InstallSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions } +func (i *InstallSpec) ShouldReboot() bool { return i.Reboot } +func (i *InstallSpec) ShouldShutdown() bool { return i.PowerOff } +func (i *InstallSpec) GetTarget() string { return i.Target } +func (i *InstallSpec) GetPartTable() string { return i.PartTable } +func (i *InstallSpec) GetPartitions() ElementalPartitions { return i.Partitions } +func (i *InstallSpec) GetExtraPartitions() types.PartitionList { return i.ExtraPartitions } // ResetSpec struct represents all the reset action details type ResetSpec struct { @@ -220,63 +220,19 @@ func (r *EmptySpec) Sanitize() error { func (r *EmptySpec) ShouldReboot() bool { return false } func (r *EmptySpec) ShouldShutdown() bool { return false } -// Partition struct represents a partition with its commonly configurable values, size in MiB -type Partition struct { - Name string `yaml:"-"` - FilesystemLabel string `yaml:"label,omitempty" mapstructure:"label"` - Size uint `yaml:"size,omitempty" mapstructure:"size"` - FS string `yaml:"fs,omitempty" mapstrcuture:"fs"` - Flags []string `yaml:"flags,omitempty" mapstrcuture:"flags"` - MountPoint string `yaml:"-"` - Path string `yaml:"-"` - Disk string `yaml:"-"` -} - -type PartitionList []*Partition - -// GetByName gets a partitions by its name from the PartitionList -func (pl PartitionList) GetByName(name string) *Partition { - var part *Partition - - for _, p := range pl { - if p.Name == name { - part = p - if part.MountPoint != "" { - return part - } - } - } - return part -} - -// GetByLabel gets a partition by its label from the PartitionList -func (pl PartitionList) GetByLabel(label string) *Partition { - var part *Partition - - for _, p := range pl { - if p.FilesystemLabel == label { - part = p - if part.MountPoint != "" { - return part - } - } - } - return part -} - type ElementalPartitions struct { - BIOS *Partition `yaml:"-"` - EFI *Partition `yaml:"-"` - OEM *Partition `yaml:"oem,omitempty" mapstructure:"oem"` - Recovery *Partition `yaml:"recovery,omitempty" mapstructure:"recovery"` - State *Partition `yaml:"state,omitempty" mapstructure:"state"` - Persistent *Partition `yaml:"persistent,omitempty" mapstructure:"persistent"` + BIOS *types.Partition `yaml:"-"` + EFI *types.Partition `yaml:"-"` + OEM *types.Partition `yaml:"oem,omitempty" mapstructure:"oem"` + Recovery *types.Partition `yaml:"recovery,omitempty" mapstructure:"recovery"` + State *types.Partition `yaml:"state,omitempty" mapstructure:"state"` + Persistent *types.Partition `yaml:"persistent,omitempty" mapstructure:"persistent"` } // SetFirmwarePartitions sets firmware partitions for a given firmware and partition table type func (ep *ElementalPartitions) SetFirmwarePartitions(firmware string, partTable string) error { if firmware == EFI && partTable == GPT { - ep.EFI = &Partition{ + ep.EFI = &types.Partition{ FilesystemLabel: constants.EfiLabel, Size: constants.EfiSize, Name: constants.EfiPartName, @@ -286,7 +242,7 @@ func (ep *ElementalPartitions) SetFirmwarePartitions(firmware string, partTable } ep.BIOS = nil } else if firmware == BIOS && partTable == GPT { - ep.BIOS = &Partition{ + ep.BIOS = &types.Partition{ FilesystemLabel: constants.EfiLabel, Size: constants.BiosSize, Name: constants.BiosPartName, @@ -322,40 +278,41 @@ func (ep *ElementalPartitions) SetDefaultLabels() { // partitions list. First tries to match partitions by partition label, if not, // it tries to match partitions by default filesystem label // TODO find a way to map custom labels when partition labels are not available -func NewElementalPartitionsFromList(pl PartitionList) ElementalPartitions { +func NewElementalPartitionsFromList(pl types.PartitionList) ElementalPartitions { ep := ElementalPartitions{} - ep.BIOS = pl.GetByName(constants.BiosPartName) - ep.EFI = pl.GetByName(constants.EfiPartName) - if ep.EFI == nil { - ep.EFI = pl.GetByLabel(constants.EfiLabel) - } - ep.OEM = pl.GetByName(constants.OEMPartName) - if ep.OEM == nil { - ep.OEM = pl.GetByLabel(constants.OEMLabel) - } - ep.Recovery = pl.GetByName(constants.RecoveryPartName) - if ep.Recovery == nil { - ep.Recovery = pl.GetByLabel(constants.RecoveryLabel) - } - ep.State = pl.GetByName(constants.StatePartName) - if ep.State == nil { - ep.State = pl.GetByLabel(constants.StateLabel) - } - ep.Persistent = pl.GetByName(constants.PersistentPartName) - if ep.Persistent == nil { - ep.Persistent = pl.GetByLabel(constants.PersistentLabel) - } + ep.BIOS = GetPartitionByNameOrLabel(constants.BiosPartName, "", pl) + ep.EFI = GetPartitionByNameOrLabel(constants.EfiPartName, constants.EfiLabel, pl) + ep.OEM = GetPartitionByNameOrLabel(constants.OEMPartName, constants.OEMLabel, pl) + ep.Recovery = GetPartitionByNameOrLabel(constants.RecoveryPartName, constants.RecoveryLabel, pl) + ep.State = GetPartitionByNameOrLabel(constants.StatePartName, constants.StateLabel, pl) + ep.Persistent = GetPartitionByNameOrLabel(constants.PersistentPartName, constants.PersistentLabel, pl) return ep } +// GetPartitionByNameOrLabel will get a types.Partition from a types.PartitionList by name or label +func GetPartitionByNameOrLabel(name string, label string, partitionList types.PartitionList) *types.Partition { + var part *types.Partition + + for _, p := range partitionList { + if p.Name == name || p.FilesystemLabel == label { + part = p + if part.MountPoint != "" { + return part + } + break + } + } + return part +} + // PartitionsByInstallOrder sorts partitions according to the default layout // nil partitions are ignored // partition with 0 size is set last -func (ep ElementalPartitions) PartitionsByInstallOrder(extraPartitions PartitionList, excludes ...*Partition) PartitionList { - partitions := PartitionList{} - var lastPartition *Partition +func (ep ElementalPartitions) PartitionsByInstallOrder(extraPartitions types.PartitionList, excludes ...*types.Partition) types.PartitionList { + partitions := types.PartitionList{} + var lastPartition *types.Partition - inExcludes := func(part *Partition, list ...*Partition) bool { + inExcludes := func(part *types.Partition, list ...*types.Partition) bool { for _, p := range list { if part == p { return true @@ -412,12 +369,12 @@ func (ep ElementalPartitions) PartitionsByInstallOrder(extraPartitions Partition // PartitionsByMountPoint sorts partitions according to its mountpoint, ignores nil // partitions or partitions with an empty mountpoint -func (ep ElementalPartitions) PartitionsByMountPoint(descending bool, excludes ...*Partition) PartitionList { - mountPointKeys := map[string]*Partition{} +func (ep ElementalPartitions) PartitionsByMountPoint(descending bool, excludes ...*types.Partition) types.PartitionList { + mountPointKeys := map[string]*types.Partition{} mountPoints := []string{} - partitions := PartitionList{} + partitions := types.PartitionList{} - for _, p := range ep.PartitionsByInstallOrder([]*Partition{}, excludes...) { + for _, p := range ep.PartitionsByInstallOrder([]*types.Partition{}, excludes...) { if p.MountPoint != "" { mountPointKeys[p.MountPoint] = p mountPoints = append(mountPoints, p.MountPoint) @@ -513,7 +470,7 @@ type InstallUkiSpec struct { Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"` PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"` Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"` - ExtraPartitions PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` + ExtraPartitions types.PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` NoFormat bool `yaml:"no-format,omitempty" mapstructure:"no-format"` CloudInit []string `yaml:"cloud-init,omitempty" mapstructure:"cloud-init"` SkipEntries []string `yaml:"skip-entries,omitempty" mapstructure:"skip-entries"` @@ -524,19 +481,19 @@ func (i *InstallUkiSpec) Sanitize() error { return err } -func (i *InstallUkiSpec) ShouldReboot() bool { return i.Reboot } -func (i *InstallUkiSpec) ShouldShutdown() bool { return i.PowerOff } -func (i *InstallUkiSpec) GetTarget() string { return i.Target } -func (i *InstallUkiSpec) GetPartTable() string { return "gpt" } -func (i *InstallUkiSpec) GetPartitions() ElementalPartitions { return i.Partitions } -func (i *InstallUkiSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions } +func (i *InstallUkiSpec) ShouldReboot() bool { return i.Reboot } +func (i *InstallUkiSpec) ShouldShutdown() bool { return i.PowerOff } +func (i *InstallUkiSpec) GetTarget() string { return i.Target } +func (i *InstallUkiSpec) GetPartTable() string { return "gpt" } +func (i *InstallUkiSpec) GetPartitions() ElementalPartitions { return i.Partitions } +func (i *InstallUkiSpec) GetExtraPartitions() types.PartitionList { return i.ExtraPartitions } type UpgradeUkiSpec struct { - Entry string `yaml:"entry,omitempty" mapstructure:"entry"` - Active Image `yaml:"system,omitempty" mapstructure:"system"` - Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"` - PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"` - EfiPartition *Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"` + Entry string `yaml:"entry,omitempty" mapstructure:"entry"` + Active Image `yaml:"system,omitempty" mapstructure:"system"` + Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"` + PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"` + EfiPartition *types.Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"` } func (i *UpgradeUkiSpec) RecoveryUpgrade() bool { diff --git a/pkg/types/v1/config_test.go b/pkg/types/v1/config_test.go index 04dd2236..05bba2d6 100644 --- a/pkg/types/v1/config_test.go +++ b/pkg/types/v1/config_test.go @@ -17,6 +17,7 @@ limitations under the License. package v1_test import ( + sdkTypes "github.com/kairos-io/kairos-sdk/types" "path/filepath" "github.com/kairos-io/kairos-agent/v2/pkg/constants" @@ -27,12 +28,12 @@ import ( var _ = Describe("Types", Label("types", "config"), func() { Describe("ElementalPartitions", func() { - var p v1.PartitionList + var p sdkTypes.PartitionList var ep v1.ElementalPartitions BeforeEach(func() { ep = v1.ElementalPartitions{} - p = v1.PartitionList{ - &v1.Partition{ + p = sdkTypes.PartitionList{ + &sdkTypes.Partition{ FilesystemLabel: "COS_OEM", Size: 0, Name: "oem", @@ -42,7 +43,7 @@ var _ = Describe("Types", Label("types", "config"), func() { Path: "", Disk: "", }, - &v1.Partition{ + &sdkTypes.Partition{ FilesystemLabel: "COS_CUSTOM", Size: 0, Name: "persistent", @@ -52,7 +53,7 @@ var _ = Describe("Types", Label("types", "config"), func() { Path: "", Disk: "", }, - &v1.Partition{ + &sdkTypes.Partition{ FilesystemLabel: "SOMETHING", Size: 0, Name: "somethingelse", @@ -77,7 +78,7 @@ var _ = Describe("Types", Label("types", "config"), func() { Expect(ep.EFI == nil && ep.BIOS != nil).To(BeTrue()) }) It("sets firmware partitions on msdos", func() { - ep.State = &v1.Partition{} + ep.State = &sdkTypes.Partition{} Expect(ep.EFI == nil && ep.BIOS == nil).To(BeTrue()) err := ep.SetFirmwarePartitions(v1.BIOS, v1.MSDOS) Expect(err).ShouldNot(HaveOccurred()) @@ -101,15 +102,15 @@ var _ = Describe("Types", Label("types", "config"), func() { Describe("returns a partition list by install order", func() { It("with no extra parts", func() { ep := v1.NewElementalPartitionsFromList(p) - lst := ep.PartitionsByInstallOrder([]*v1.Partition{}) + lst := ep.PartitionsByInstallOrder([]*sdkTypes.Partition{}) Expect(len(lst)).To(Equal(2)) Expect(lst[0].Name == "oem").To(BeTrue()) Expect(lst[1].Name == "persistent").To(BeTrue()) }) It("with extra parts with size > 0", func() { ep := v1.NewElementalPartitionsFromList(p) - var extraParts []*v1.Partition - extraParts = append(extraParts, &v1.Partition{Name: "extra", Size: 5}) + var extraParts []*sdkTypes.Partition + extraParts = append(extraParts, &sdkTypes.Partition{Name: "extra", Size: 5}) lst := ep.PartitionsByInstallOrder(extraParts) Expect(len(lst)).To(Equal(3)) @@ -119,8 +120,8 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("with extra part with size == 0 and persistent.Size == 0", func() { ep := v1.NewElementalPartitionsFromList(p) - var extraParts []*v1.Partition - extraParts = append(extraParts, &v1.Partition{Name: "extra", Size: 0}) + var extraParts []*sdkTypes.Partition + extraParts = append(extraParts, &sdkTypes.Partition{Name: "extra", Size: 0}) lst := ep.PartitionsByInstallOrder(extraParts) // Should ignore the wrong partition had have the persistent over it Expect(len(lst)).To(Equal(2)) @@ -130,8 +131,8 @@ var _ = Describe("Types", Label("types", "config"), func() { It("with extra part with size == 0 and persistent.Size > 0", func() { ep := v1.NewElementalPartitionsFromList(p) ep.Persistent.Size = 10 - var extraParts []*v1.Partition - extraParts = append(extraParts, &v1.Partition{Name: "extra", FilesystemLabel: "LABEL", Size: 0}) + var extraParts []*sdkTypes.Partition + extraParts = append(extraParts, &sdkTypes.Partition{Name: "extra", FilesystemLabel: "LABEL", Size: 0}) lst := ep.PartitionsByInstallOrder(extraParts) // Will have our size == 0 partition the latest Expect(len(lst)).To(Equal(3)) @@ -142,9 +143,9 @@ var _ = Describe("Types", Label("types", "config"), func() { It("with several extra parts with size == 0 and persistent.Size > 0", func() { ep := v1.NewElementalPartitionsFromList(p) ep.Persistent.Size = 10 - var extraParts []*v1.Partition - extraParts = append(extraParts, &v1.Partition{Name: "extra1", Size: 0}) - extraParts = append(extraParts, &v1.Partition{Name: "extra2", Size: 0}) + var extraParts []*sdkTypes.Partition + extraParts = append(extraParts, &sdkTypes.Partition{Name: "extra1", Size: 0}) + extraParts = append(extraParts, &sdkTypes.Partition{Name: "extra2", Size: 0}) lst := ep.PartitionsByInstallOrder(extraParts) // Should ignore the wrong partition had have the first partition with size 0 added last Expect(len(lst)).To(Equal(3)) @@ -170,10 +171,10 @@ var _ = Describe("Types", Label("types", "config"), func() { }) }) Describe("PartitionList", func() { - var p v1.PartitionList + var p sdkTypes.PartitionList BeforeEach(func() { - p = v1.PartitionList{ - &v1.Partition{ + p = sdkTypes.PartitionList{ + &sdkTypes.Partition{ FilesystemLabel: "ONE", Size: 0, Name: "one", @@ -183,7 +184,7 @@ var _ = Describe("Types", Label("types", "config"), func() { Path: "", Disk: "", }, - &v1.Partition{ + &sdkTypes.Partition{ FilesystemLabel: "TWO", Size: 0, Name: "two", @@ -196,7 +197,7 @@ var _ = Describe("Types", Label("types", "config"), func() { } }) It("returns partitions by name", func() { - Expect(p.GetByName("two")).To(Equal(&v1.Partition{ + Expect(v1.GetPartitionByNameOrLabel("two", "", p)).To(Equal(&sdkTypes.Partition{ FilesystemLabel: "TWO", Size: 0, Name: "two", @@ -208,10 +209,10 @@ var _ = Describe("Types", Label("types", "config"), func() { })) }) It("returns nil if partiton name not found", func() { - Expect(p.GetByName("nonexistent")).To(BeNil()) + Expect(v1.GetPartitionByNameOrLabel("dsd", "nonexistent", p)).To(BeNil()) }) It("returns partitions by filesystem label", func() { - Expect(p.GetByLabel("TWO")).To(Equal(&v1.Partition{ + Expect(v1.GetPartitionByNameOrLabel("", "TWO", p)).To(Equal(&sdkTypes.Partition{ FilesystemLabel: "TWO", Size: 0, Name: "two", @@ -223,7 +224,7 @@ var _ = Describe("Types", Label("types", "config"), func() { })) }) It("returns nil if filesystem label not found", func() { - Expect(p.GetByName("nonexistent")).To(BeNil()) + Expect(v1.GetPartitionByNameOrLabel("sd", "nonexistent", p)).To(BeNil()) }) }) Describe("Specs", func() { @@ -241,11 +242,11 @@ var _ = Describe("Types", Label("types", "config"), func() { Source: v1.NewEmptySrc(), }, Partitions: v1.ElementalPartitions{ - OEM: &v1.Partition{}, - Recovery: &v1.Partition{}, - Persistent: &v1.Partition{}, + OEM: &sdkTypes.Partition{}, + Recovery: &sdkTypes.Partition{}, + Persistent: &sdkTypes.Partition{}, }, - ExtraPartitions: v1.PartitionList{}, + ExtraPartitions: sdkTypes.PartitionList{}, } }) It("fails with empty source", func() { @@ -261,7 +262,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("passes if state and source are ready", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } err := spec.Sanitize() @@ -269,7 +270,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("fills the spec with defaults (BIOS)", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } spec.Firmware = constants.BiosPartName @@ -292,7 +293,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("fills the spec with defaults (EFI)", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } spec.Firmware = constants.EfiPartName @@ -319,16 +320,16 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("Cannot add extra partitions with 0 size + persistent with 0 size", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } - spec.Partitions.Persistent = &v1.Partition{ + spec.Partitions.Persistent = &sdkTypes.Partition{ Size: 0, } spec.Firmware = constants.BiosPartName spec.PartTable = constants.GPT - spec.ExtraPartitions = v1.PartitionList{ - &v1.Partition{ + spec.ExtraPartitions = sdkTypes.PartitionList{ + &sdkTypes.Partition{ Size: 0, }, } @@ -338,19 +339,19 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("Cannot add more than 1 extra partition with 0 size", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } - spec.Partitions.Persistent = &v1.Partition{ + spec.Partitions.Persistent = &sdkTypes.Partition{ Size: 100, } spec.Firmware = constants.BiosPartName spec.PartTable = constants.GPT - spec.ExtraPartitions = v1.PartitionList{ - &v1.Partition{ + spec.ExtraPartitions = sdkTypes.PartitionList{ + &sdkTypes.Partition{ Size: 0, }, - &v1.Partition{ + &sdkTypes.Partition{ Size: 0, }, } @@ -360,16 +361,16 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("Can add 1 extra partition with 0 size", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } - spec.Partitions.Persistent = &v1.Partition{ + spec.Partitions.Persistent = &sdkTypes.Partition{ Size: 100, } spec.Firmware = constants.BiosPartName spec.PartTable = constants.GPT - spec.ExtraPartitions = v1.PartitionList{ - &v1.Partition{ + spec.ExtraPartitions = sdkTypes.PartitionList{ + &sdkTypes.Partition{ Size: 0, }, } @@ -399,12 +400,12 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("passes if state and source are ready", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } - spec.Partitions.OEM = &v1.Partition{} - spec.Partitions.Recovery = &v1.Partition{} - spec.Partitions.Persistent = &v1.Partition{} + spec.Partitions.OEM = &sdkTypes.Partition{} + spec.Partitions.Recovery = &sdkTypes.Partition{} + spec.Partitions.Persistent = &sdkTypes.Partition{} err := spec.Sanitize() Expect(err).ToNot(HaveOccurred()) }) @@ -436,7 +437,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("passes if state and source are ready", func() { spec.Active.Source = v1.NewFileSrc("/tmp") - spec.Partitions.State = &v1.Partition{ + spec.Partitions.State = &sdkTypes.Partition{ MountPoint: "/tmp", } err := spec.Sanitize() @@ -460,7 +461,7 @@ var _ = Describe("Types", Label("types", "config"), func() { }) It("passes if state and source are ready", func() { spec.Recovery.Source = v1.NewFileSrc("/tmp") - spec.Partitions.Recovery = &v1.Partition{ + spec.Partitions.Recovery = &sdkTypes.Partition{ MountPoint: "/tmp", } err := spec.Sanitize() diff --git a/pkg/utils/common.go b/pkg/utils/common.go index dff109e3..abc11b51 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -35,6 +35,7 @@ import ( sdkTypes "github.com/kairos-io/kairos-sdk/types" "github.com/kairos-io/kairos-sdk/state" + "github.com/kairos-io/kairos-sdk/types" agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" @@ -55,31 +56,21 @@ func CommandExists(command string) bool { // GetDeviceByLabel will try to return the device that matches the given label. // attempts value sets the number of attempts to find the device, it // waits a second between attempts. -func GetDeviceByLabel(runner v1.Runner, label string, attempts int) (string, error) { - part, err := GetFullDeviceByLabel(runner, label, attempts) - if err != nil { - return "", err - } - return part.Path, nil -} - -// GetFullDeviceByLabel works like GetDeviceByLabel, but it will try to get as much info as possible from the existing -// partition and return a v1.Partition object -func GetFullDeviceByLabel(runner v1.Runner, label string, attempts int) (*v1.Partition, error) { +func GetDeviceByLabel(config *agentConfig.Config, label string, attempts int) (string, error) { for tries := 0; tries < attempts; tries++ { - _, _ = runner.Run("udevadm", "trigger") - _, _ = runner.Run("udevadm", "settle") - parts, err := partitions.GetAllPartitions() + _, _ = config.Runner.Run("udevadm", "trigger") + _, _ = config.Runner.Run("udevadm", "settle") + parts, err := partitions.GetAllPartitions(&config.Logger) if err != nil { - return nil, err + return "", err } - part := parts.GetByLabel(label) + part := v1.GetPartitionByNameOrLabel("", label, parts) if part != nil { - return part, nil + return part.Path, nil } time.Sleep(1 * time.Second) } - return nil, errors.New("no device found") + return "", errors.New("no device found") } // CopyFile Copies source file to target file using Fs interface. If target @@ -310,7 +301,7 @@ func LoadEnvFile(fs v1.FS, file string) (map[string]string, error) { return envMap, err } -func IsMounted(config *agentConfig.Config, part *v1.Partition) (bool, error) { +func IsMounted(config *agentConfig.Config, part *types.Partition) (bool, error) { if part == nil { return false, fmt.Errorf("nil partition") } @@ -343,7 +334,7 @@ func GetTempDir(config *agentConfig.Config, suffix string) string { config.Logger.Debugf("Got tmpdir from TMPDIR var: %s", dir) return filepath.Join(dir, elementalTmpDir) } - parts, err := partitions.GetAllPartitions() + parts, err := partitions.GetAllPartitions(&config.Logger) if err != nil { config.Logger.Debug("Could not get partitions, defaulting to /tmp") return filepath.Join("/", "tmp", elementalTmpDir) diff --git a/pkg/utils/partitions/getpartitions.go b/pkg/utils/partitions/getpartitions.go index 755d2580..7f25d089 100644 --- a/pkg/utils/partitions/getpartitions.go +++ b/pkg/utils/partitions/getpartitions.go @@ -25,40 +25,20 @@ import ( "strconv" "strings" - "github.com/jaypipes/ghw" - "github.com/jaypipes/ghw/pkg/block" - "github.com/jaypipes/ghw/pkg/context" - "github.com/jaypipes/ghw/pkg/linuxpath" - ghwUtil "github.com/jaypipes/ghw/pkg/util" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/kairos-io/kairos-sdk/ghw" + "github.com/kairos-io/kairos-sdk/types" log "github.com/sirupsen/logrus" ) -// ghwPartitionToInternalPartition transforms a block.Partition from ghw lib to our v1.Partition type -func ghwPartitionToInternalPartition(partition *block.Partition) *v1.Partition { - return &v1.Partition{ - FilesystemLabel: partition.FilesystemLabel, - Size: uint(partition.SizeBytes / (1024 * 1024)), // Converts B to MB - Name: partition.Name, - FS: partition.Type, - Flags: nil, - MountPoint: partition.MountPoint, - Path: filepath.Join("/dev", partition.Name), - Disk: filepath.Join("/dev", partition.Disk.Name), - } -} - // GetAllPartitions returns all partitions in the system for all disks -func GetAllPartitions() (v1.PartitionList, error) { - var parts []*v1.Partition - blockDevices, err := block.New(ghw.WithDisableTools(), ghw.WithDisableWarnings()) - if err != nil { - return nil, err - } - for _, d := range blockDevices.Disks { +func GetAllPartitions(logger *types.KairosLogger) (types.PartitionList, error) { + var parts []*types.Partition + + for _, d := range ghw.GetDisks(ghw.NewPaths(""), logger) { for _, part := range d.Partitions { - parts = append(parts, ghwPartitionToInternalPartition(part)) + parts = append(parts, part) } } return parts, nil @@ -117,39 +97,15 @@ func parseMountEntry(line string) (string, string) { return fields[0], mp } -// GetPartitionFS gets the FS of a partition given -func GetPartitionFS(partition string) (string, error) { - // We want to have the device always prefixed with a /dev - if !strings.HasPrefix(partition, "/dev") { - partition = filepath.Join("/dev", partition) - } - blockDevices, err := block.New(ghw.WithDisableTools(), ghw.WithDisableWarnings()) - if err != nil { - return "", err - } - - for _, disk := range blockDevices.Disks { - for _, part := range disk.Partitions { - if filepath.Join("/dev", part.Name) == partition { - if part.Type == ghwUtil.UNKNOWN { - return "", fmt.Errorf("could not find filesystem for partition %s", partition) - } - return part.Type, nil - } - } - } - return "", fmt.Errorf("could not find filesystem for partition %s", partition) -} - // GetPartitionViaDM tries to get the partition via devicemapper for reset // We only need to get all this info due to the fS that we need to use to format the partition // Otherwise we could just format with the label ¯\_(ツ)_/¯ // TODO: store info about persistent and oem in the state.yaml so we can directly load it -func GetPartitionViaDM(fs v1.FS, label string) *v1.Partition { - var part *v1.Partition +func GetPartitionViaDM(fs v1.FS, label string) *types.Partition { + var part *types.Partition rootPath, _ := fs.RawPath("/") - ctx := context.New(ghw.WithDisableTools(), ghw.WithDisableWarnings(), ghw.WithChroot(rootPath)) - lp := linuxpath.New(ctx) + lp := ghw.NewPaths(rootPath) + devices, _ := fs.ReadDir(lp.SysBlock) for _, dev := range devices { if !strings.HasPrefix(dev.Name(), "dm-") { @@ -178,7 +134,7 @@ func GetPartitionViaDM(fs v1.FS, label string) *v1.Partition { partitionFS := udevInfo["ID_FS_TYPE"] partitionName := udevInfo["DM_LV_NAME"] - part = &v1.Partition{ + part = &types.Partition{ Name: partitionName, FilesystemLabel: label, FS: partitionFS, @@ -268,18 +224,17 @@ func GetPartitionViaDM(fs v1.FS, label string) *v1.Partition { } // GetEfiPartition returns the EFI partition by looking for the partition with the label "COS_GRUB" -func GetEfiPartition() (*v1.Partition, error) { - var efiPartition *v1.Partition - parts, err := GetAllPartitions() - if err != nil { - return efiPartition, fmt.Errorf("could not read host partitions") - } - for _, p := range parts { - if p.FilesystemLabel == constants.EfiLabel { - efiPartition = p - break +func GetEfiPartition(logger *types.KairosLogger) (*types.Partition, error) { + var efiPartition *types.Partition + for _, d := range ghw.GetDisks(ghw.NewPaths(""), logger) { + for _, part := range d.Partitions { + if part.FilesystemLabel == constants.EfiLabel { + efiPartition = part + break + } } } + if efiPartition == nil { return efiPartition, fmt.Errorf("could not find EFI partition") } diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index a794795e..4f428f5b 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -20,22 +20,22 @@ import ( "bytes" "errors" "fmt" - "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" - "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions" - sdkTypes "github.com/kairos-io/kairos-sdk/types" "io/fs" "os" "path/filepath" "strings" "time" - "github.com/jaypipes/ghw/pkg/block" - agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" "github.com/kairos-io/kairos-agent/v2/pkg/utils" + "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" + "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks" + sdkTypes "github.com/kairos-io/kairos-sdk/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs/v4" @@ -189,8 +189,8 @@ var _ = Describe("Utils", Label("utils"), func() { } }) It("returns found device", func() { - ghwTest := v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ + ghwTest := ghwMock.GhwMock{} + disk := sdkTypes.Disk{Name: "device", Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "FAKE", @@ -199,24 +199,24 @@ var _ = Describe("Utils", Label("utils"), func() { ghwTest.AddDisk(disk) ghwTest.CreateDevices() defer ghwTest.Clean() - out, err := utils.GetDeviceByLabel(runner, "FAKE", 1) + out, err := utils.GetDeviceByLabel(config, "FAKE", 1) Expect(err).To(BeNil()) Expect(out).To(Equal("/dev/device1")) Expect(runner.CmdsMatch(cmds)).To(BeNil()) }) It("fails if no device is found in two attempts", func() { - _, err := utils.GetDeviceByLabel(runner, "FAKE", 2) + _, err := utils.GetDeviceByLabel(config, "FAKE", 2) Expect(err).NotTo(BeNil()) Expect(runner.CmdsMatch(append(cmds, cmds...))).To(BeNil()) }) }) Describe("GetAllPartitions", Label("lsblk", "partitions"), func() { - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { - ghwTest = v1mock.GhwMock{} - disk1 := block.Disk{ + ghwTest = ghwMock.GhwMock{} + disk1 := sdkTypes.Disk{ Name: "sda", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "sda1Test", }, @@ -225,9 +225,9 @@ var _ = Describe("Utils", Label("utils"), func() { }, }, } - disk2 := block.Disk{ + disk2 := sdkTypes.Disk{ Name: "sdb", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "sdb1Test", }, @@ -241,7 +241,7 @@ var _ = Describe("Utils", Label("utils"), func() { ghwTest.Clean() }) It("returns all found partitions", func() { - parts, err := partitions.GetAllPartitions() + parts, err := partitions.GetAllPartitions(&logger) Expect(err).To(BeNil()) var partNames []string for _, p := range parts { @@ -252,40 +252,6 @@ var _ = Describe("Utils", Label("utils"), func() { Expect(partNames).To(ContainElement("sdb1Test")) }) }) - Describe("GetPartitionFS", Label("lsblk", "partitions"), func() { - var ghwTest v1mock.GhwMock - BeforeEach(func() { - ghwTest = v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ - { - Name: "device1", - Type: "xfs", - }, - { - Name: "device2", - }, - }} - ghwTest.AddDisk(disk) - ghwTest.CreateDevices() - }) - AfterEach(func() { - ghwTest.Clean() - }) - It("returns found device with plain partition device", func() { - pFS, err := partitions.GetPartitionFS("device1") - Expect(err).To(BeNil()) - Expect(pFS).To(Equal("xfs")) - }) - It("returns found device with full partition device", func() { - pFS, err := partitions.GetPartitionFS("/dev/device1") - Expect(err).To(BeNil()) - Expect(pFS).To(Equal("xfs")) - }) - It("fails if no partition is found", func() { - _, err := partitions.GetPartitionFS("device2") - Expect(err).NotTo(BeNil()) - }) - }) Describe("CosignVerify", Label("cosign"), func() { It("runs a keyless verification", func() { _, err := utils.CosignVerify(fs, runner, "some/image:latest", "") @@ -320,57 +286,6 @@ var _ = Describe("Utils", Label("utils"), func() { Expect(duration.Seconds() >= 3).To(BeTrue()) }) }) - Describe("GetFullDeviceByLabel", Label("lsblk", "partitions"), func() { - var cmds [][]string - BeforeEach(func() { - cmds = [][]string{ - {"udevadm", "trigger"}, - {"udevadm", "settle"}, - } - }) - It("returns found v1.Partition", func() { - var flags []string - ghwTest := v1mock.GhwMock{} - disk := block.Disk{Name: "device", Partitions: []*block.Partition{ - { - Name: "device1", - FilesystemLabel: "FAKE", - Type: "fakefs", - MountPoint: "/mnt/fake", - SizeBytes: 0, - }, - }} - ghwTest.AddDisk(disk) - ghwTest.CreateDevices() - defer ghwTest.Clean() - out, err := utils.GetFullDeviceByLabel(runner, "FAKE", 1) - Expect(err).To(BeNil()) - Expect(out.FilesystemLabel).To(Equal("FAKE")) - Expect(out.Size).To(Equal(uint(0))) - Expect(out.FS).To(Equal("fakefs")) - Expect(out.MountPoint).To(Equal("/mnt/fake")) - Expect(out.Flags).To(Equal(flags)) - Expect(runner.CmdsMatch(cmds)).To(BeNil()) - }) - It("fails to run lsblk", func() { - runner.ReturnError = errors.New("failed running lsblk") - _, err := utils.GetFullDeviceByLabel(runner, "FAKE", 1) - Expect(err).To(HaveOccurred()) - Expect(runner.CmdsMatch(cmds)).To(BeNil()) - }) - It("fails to parse json output", func() { - runner.ReturnValue = []byte(`{"invalidobject": []}`) - _, err := utils.GetFullDeviceByLabel(runner, "FAKE", 1) - Expect(err).To(HaveOccurred()) - Expect(runner.CmdsMatch(cmds)).To(BeNil()) - }) - It("fails if no device is found in two attempts", func() { - runner.ReturnValue = []byte(`{"blockdevices":[{"label":"something","type": "part"}]}`) - _, err := utils.GetFullDeviceByLabel(runner, "FAKE", 2) - Expect(err).To(HaveOccurred()) - Expect(runner.CmdsMatch(append(cmds, cmds...))).To(BeNil()) - }) - }) Describe("CopyFile", Label("CopyFile"), func() { It("Copies source file to target file", func() { err := fsutils.MkdirAll(fs, "/some", constants.DirPerm) @@ -967,7 +882,7 @@ var _ = Describe("Utils", Label("utils"), func() { }) Describe("IsMounted", Label("ismounted"), func() { It("checks a mounted partition", func() { - part := &v1.Partition{ + part := &sdkTypes.Partition{ MountPoint: "/some/mountpoint", } err := mounter.Mount("/some/device", "/some/mountpoint", "auto", []string{}) @@ -977,7 +892,7 @@ var _ = Describe("Utils", Label("utils"), func() { Expect(mnt).To(BeTrue()) }) It("checks a not mounted partition", func() { - part := &v1.Partition{ + part := &sdkTypes.Partition{ MountPoint: "/some/mountpoint", } mnt, err := utils.IsMounted(config, part) @@ -985,7 +900,7 @@ var _ = Describe("Utils", Label("utils"), func() { Expect(mnt).To(BeFalse()) }) It("checks a partition without mountpoint", func() { - part := &v1.Partition{} + part := &sdkTypes.Partition{} mnt, err := utils.IsMounted(config, part) Expect(err).ShouldNot(HaveOccurred()) Expect(mnt).To(BeFalse()) @@ -1071,33 +986,36 @@ var _ = Describe("Utils", Label("utils"), func() { }) }) Describe("GetEfiPartition", func() { - var ghwTest v1mock.GhwMock + var ghwTest ghwMock.GhwMock BeforeEach(func() { - mainDisk := block.Disk{ + mainDisk := sdkTypes.Disk{ Name: "device", - Partitions: []*block.Partition{ + Partitions: []*sdkTypes.Partition{ { Name: "device1", FilesystemLabel: "COS_GRUB", - Type: "ext4", + FS: "ext4", MountPoint: "/efi", }, }, } - ghwTest = v1mock.GhwMock{} + ghwTest = ghwMock.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() }) + AfterEach(func() { + ghwTest.Clean() + }) It("returns the efi partition", func() { - efi, err := partitions.GetEfiPartition() + efi, err := partitions.GetEfiPartition(&logger) Expect(err).ToNot(HaveOccurred()) Expect(efi.FilesystemLabel).To(Equal("COS_GRUB")) Expect(efi.Name).To(Equal("device1")) // Just to make sure its our mocked system }) It("fails to find the efi partition", func() { ghwTest.Clean() // Remove the disk - efi, err := partitions.GetEfiPartition() + efi, err := partitions.GetEfiPartition(&logger) Expect(err).To(HaveOccurred()) Expect(efi).To(BeNil()) }) diff --git a/tests/mocks/ghw_mock.go b/tests/mocks/ghw_mock.go deleted file mode 100644 index 6be7f49b..00000000 --- a/tests/mocks/ghw_mock.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package mocks - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/jaypipes/ghw/pkg/block" - "github.com/jaypipes/ghw/pkg/context" - "github.com/jaypipes/ghw/pkg/linuxpath" -) - -// GhwMock is used to construct a fake disk to present to ghw when scanning block devices -// The way this works is ghw will use the existing files in the system to determine the different disks, partitions and -// mountpoints. It uses /sys/block, /proc/self/mounts and /run/udev/data to gather everything -// It also has an entrypoint to overwrite the root dir from which the paths are constructed so that allows us to override -// it easily and make it read from a different location. -// This mock is used to construct a fake FS with all its needed files on a different chroot and just add a Disk with its -// partitions and let the struct do its thing creating files and mountpoints and such -// You can even just pass no disks to simulate a system in which there is no disk/no cos partitions -type GhwMock struct { - chroot string - paths *linuxpath.Paths - disks []block.Disk - mounts []string -} - -// AddDisk adds a disk to GhwMock -func (g *GhwMock) AddDisk(disk block.Disk) { - g.disks = append(g.disks, disk) -} - -// AddPartitionToDisk will add a partition to the given disk and call Clean+CreateDevices, so we recreate all files -// It makes no effort checking if the disk exists -func (g *GhwMock) AddPartitionToDisk(diskName string, partition *block.Partition) { - for _, disk := range g.disks { - if disk.Name == diskName { - disk.Partitions = append(disk.Partitions, partition) - g.Clean() - g.CreateDevices() - } - } -} - -// CreateDevices will create a new context and paths for ghw using the Chroot value as base, then set the env var GHW_ROOT so the -// ghw library picks that up and then iterate over the disks and partitions and create the necessary files -func (g *GhwMock) CreateDevices() { - d, _ := os.MkdirTemp("", "ghwmock") - g.chroot = d - ctx := context.New() - ctx.Chroot = d - g.paths = linuxpath.New(ctx) - _ = os.Setenv("GHW_CHROOT", g.chroot) - // Create the /sys/block dir - _ = os.MkdirAll(g.paths.SysBlock, 0755) - // Create the /run/udev/data dir - _ = os.MkdirAll(g.paths.RunUdevData, 0755) - // Create only the /proc/self dir, we add the mounts file afterwards - procDir, _ := filepath.Split(g.paths.ProcMounts) - _ = os.MkdirAll(procDir, 0755) - - for indexDisk, disk := range g.disks { - // For each dir we create the /sys/block/DISK_NAME - diskPath := filepath.Join(g.paths.SysBlock, disk.Name) - _ = os.Mkdir(diskPath, 0755) - for indexPart, partition := range disk.Partitions { - // For each partition we create the /sys/block/DISK_NAME/PARTITION_NAME - _ = os.Mkdir(filepath.Join(diskPath, partition.Name), 0755) - // Create the /sys/block/DISK_NAME/PARTITION_NAME/dev file which contains the major:minor of the partition - _ = os.WriteFile(filepath.Join(diskPath, partition.Name, "dev"), []byte(fmt.Sprintf("%d:6%d\n", indexDisk, indexPart)), 0644) - // Create the /run/udev/data/bMAJOR:MINOR file with the data inside to mimic the udev database - data := []string{fmt.Sprintf("E:ID_FS_LABEL=%s\n", partition.FilesystemLabel)} - if partition.Type != "" { - data = append(data, fmt.Sprintf("E:ID_FS_TYPE=%s\n", partition.Type)) - } - _ = os.WriteFile(filepath.Join(g.paths.RunUdevData, fmt.Sprintf("b%d:6%d", indexDisk, indexPart)), []byte(strings.Join(data, "")), 0644) - // If we got a mountpoint, add it to our fake /proc/self/mounts - if partition.MountPoint != "" { - // Check if the partition has a fs, otherwise default to ext4 - if partition.Type == "" { - partition.Type = "ext4" - } - // Prepare the g.mounts with all the mount lines - g.mounts = append( - g.mounts, - fmt.Sprintf("%s %s %s ro,relatime 0 0\n", filepath.Join("/dev", partition.Name), partition.MountPoint, partition.Type)) - } - } - } - // Finally, write all the mounts - _ = os.WriteFile(g.paths.ProcMounts, []byte(strings.Join(g.mounts, "")), 0644) -} - -// RemoveDisk will remove the files for a disk. It makes no effort to check if the disk exists or not -func (g *GhwMock) RemoveDisk(disk string) { - // This could be simpler I think, just removing the /sys/block/DEVICE should make ghw not find anything and not search - // for partitions, but just in case do it properly - var newMounts []string - diskPath := filepath.Join(g.paths.SysBlock, disk) - _ = os.RemoveAll(diskPath) - - // Try to find any mounts that match the disk given and remove them from the mounts - for _, mount := range g.mounts { - fields := strings.Fields(mount) - // If first field does not contain the /dev/DEVICE, add it to the newmounts - if !strings.Contains(fields[0], filepath.Join("/dev", disk)) { - newMounts = append(newMounts, mount) - } - } - g.mounts = newMounts - // Write the mounts again - _ = os.WriteFile(g.paths.ProcMounts, []byte(strings.Join(g.mounts, "")), 0644) -} - -// RemovePartitionFromDisk will remove the files for a partition -// It makes no effort checking if the disk/partition/files exist -func (g *GhwMock) RemovePartitionFromDisk(diskName string, partitionName string) { - var newMounts []string - diskPath := filepath.Join(g.paths.SysBlock, diskName) - // Read the dev major:minor - devName, _ := os.ReadFile(filepath.Join(diskPath, partitionName, "dev")) - // Remove the MAJOR:MINOR file from the udev database - _ = os.RemoveAll(filepath.Join(g.paths.RunUdevData, fmt.Sprintf("b%s", devName))) - // Remove the /sys/block/DISK/PARTITION dir - _ = os.RemoveAll(filepath.Join(diskPath, partitionName)) - - // Try to find any mounts that match the partition given and remove them from the mounts - for _, mount := range g.mounts { - fields := strings.Fields(mount) - // If first field does not contain the /dev/PARTITION, add it to the newmounts - if !strings.Contains(fields[0], filepath.Join("/dev", partitionName)) { - newMounts = append(newMounts, mount) - } - } - g.mounts = newMounts - // Write the mounts again - _ = os.WriteFile(g.paths.ProcMounts, []byte(strings.Join(g.mounts, "")), 0644) - // Remove it from the partitions list - for index, disk := range g.disks { - if disk.Name == diskName { - var newPartitions []*block.Partition - for _, partition := range disk.Partitions { - if partition.Name != partitionName { - newPartitions = append(newPartitions, partition) - } - } - g.disks[index].Partitions = newPartitions - } - } -} - -// Clean will remove the chroot dir and unset the env var -func (g *GhwMock) Clean() { - _ = os.Unsetenv("GHW_CHROOT") - _ = os.RemoveAll(g.chroot) -}