diff --git a/go.mod b/go.mod index 5343816..602bf4b 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/deniswernert/go-fstab v0.0.0-20141204152952-eb4090f26517 github.com/kairos-io/kairos v1.5.0 github.com/moby/sys/mountinfo v0.5.0 + github.com/rs/zerolog v1.29.0 github.com/spectrocloud-labs/herd v0.2.1 github.com/urfave/cli v1.22.10 ) @@ -26,6 +27,7 @@ require ( github.com/joho/godotenv v1.4.0 // indirect github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect diff --git a/go.sum b/go.sum index 9ca6c63..17a2f45 100644 --- a/go.sum +++ b/go.sum @@ -229,6 +229,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -470,7 +471,12 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -612,6 +618,9 @@ github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -635,8 +644,6 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spectrocloud-labs/herd v0.1.2-0.20230201084705-8e524743ec9c h1:l6aDSoktdHpSTsUEMZy6tkn0iMf/8Buzwh3DIkkWeoE= -github.com/spectrocloud-labs/herd v0.1.2-0.20230201084705-8e524743ec9c/go.mod h1:fcZ8fjFcEJUM7qF6YcgxF3z8CCLjJeF7r4K1m8JQbHs= github.com/spectrocloud-labs/herd v0.2.1 h1:Z08zjr8i+DFD6hB/51FnMSDIf2Q3nKGtA25UMYJwKMI= github.com/spectrocloud-labs/herd v0.2.1/go.mod h1:fcZ8fjFcEJUM7qF6YcgxF3z8CCLjJeF7r4K1m8JQbHs= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -891,6 +898,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/cmd/commands.go b/internal/cmd/commands.go index dd45378..bfdb431 100644 --- a/internal/cmd/commands.go +++ b/internal/cmd/commands.go @@ -1,9 +1,12 @@ package cmd import ( - "context" + "os" "github.com/kairos-io/immucore/pkg/mount" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/spectrocloud-labs/herd" "github.com/urfave/cli" ) @@ -20,14 +23,29 @@ Sends a generic event payload with the configuration found in the scanned direct Aliases: []string{}, Flags: []cli.Flag{}, Action: func(c *cli.Context) error { - + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) g := herd.DAG() s := &mount.State{Rootdir: "/"} s.Register(g) - - return g.Run(context.Background()) + writeDag(g.Analyze()) + return nil + //return g.Run(context.Background()) }, }, } + +func writeDag(d [][]herd.GraphEntry) { + for i, layer := range d { + log.Printf("%d.", (i + 1)) + for _, op := range layer { + if op.Error != nil { + log.Printf(" <%s> (error: %s) (background: %t)", op.Name, op.Error.Error(), op.Background) + } else { + log.Printf(" <%s> (background: %t)", op.Name, op.Background) + } + } + log.Print("") + } +} diff --git a/pkg/mount/mount.go b/pkg/mount/mount.go index 0c9a5ac..810cdac 100644 --- a/pkg/mount/mount.go +++ b/pkg/mount/mount.go @@ -15,15 +15,14 @@ import ( ) type State struct { - Rootdir string - TargetImage string // e.g. /cOS/active.img - OverlayDir []string // e.g. /var - BindMounts []string // e.g. /etc/kubernetes - StateDir string // e.g. "/usr/local/.state" - TargetLabel string // e.g. COS_ACTIVE - - MountRoot bool // e.g. if true, it tries to find the image to loopback mount - + Rootdir string // e.g. /sysroot inside initrd with pivot, / with nopivot + TargetImage string // e.g. /cOS/active.img + OverlayDir []string // e.g. /var + BindMounts []string // e.g. /etc/kubernetes + StateDir string // e.g. "/usr/local/.state" + TargetLabel string // e.g. COS_ACTIVE + FStabFile string // e.g. /etc/fstab + MountRoot bool // e.g. if true, it tries to find the image to loopback mount CustomMounts map[string]string // e.g. diskid : mountpoint fstabs []*fstab.Mount @@ -50,162 +49,15 @@ func genOpreference(op string, s []string) (res []string) { } const ( - opCustomMounts = "custom-mount" - opDiscoverState = "discover-state" - opMountState = "mount-state" - opMountRoot = "mount-root" + opCustomMounts = "custom-mount" + opDiscoverState = "discover-state" + opMountState = "mount-state" + opMountRoot = "mount-root" + opOverlayMount = "overlay-mount" + opWriteFstab = "write-fstab" + opMountBaseOverlay = "mount-base-overlay" ) -func (s *State) Register(g *herd.Graph) error { - - // TODO: add, hooks, fstab, systemd compat - - // This is legacy - in UKI we don't need to found the img, this needs to run in a conditional - if s.MountRoot { - g.Add(opDiscoverState, - herd.WithDeps(opMountState), - herd.WithCallback( - func(ctx context.Context) error { - _, err := utils.SH(fmt.Sprintf("losetup --show -f /run/initramfs/cos-state%s", s.TargetImage)) - return err - }, - )) - - g.Add(opMountState, - herd.WithCallback( - s.MountOP( - "/dev/disk/by-label/COS_STATE", - s.path("/run/initramfs/cos-state"), - "auto", - []string{ - "ro", // or rw - }, 60*time.Second), - ), - ) - - g.Add(opMountRoot, - herd.WithDeps(opDiscoverState), - herd.WithCallback( - s.MountOP( - fmt.Sprintf("/dev/disk/by-label/%s", s.TargetLabel), - s.Rootdir, - "auto", - []string{ - "ro", // or rw - "suid", - "dev", - "exec", - "auto", - "nouser", - "async", - }, 60*time.Second), - ), - ) - - } - // end sysroot mount - - // overlay mount start - if rootFSType(s.Rootdir) != "overlay" { - g.Add("mount-overlay-base", - herd.WithCallback( - func(ctx context.Context) error { - op, err := baseOverlay(profile.Overlay{ - Base: "/run/overlay", - BackingBase: "tmpfs:20%", - }) - if err != nil { - return err - } - s.fstabs = append(s.fstabs, &op.FstabEntry) - return op.run() - }, - ), - ) - } - - overlayCondition := herd.ConditionalOption(func() bool { return rootFSType(s.Rootdir) != "overlay" }, herd.WithDeps("mount-overlay-base")) - - // TODO: Add fsck - // mount overlay - for _, p := range s.OverlayDir { - g.Add("mount-overlays-base", - overlayCondition, - herd.WithCallback( - func(ctx context.Context) error { - op, err := mountWithBaseOverlay(p, s.Rootdir, "/run/overlay") - if err != nil { - return err - } - s.fstabs = append(s.fstabs, &op.FstabEntry) - return op.run() - }, - ), - ) - } - - // custom mounts TODO: disk/path - for id, mountpoint := range s.CustomMounts { - g.Add( - genOpreferenceName(opCustomMounts, mountpoint), - overlayCondition, - herd.WithCallback( - s.MountOP( - id, - s.path(mountpoint), - "auto", - []string{ - "ro", // or rw - }, 60*time.Second), - ), - ) - } - - // mount state - // mount state is defined over a custom mount (/usr/local/.state for instance, needs to be mounted over a device) - for _, p := range s.BindMounts { - g.Add( - genOpreferenceName("mount-state", p), - overlayCondition, - herd.WithDeps(genOpreferenceFromMap(opCustomMounts, s.CustomMounts)...), - herd.WithCallback( - func(ctx context.Context) error { - op, err := mountBind(p, s.Rootdir, s.StateDir) - if err != nil { - return err - } - s.fstabs = append(s.fstabs, &op.FstabEntry) - return op.run() - }, - ), - ) - } - - // overlay mount end - g.Add(opMountRoot, - herd.ConditionalOption(func() bool { return s.MountRoot }, herd.WithDeps("mount-overlay-base")), - herd.WithCallback( - s.MountOP( - "/dev/disk/by-label/COS_OEM", - s.path("/oem"), - "auto", - []string{ - "rw", - "suid", - "dev", - "exec", - "noauto", - "nouser", - "async", - }, 60*time.Second), - ), - ) - - g.Add("write-fstab", herd.WithCallback(s.WriteFstab("foo"))) - - return nil -} - func (s *State) path(p ...string) string { return filepath.Join(append([]string{s.Rootdir}, p...)...) } @@ -266,3 +118,161 @@ func (s *State) MountOP(what, where, t string, options []string, timeout time.Du } } } + +func (s *State) Register(g *herd.Graph) error { + + // TODO: add, hooks, fstab, systemd compat + + // This is legacy - in UKI we don't need to found the img, this needs to run in a conditional + if s.MountRoot { + g.Add(opDiscoverState, + herd.WithDeps(opMountState), + herd.WithCallback( + func(ctx context.Context) error { + _, err := utils.SH(fmt.Sprintf("losetup --show -f /run/initramfs/cos-state%s", s.TargetImage)) + return err + }, + )) + + g.Add(opMountState, + herd.WithCallback( + s.MountOP( + "/dev/disk/by-label/COS_STATE", + s.path("/run/initramfs/cos-state"), + "auto", + []string{ + "ro", // or rw + }, 60*time.Second), + ), + ) + + g.Add(opMountRoot, + herd.WithDeps(opDiscoverState), + herd.WithCallback( + s.MountOP( + fmt.Sprintf("/dev/disk/by-label/%s", s.TargetLabel), + s.Rootdir, + "auto", + []string{ + "ro", // or rw + "suid", + "dev", + "exec", + "auto", + "nouser", + "async", + }, 60*time.Second), + ), + ) + + } + // end sysroot mount + + // overlay mount start + if rootFSType(s.Rootdir) != "overlay" { + g.Add(opMountBaseOverlay, + herd.WithCallback( + func(ctx context.Context) error { + op, err := baseOverlay(profile.Overlay{ + Base: "/run/overlay", + BackingBase: "tmpfs:20%", + }) + if err != nil { + return err + } + s.fstabs = append(s.fstabs, &op.FstabEntry) + return op.run() + }, + ), + ) + } + + overlayCondition := herd.ConditionalOption(func() bool { return rootFSType(s.Rootdir) != "overlay" }, herd.WithDeps(opMountBaseOverlay)) + + // TODO: Add fsck + // mount overlay + for _, p := range s.OverlayDir { + g.Add( + genOpreferenceName(opOverlayMount, p), + overlayCondition, + herd.WithCallback( + func(ctx context.Context) error { + op, err := mountWithBaseOverlay(p, s.Rootdir, "/run/overlay") + if err != nil { + return err + } + s.fstabs = append(s.fstabs, &op.FstabEntry) + return op.run() + }, + ), + ) + } + + // custom mounts TODO: disk/path + for id, mountpoint := range s.CustomMounts { + g.Add( + genOpreferenceName(opCustomMounts, mountpoint), + overlayCondition, + herd.WithCallback( + s.MountOP( + id, + s.path(mountpoint), + "auto", + []string{ + "ro", // or rw + }, 60*time.Second), + ), + ) + } + + // mount state + // mount state is defined over a custom mount (/usr/local/.state for instance, needs to be mounted over a device) + for _, p := range s.BindMounts { + g.Add( + genOpreferenceName(opMountState, p), + overlayCondition, + herd.WithDeps(genOpreferenceFromMap(opCustomMounts, s.CustomMounts)...), + herd.WithCallback( + func(ctx context.Context) error { + op, err := mountBind(p, s.Rootdir, s.StateDir) + if err != nil { + return err + } + s.fstabs = append(s.fstabs, &op.FstabEntry) + return op.run() + }, + ), + ) + } + + // overlay mount end + g.Add(opMountRoot, + herd.ConditionalOption(func() bool { return s.MountRoot }, herd.WithDeps("mount-overlay-base")), + herd.WithCallback( + s.MountOP( + "/dev/disk/by-label/COS_OEM", + s.path("/oem"), + "auto", + []string{ + "rw", + "suid", + "dev", + "exec", + "noauto", + "nouser", + "async", + }, 60*time.Second), + ), + ) + + g.Add(opWriteFstab, + overlayCondition, + herd.ConditionalOption(func() bool { return s.MountRoot }, herd.WithDeps(opMountRoot)), + herd.WithDeps(opMountRoot), + herd.WithDeps(genOpreferenceFromMap(opCustomMounts, s.CustomMounts)...), + herd.WithDeps(genOpreference(opMountState, s.BindMounts)...), + herd.WithDeps(genOpreference(opOverlayMount, s.OverlayDir)...), + herd.WithCallback(s.WriteFstab(s.FStabFile))) + + return nil +}