From 2be9cfce66fbe5d5c17406d6ba2c716ec9c57677 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Tue, 18 Jul 2023 12:46:50 +0200 Subject: [PATCH 1/8] Add iso builder This adds a new package for the iso builder run directly on go. This is extracted from the original elemental-cli and then from the now build-less kairos-agent This uses no deps on elemental, only deps are on kairos-agent for the config stuff mainly. Signed-off-by: Itxaka --- tools-image/Dockerfile | 19 +- tools-image/enki/cmd/build-iso.go | 126 +++ tools-image/enki/cmd/root.go | 90 ++ tools-image/enki/go.mod | 149 +++ tools-image/enki/go.sum | 1002 ++++++++++++++++++ tools-image/enki/internal/version/version.go | 36 + tools-image/enki/main.go | 7 + tools-image/enki/pkg/action/build-iso.go | 373 +++++++ tools-image/enki/pkg/config/config.go | 295 ++++++ tools-image/enki/pkg/constants/constants.go | 139 +++ tools-image/enki/pkg/utils/chroot.go | 218 ++++ tools-image/enki/pkg/utils/cleanstack.go | 50 + tools-image/enki/pkg/utils/common.go | 40 + tools-image/enki/pkg/utils/fs.go | 223 ++++ tools-image/entrypoint.sh | 2 +- 15 files changed, 2766 insertions(+), 3 deletions(-) create mode 100644 tools-image/enki/cmd/build-iso.go create mode 100644 tools-image/enki/cmd/root.go create mode 100644 tools-image/enki/go.mod create mode 100644 tools-image/enki/go.sum create mode 100644 tools-image/enki/internal/version/version.go create mode 100644 tools-image/enki/main.go create mode 100644 tools-image/enki/pkg/action/build-iso.go create mode 100644 tools-image/enki/pkg/config/config.go create mode 100644 tools-image/enki/pkg/constants/constants.go create mode 100644 tools-image/enki/pkg/utils/chroot.go create mode 100644 tools-image/enki/pkg/utils/cleanstack.go create mode 100644 tools-image/enki/pkg/utils/common.go create mode 100644 tools-image/enki/pkg/utils/fs.go diff --git a/tools-image/Dockerfile b/tools-image/Dockerfile index c311321..eea12fc 100644 --- a/tools-image/Dockerfile +++ b/tools-image/Dockerfile @@ -3,12 +3,27 @@ ARG LEAP_VERSION=15.4 ARG LUET_VERSION=0.33.0 FROM quay.io/luet/base:$LUET_VERSION AS luet +FROM golang:1.20 as enki +ENV CGO_ENABLED=0 +COPY ./enki /src/enki +WORKDIR /src/enki +RUN go mod download +# Set arg/env after go mod download, otherwise we invalidate the cached layers due to the commit changing easily +ARG ENKI_VERSION=0.0.1 +ARG ENKI_COMMIT="" +ENV ENKI_VERSION=${ENKI_VERSION} +ENV ENKI_COMMIT=${ENKI_COMMIT} +RUN go build \ + -ldflags "-w -s \ + -X github.com/kairos-io/enki/internal/version.version=$ENKI_VERSION \ + -X github.com/kairos-io/enki/internal/version.gitCommit=$ENKI_COMMIT" \ + -o /usr/bin/enki + FROM opensuse/leap:$LEAP_VERSION as luet-install COPY --from=luet /usr/bin/luet /usr/bin/luet ENV LUET_NOLOCK=true ENV TMPDIR=/tmp COPY luet.yaml /etc/luet/luet.yaml -RUN luet install -y system/elemental-cli RUN luet install -y livecd/grub2 --system-target /grub2 RUN luet install -y livecd/grub2-efi-image --system-target /efi @@ -42,7 +57,6 @@ FROM quay.io/kairos/packages:grub-config-static-0.1 AS grub-raw-config FROM quay.io/kairos/packages:grub-artifacts-static-0.1 AS grub-raw-artifacts FROM opensuse/leap:$LEAP_VERSION -COPY --from=luet-install /usr/bin/elemental /usr/bin/elemental COPY --from=luet /usr/bin/luet /usr/bin/luet # ISO files @@ -101,5 +115,6 @@ COPY ./netboot.sh /netboot.sh COPY defaults.yaml /defaults.yaml +COPY --from=enki /usr/bin/enki /usr/bin/enki ENTRYPOINT [ "/entrypoint.sh" ] diff --git a/tools-image/enki/cmd/build-iso.go b/tools-image/enki/cmd/build-iso.go new file mode 100644 index 0000000..21c0ba6 --- /dev/null +++ b/tools-image/enki/cmd/build-iso.go @@ -0,0 +1,126 @@ +package cmd + +import ( + "fmt" + "os/exec" + + "github.com/kairos-io/enki/pkg/action" + "github.com/kairos-io/enki/pkg/config" + "github.com/kairos-io/enki/pkg/utils" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "k8s.io/mount-utils" +) + +// NewBuildISO returns a new instance of the buid-iso subcommand and appends it to +// the root command. requireRoot is to initiate it with or without the CheckRoot +// pre-run check. This method is mostly used for testing purposes. +func NewBuildISO(root *cobra.Command, addCheckRoot bool) *cobra.Command { + c := &cobra.Command{ + Use: "build-iso SOURCE", + Short: "Build bootable installation media ISOs", + Long: "Build bootable installation media ISOs\n\n" + + "SOURCE - should be provided as uri in following format :\n" + + " * - might be [\"dir\", \"file\", \"oci\", \"docker\"], as default is \"docker\"\n" + + " * - is path to file or directory, image name with tag version", + Args: cobra.MaximumNArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + if addCheckRoot { + return CheckRoot() + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + path, err := exec.LookPath("mount") + if err != nil { + return err + } + mounter := mount.New(path) + + cfg, err := config.ReadConfigBuild(viper.GetString("config-dir"), cmd.Flags(), mounter) + if err != nil { + cfg.Logger.Errorf("Error reading config: %s\n", err) + } + + flags := cmd.Flags() + + // Set this after parsing of the flags, so it fails on parsing and prints usage properly + cmd.SilenceUsage = true + cmd.SilenceErrors = true // Do not propagate errors down the line, we control them + spec, err := config.ReadBuildISO(cfg, flags) + if err != nil { + cfg.Logger.Errorf("invalid install command setup %v", err) + return err + } + + if len(args) == 1 { + imgSource, err := v1.NewSrcFromURI(args[0]) + if err != nil { + cfg.Logger.Errorf("not a valid rootfs source image argument: %s", args[0]) + return err + } + spec.RootFS = []*v1.ImageSource{imgSource} + } else if len(spec.RootFS) == 0 { + errmsg := "rootfs source image for building ISO was not provided" + cfg.Logger.Errorf(errmsg) + return fmt.Errorf(errmsg) + } + + // Repos and overlays can't be unmarshaled directly as they require + // to be merged on top and flags do not match any config value key + oRootfs, _ := flags.GetString("overlay-rootfs") + oUEFI, _ := flags.GetString("overlay-uefi") + oISO, _ := flags.GetString("overlay-iso") + + if oRootfs != "" { + if ok, err := utils.Exists(cfg.Fs, oRootfs); ok { + spec.RootFS = append(spec.RootFS, v1.NewDirSrc(oRootfs)) + } else { + cfg.Logger.Errorf("Invalid value for overlay-rootfs") + return fmt.Errorf("Invalid path '%s': %v", oRootfs, err) + } + } + if oUEFI != "" { + if ok, err := utils.Exists(cfg.Fs, oUEFI); ok { + spec.UEFI = append(spec.UEFI, v1.NewDirSrc(oUEFI)) + } else { + cfg.Logger.Errorf("Invalid value for overlay-uefi") + return fmt.Errorf("Invalid path '%s': %v", oUEFI, err) + } + } + if oISO != "" { + if ok, err := utils.Exists(cfg.Fs, oISO); ok { + spec.Image = append(spec.Image, v1.NewDirSrc(oISO)) + } else { + cfg.Logger.Errorf("Invalid value for overlay-iso") + return fmt.Errorf("Invalid path '%s': %v", oISO, err) + } + } + + buildISO := action.NewBuildISOAction(cfg, spec) + err = buildISO.ISORun() + if err != nil { + cfg.Logger.Errorf(err.Error()) + return err + } + + return nil + }, + } + root.AddCommand(c) + c.Flags().StringP("name", "n", "", "Basename of the generated ISO file") + c.Flags().StringP("output", "o", "", "Output directory (defaults to current directory)") + c.Flags().Bool("date", false, "Adds a date suffix into the generated ISO file") + c.Flags().String("overlay-rootfs", "", "Path of the overlayed rootfs data") + c.Flags().String("overlay-uefi", "", "Path of the overlayed uefi data") + c.Flags().String("overlay-iso", "", "Path of the overlayed iso data") + c.Flags().String("label", "", "Label of the ISO volume") + archType := newEnumFlag([]string{"x86_64", "arm64"}, "x86_64") + c.Flags().Bool("squash-no-compression", true, "Disable squashfs compression.") + c.Flags().VarP(archType, "arch", "a", "Arch to build the image for") + return c +} + +// register the subcommand into rootCmd +var _ = NewBuildISO(rootCmd, true) diff --git a/tools-image/enki/cmd/root.go b/tools-image/enki/cmd/root.go new file mode 100644 index 0000000..6daad8a --- /dev/null +++ b/tools-image/enki/cmd/root.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "errors" + "fmt" + "os" + "strings" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func NewRootCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "enki", + Short: "enki", + } + cmd.PersistentFlags().Bool("debug", false, "Enable debug output") + cmd.PersistentFlags().String("config-dir", "/etc/elemental", "Set config dir (default is /etc/elemental)") + cmd.PersistentFlags().String("logfile", "", "Set logfile") + cmd.PersistentFlags().Bool("quiet", false, "Do not output to stdout") + _ = viper.BindPFlag("debug", cmd.PersistentFlags().Lookup("debug")) + _ = viper.BindPFlag("config-dir", cmd.PersistentFlags().Lookup("config-dir")) + _ = viper.BindPFlag("logfile", cmd.PersistentFlags().Lookup("logfile")) + _ = viper.BindPFlag("quiet", cmd.PersistentFlags().Lookup("quiet")) + + if viper.GetBool("debug") { + logrus.SetLevel(logrus.DebugLevel) + } + return cmd +} + +// rootCmd represents the base command when called without any subcommands +var rootCmd = NewRootCmd() + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +// CheckRoot is a helper to return on PreRunE, so we can add it to commands that require root +func CheckRoot() error { + if os.Geteuid() != 0 { + return errors.New("this command requires root privileges") + } + return nil +} + +type enum struct { + Allowed []string + Value string +} + +func (a enum) String() string { + return a.Value +} + +func (a *enum) Set(p string) error { + isIncluded := func(opts []string, val string) bool { + for _, opt := range opts { + if val == opt { + return true + } + } + return false + } + if !isIncluded(a.Allowed, p) { + return fmt.Errorf("%s is not included in %s", p, strings.Join(a.Allowed, ",")) + } + a.Value = p + return nil +} + +func (a *enum) Type() string { + return "string" +} + +// newEnum give a list of allowed flag parameters, where the second argument is the default +func newEnumFlag(allowed []string, d string) *enum { + return &enum{ + Allowed: allowed, + Value: d, + } +} diff --git a/tools-image/enki/go.mod b/tools-image/enki/go.mod new file mode 100644 index 0000000..967bfec --- /dev/null +++ b/tools-image/enki/go.mod @@ -0,0 +1,149 @@ +module github.com/kairos-io/enki + +go 1.20 + +require ( + github.com/hashicorp/go-multierror v1.1.1 + github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6 + github.com/mitchellh/mapstructure v1.5.0 + github.com/sanity-io/litter v1.5.5 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.7.0 + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.16.0 + github.com/twpayne/go-vfs v1.7.2 + k8s.io/mount-utils v0.27.3 + +) + +require ( + atomicgo.dev/cursor v0.1.1 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.0.2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.10.0-rc.8 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230117203413-a47887b8f098 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/cavaliergopher/grab v2.0.0+incompatible // indirect + github.com/cavaliergopher/grab/v3 v3.0.1 // indirect + github.com/cloudflare/circl v1.3.1 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/containerd/console v1.0.3 // indirect + github.com/containerd/containerd v1.7.1 // indirect + github.com/containerd/continuity v0.3.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/denisbrodbeck/machineid v1.0.1 // indirect + github.com/diskfs/go-diskfs v1.3.0 // indirect + github.com/distribution/distribution v2.8.2+incompatible // indirect + github.com/docker/cli v23.0.5+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v23.0.6+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 + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.3.1 // indirect + github.com/go-git/go-git/v5 v5.4.2 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-containerregistry v0.15.2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gookit/color v1.5.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/imdario/mergo v0.3.15 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/itchyny/gojq v0.12.12 // indirect + github.com/itchyny/timefmt-go v0.1.5 // indirect + github.com/jaypipes/ghw v0.10.0 // indirect + github.com/jaypipes/pcidb v1.0.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07 // indirect + github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/moby v23.0.4+incompatible // indirect + github.com/moby/sys/mountinfo v0.6.2 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/mudler/entities v0.0.0-20220905203055-68348bae0f49 // indirect + github.com/mudler/yip v1.3.1-0.20230704124832-e5812d0f5890 // indirect + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc3 // indirect + github.com/packethost/packngo v0.29.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/xattr v0.4.9 // indirect + github.com/pterm/pterm v0.12.62 // indirect + github.com/qeesung/image2ascii v1.0.1 // indirect + github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/samber/lo v1.37.0 // indirect + github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/spectrocloud-labs/herd v0.4.2 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/tredoe/osutil/v2 v2.0.0-rc.16 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect + github.com/vishvananda/netlink v1.2.1-beta.2 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3 // indirect + github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect + github.com/willdonnelly/passwd v0.0.0-20141013001024-7935dab3074c // indirect + github.com/xanzy/ssh-agent v0.3.1 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/zcalusic/sysinfo v0.9.5 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.9.1 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.55.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/djherbis/times.v1 v1.3.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + howett.net/plist v1.0.0 // indirect + k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect + pault.ag/go/modprobe v0.1.2 // indirect + pault.ag/go/topsort v0.1.1 // indirect +) diff --git a/tools-image/enki/go.sum b/tools-image/enki/go.sum new file mode 100644 index 0000000..3ba9200 --- /dev/null +++ b/tools-image/enki/go.sum @@ -0,0 +1,1002 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4= +atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.0.2 h1:2e/4KY6t3wokja01Cyty6qgkQM8MotJzjtqCH70oX2Q= +atomicgo.dev/schedule v0.0.2/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= +github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v0.0.0-20230117203413-a47887b8f098 h1:gQT1cLGP56jqbm0ioh/80TgknBT2EyZ5XwnnJsiQQKo= +github.com/ProtonMail/go-crypto v0.0.0-20230117203413-a47887b8f098/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cavaliergopher/grab v2.0.0+incompatible h1:XLeGNAc7MIRTMb8RlRbN76uO8vx1/AeNMWWN7FYpDw8= +github.com/cavaliergopher/grab v2.0.0+incompatible/go.mod h1:6ICNRTQPwkMP0m2sKIDv/9XkhFJJwiEOQyZ+8E4H7Yg= +github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= +github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.1 h1:4OVCZRL62ijwEwxnF6I7hLwxvIYi3VaZt8TflkqtrtA= +github.com/cloudflare/circl v1.3.1/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.7.1 h1:k8DbDkSOwt5rgxQ3uCI4WMKIJxIndSCBUaGm5oRn+Go= +github.com/containerd/containerd v1.7.1/go.mod h1:gA+nJUADRBm98QS5j5RPROnt0POQSMK+r7P7EGMC/Qc= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= +github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/diskfs/go-diskfs v1.3.0 h1:D3IVe1y7ybB5SjCO0pOmkWThL9lZEWeanp8rRa0q0sk= +github.com/diskfs/go-diskfs v1.3.0/go.mod h1:3pUpCAz75Q11om5RsGpVKUgXp2Z+ATw1xV500glmCP0= +github.com/distribution/distribution v2.8.2+incompatible h1:k9+4DKdOG+quPFZXT/mUsiQrGu9vYCp+dXpuPkuqhk8= +github.com/distribution/distribution v2.8.2+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= +github.com/docker/cli v23.0.5+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 v23.0.6+incompatible h1:aBD4np894vatVX99UTx/GyOUOK4uEcROwA3+bQhEcoU= +github.com/docker/docker v23.0.6+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= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= +github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= +github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/itchyny/gojq v0.12.12 h1:x+xGI9BXqKoJQZkr95ibpe3cdrTbY8D9lonrK433rcA= +github.com/itchyny/gojq v0.12.12/go.mod h1:j+3sVkjxwd7A7Z5jrbKibgOLn0ZfLWkV+Awxr/pyzJE= +github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= +github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= +github.com/jaypipes/ghw v0.10.0 h1:UHu9UX08Py315iPojADFPOkmjTsNzHj4g4adsNKKteY= +github.com/jaypipes/ghw v0.10.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g= +github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8= +github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6 h1:5tl86nNswp+f91Oudzoo7ceSfQXd/Fhd1fkO85/mVSU= +github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6/go.mod h1:+zG2JtLuTE9TDwiXJg9/jqcD/G59PhdN+Z0G5dcGiJk= +github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07 h1:WctdkLqZBl8bViFPoqnRtxU5Vf63G9c1lTLem6F3d4s= +github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07/go.mod h1:Z+1CLqMZq97bzwX2XSIArr8EoniMth3mMYkOOb8L3QY= +github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk= +github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c/go.mod h1:VOfm8h1NySetVlpHDSnbpCMsvCgYaU+YDn4XezUy2+4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/moby v23.0.4+incompatible h1:A/pe8vi9KIKhNbzR0G3wW4ACKDsMgXILBveMqiJNa8M= +github.com/moby/moby v23.0.4+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/mudler/entities v0.0.0-20220905203055-68348bae0f49 h1:P1QgHLh0hX935j6m9K6rlSxc0mkD1UuIAOQEu+1VCW4= +github.com/mudler/entities v0.0.0-20220905203055-68348bae0f49/go.mod h1:qquFT9tYp+/NO7tTotto4BT9zSRYSMDxo2PGZwujpFA= +github.com/mudler/yip v1.3.1-0.20230704124832-e5812d0f5890 h1:lNOwUTOH+WW8c2t1aQniYRiF8qFwRjB6XO6Nu+d9vlo= +github.com/mudler/yip v1.3.1-0.20230704124832-e5812d0f5890/go.mod h1:3WeDh6tGX1yYPJom05E7xEjw8dNVlkH2WFxLi7Gflzk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= +github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/packethost/packngo v0.29.0 h1:gRIhciVZQ/zLNrIdIdbOUyB/Tw5IgoaXyhP4bvE+D2s= +github.com/packethost/packngo v0.29.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee h1:P6U24L02WMfj9ymZTxl7CxS73JC99x3ukk+DBkgQGQs= +github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY= +github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs= +github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE= +github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.62 h1:Xjj5Wl6UR4Il9xOiDUOZRwReRTdO75if/JdWsn9I59s= +github.com/pterm/pterm v0.12.62/go.mod h1:+c3ujjE7N5qmNx6eKAa7YVSC6m/gCorJJKhzwYTbL90= +github.com/qeesung/image2ascii v1.0.1 h1:Fe5zTnX/v/qNC3OC4P/cfASOXS501Xyw2UUcgrLgtp4= +github.com/qeesung/image2ascii v1.0.1/go.mod h1:kZKhyX0h2g/YXa/zdJR3JnLnJ8avHjZ3LrvEKSYyAyU= +github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09 h1:/yNp//3ZC5J7KUaUPDmomQ78j8VUD/2T/uT+TvS4M0w= +github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09/go.mod h1:n6Fkjc5qoMeWrnLSA5oqUF8ZzFKMrM960CtBwfvH1ZM= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= +github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= +github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= +github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= +github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM= +github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/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.4.2 h1:90cYZmW0yxNw4PEbqNGSerrtqKSx1nvRbSwAwjc/5AY= +github.com/spectrocloud-labs/herd v0.4.2/go.mod h1:WBlMIs1QZ7XtVrt9rAAFZpkh/fZYA4l2gGOCUS1LDHE= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tredoe/osutil/v2 v2.0.0-rc.16 h1:5A2SKvyB2c3lhPYUIHyFtu6jbaXlaA3Hu5gWIam8Pik= +github.com/tredoe/osutil/v2 v2.0.0-rc.16/go.mod h1:uLRVx/3pb7Y4RQhG8cQFbPE9ha5r81e6MXpBsxbTAYc= +github.com/twpayne/go-vfs v1.7.2 h1:ZNYMAXcu2Av8c109USrSGYm8dIIIV0xPlG19I2088Kw= +github.com/twpayne/go-vfs v1.7.2/go.mod h1:1eni2ntkiiAHZG27xfLOO4CYvMR4Kw8V7rYiLeeolsQ= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +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= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3 h1:v6jG/tdl4O07LNVp74Nt7/OyL+1JsIW1M2f/nSvQheY= +github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3/go.mod h1:CSBTxrhePCm0cmXNKDGeu+6bOQzpaEklfCqEpn89JWk= +github.com/wayneashleyberry/terminal-dimensions v1.1.0 h1:EB7cIzBdsOzAgmhTUtTTQXBByuPheP/Zv1zL2BRPY6g= +github.com/wayneashleyberry/terminal-dimensions v1.1.0/go.mod h1:2lc/0eWCObmhRczn2SdGSQtgBooLUzIotkkEGXqghyg= +github.com/willdonnelly/passwd v0.0.0-20141013001024-7935dab3074c h1:4+NVyrLUuEmvE3r3Xst7gPuKhAP6X04ACpMmPvtK0M0= +github.com/willdonnelly/passwd v0.0.0-20141013001024-7935dab3074c/go.mod h1:xcvfY9pOw6s4wyrhilFSbMthL6KzgrfCIETHHUOQ/fQ= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= +github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zcalusic/sysinfo v0.9.5 h1:ivoHyj9aIAYkwzo1+8QgJ5s4oeE6Etx9FmZtqa4wJjQ= +github.com/zcalusic/sysinfo v0.9.5/go.mod h1:Z/gPVufBrFc8X5sef3m6kkw3r3nlNFp+I6bvASfvBZQ= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/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.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +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= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181021155630-eda9bb28ed51/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200102141924-c96a22e43c9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20211007075335-d3039528d8ac/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-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= +gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +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.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/mount-utils v0.27.3 h1:oubkDKLTZUneW27wgyOmp8a1AAZj04vGmtq+YW8wdvY= +k8s.io/mount-utils v0.27.3/go.mod h1:vmcjYdi2Vg1VTWY7KkhvwJVY6WDHxb/QQhiQKkR8iNs= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +pault.ag/go/modprobe v0.1.2 h1:bblunaPhqpTxGDJ5TVFW/4gheohBPleF2dIV6j6sWkI= +pault.ag/go/modprobe v0.1.2/go.mod h1:afr2STC/2Maz/qi4+Bma1s0dszZgO/PcM8AKar9DWhM= +pault.ag/go/topsort v0.0.0-20160530003732-f98d2ad46e1a/go.mod h1:INqx0ClF7kmPAMk2zVTX8DRnhZ/yaA/Mg52g8KFKE7k= +pault.ag/go/topsort v0.1.1 h1:L0QnhUly6LmTv0e3DEzbN2q6/FGgAcQvaEw65S53Bg4= +pault.ag/go/topsort v0.1.1/go.mod h1:r1kc/L0/FZ3HhjezBIPaNVhkqv8L0UJ9bxRuHRVZ0q4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/tools-image/enki/internal/version/version.go b/tools-image/enki/internal/version/version.go new file mode 100644 index 0000000..0e549c0 --- /dev/null +++ b/tools-image/enki/internal/version/version.go @@ -0,0 +1,36 @@ +package version + +import ( + "runtime" +) + +var ( + version = "v0.0.1" + // gitCommit is the git sha1 + gitCommit = "" +) + +// BuildInfo describes the compile time information. +type BuildInfo struct { + // Version is the current semver. + Version string `json:"version,omitempty"` + // GitCommit is the git sha1. + GitCommit string `json:"git_commit,omitempty"` + // GoVersion is the version of the Go compiler used. + GoVersion string `json:"go_version,omitempty"` +} + +func GetVersion() string { + return version +} + +// Get returns build info +func Get() BuildInfo { + v := BuildInfo{ + Version: GetVersion(), + GitCommit: gitCommit, + GoVersion: runtime.Version(), + } + + return v +} diff --git a/tools-image/enki/main.go b/tools-image/enki/main.go new file mode 100644 index 0000000..1a1dc1a --- /dev/null +++ b/tools-image/enki/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/kairos-io/enki/cmd" + +func main() { + cmd.Execute() +} diff --git a/tools-image/enki/pkg/action/build-iso.go b/tools-image/enki/pkg/action/build-iso.go new file mode 100644 index 0000000..a2e2e8e --- /dev/null +++ b/tools-image/enki/pkg/action/build-iso.go @@ -0,0 +1,373 @@ +package action + +import ( + "fmt" + "path/filepath" + "strings" + "time" + + "github.com/kairos-io/enki/pkg/constants" + "github.com/kairos-io/enki/pkg/utils" + "github.com/kairos-io/kairos-agent/v2/pkg/elemental" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" +) + +type BuildISOAction struct { + cfg *v1.BuildConfig + spec *v1.LiveISO + e *elemental.Elemental +} + +type BuildISOActionOption func(a *BuildISOAction) + +func NewBuildISOAction(cfg *v1.BuildConfig, spec *v1.LiveISO, opts ...BuildISOActionOption) *BuildISOAction { + b := &BuildISOAction{ + cfg: cfg, + e: elemental.NewElemental(&cfg.Config), + spec: spec, + } + for _, opt := range opts { + opt(b) + } + return b +} + +// ISORun will install the system from a given configuration +func (b *BuildISOAction) ISORun() (err error) { + cleanup := utils.NewCleanStack() + defer func() { err = cleanup.Cleanup(err) }() + + isoTmpDir, err := utils.TempDir(b.cfg.Fs, "", "elemental-iso") + if err != nil { + return err + } + cleanup.Push(func() error { return b.cfg.Fs.RemoveAll(isoTmpDir) }) + + rootDir := filepath.Join(isoTmpDir, "rootfs") + err = utils.MkdirAll(b.cfg.Fs, rootDir, constants.DirPerm) + if err != nil { + return err + } + + uefiDir := filepath.Join(isoTmpDir, "uefi") + err = utils.MkdirAll(b.cfg.Fs, uefiDir, constants.DirPerm) + if err != nil { + return err + } + + isoDir := filepath.Join(isoTmpDir, "iso") + err = utils.MkdirAll(b.cfg.Fs, isoDir, constants.DirPerm) + if err != nil { + return err + } + + if b.cfg.OutDir != "" { + err = utils.MkdirAll(b.cfg.Fs, b.cfg.OutDir, constants.DirPerm) + if err != nil { + b.cfg.Logger.Errorf("Failed creating output folder: %s", b.cfg.OutDir) + return err + } + } + + b.cfg.Logger.Infof("Preparing squashfs root...") + err = b.applySources(rootDir, b.spec.RootFS...) + if err != nil { + b.cfg.Logger.Errorf("Failed installing OS packages: %v", err) + return err + } + err = utils.CreateDirStructure(b.cfg.Fs, rootDir) + if err != nil { + b.cfg.Logger.Errorf("Failed creating root directory structure: %v", err) + return err + } + + b.cfg.Logger.Infof("Preparing EFI image...") + if b.spec.BootloaderInRootFs { + err = b.PrepareEFI(rootDir, uefiDir) + if err != nil { + b.cfg.Logger.Errorf("Failed fetching EFI data: %v", err) + return err + } + } + err = b.applySources(uefiDir, b.spec.UEFI...) + if err != nil { + b.cfg.Logger.Errorf("Failed installing EFI packages: %v", err) + return err + } + + b.cfg.Logger.Infof("Preparing ISO image root tree...") + if b.spec.BootloaderInRootFs { + err = b.PrepareISO(rootDir, isoDir) + if err != nil { + b.cfg.Logger.Errorf("Failed fetching bootloader binaries: %v", err) + return err + } + } + err = b.applySources(isoDir, b.spec.Image...) + if err != nil { + b.cfg.Logger.Errorf("Failed installing ISO image packages: %v", err) + return err + } + + err = b.prepareISORoot(isoDir, rootDir, uefiDir) + if err != nil { + b.cfg.Logger.Errorf("Failed preparing ISO's root tree: %v", err) + return err + } + + b.cfg.Logger.Infof("Creating ISO image...") + err = b.burnISO(isoDir) + if err != nil { + b.cfg.Logger.Errorf("Failed preparing ISO's root tree: %v", err) + return err + } + + return err +} + +func (b BuildISOAction) prepareISORoot(isoDir string, rootDir string, uefiDir string) error { + kernel, initrd, err := b.e.FindKernelInitrd(rootDir) + if err != nil { + b.cfg.Logger.Error("Could not find kernel and/or initrd") + return err + } + err = utils.MkdirAll(b.cfg.Fs, filepath.Join(isoDir, "boot"), constants.DirPerm) + if err != nil { + return err + } + //TODO document boot/kernel and boot/initrd expectation in bootloader config + b.cfg.Logger.Debugf("Copying Kernel file %s to iso root tree", kernel) + err = utils.CopyFile(b.cfg.Fs, kernel, filepath.Join(isoDir, constants.IsoKernelPath)) + if err != nil { + return err + } + + b.cfg.Logger.Debugf("Copying initrd file %s to iso root tree", initrd) + err = utils.CopyFile(b.cfg.Fs, initrd, filepath.Join(isoDir, constants.IsoInitrdPath)) + if err != nil { + return err + } + + b.cfg.Logger.Info("Creating squashfs...") + err = utils.CreateSquashFS(b.cfg.Runner, b.cfg.Logger, rootDir, filepath.Join(isoDir, constants.IsoRootFile), constants.GetDefaultSquashfsOptions()) + if err != nil { + return err + } + + b.cfg.Logger.Info("Creating EFI image...") + err = b.createEFI(uefiDir, filepath.Join(isoDir, constants.IsoEFIPath)) + if err != nil { + return err + } + return nil +} + +func (b BuildISOAction) createEFI(root string, img string) error { + efiSize, err := utils.DirSize(b.cfg.Fs, root) + if err != nil { + return err + } + + // align efiSize to the next 4MB slot + align := int64(4 * 1024 * 1024) + efiSizeMB := (efiSize/align*align + align) / (1024 * 1024) + + err = b.e.CreateFileSystemImage(&v1.Image{ + File: img, + Size: uint(efiSizeMB), + FS: constants.EfiFs, + Label: constants.EfiLabel, + }) + if err != nil { + return err + } + + files, err := b.cfg.Fs.ReadDir(root) + if err != nil { + return err + } + + for _, f := range files { + _, err = b.cfg.Runner.Run("mcopy", "-s", "-i", img, filepath.Join(root, f.Name()), "::") + if err != nil { + return err + } + } + + return nil +} + +func (b BuildISOAction) burnISO(root string) error { + cmd := "xorriso" + var outputFile string + var isoFileName string + + if b.cfg.Date { + currTime := time.Now() + isoFileName = fmt.Sprintf("%s.%s.iso", b.cfg.Name, currTime.Format("20060102")) + } else { + isoFileName = fmt.Sprintf("%s.iso", b.cfg.Name) + } + + outputFile = isoFileName + if b.cfg.OutDir != "" { + outputFile = filepath.Join(b.cfg.OutDir, outputFile) + } + + if exists, _ := utils.Exists(b.cfg.Fs, outputFile); exists { + b.cfg.Logger.Warnf("Overwriting already existing %s", outputFile) + err := b.cfg.Fs.Remove(outputFile) + if err != nil { + return err + } + } + + args := []string{ + "-volid", b.spec.Label, "-joliet", "on", "-padding", "0", + "-outdev", outputFile, "-map", root, "/", "-chmod", "0755", "--", + } + args = append(args, constants.GetXorrisoBooloaderArgs(root)...) + + out, err := b.cfg.Runner.Run(cmd, args...) + b.cfg.Logger.Debugf("Xorriso: %s", string(out)) + if err != nil { + return err + } + + checksum, err := utils.CalcFileChecksum(b.cfg.Fs, outputFile) + if err != nil { + return fmt.Errorf("checksum computation failed: %w", err) + } + err = b.cfg.Fs.WriteFile(fmt.Sprintf("%s.sha256", outputFile), []byte(fmt.Sprintf("%s %s\n", checksum, isoFileName)), 0644) + if err != nil { + return fmt.Errorf("cannot write checksum file: %w", err) + } + + return nil +} + +func (b BuildISOAction) applySources(target string, sources ...*v1.ImageSource) error { + for _, src := range sources { + _, err := b.e.DumpSource(target, src) + if err != nil { + return err + } + } + return nil +} + +func (g *BuildISOAction) PrepareEFI(rootDir, uefiDir string) error { + err := utils.MkdirAll(g.cfg.Fs, filepath.Join(uefiDir, constants.EfiBootPath), constants.DirPerm) + if err != nil { + return err + } + + switch g.cfg.Arch { + case constants.ArchAmd64, constants.Archx86: + err = utils.CopyFile( + g.cfg.Fs, + filepath.Join(rootDir, constants.GrubEfiImagex86), + filepath.Join(uefiDir, constants.GrubEfiImagex86Dest), + ) + case constants.ArchArm64: + err = utils.CopyFile( + g.cfg.Fs, + filepath.Join(rootDir, constants.GrubEfiImageArm64), + filepath.Join(uefiDir, constants.GrubEfiImageArm64Dest), + ) + default: + err = fmt.Errorf("Not supported architecture: %v", g.cfg.Arch) + } + if err != nil { + return err + } + + return g.cfg.Fs.WriteFile(filepath.Join(uefiDir, constants.EfiBootPath, constants.GrubCfg), []byte(constants.GrubEfiCfg), constants.FilePerm) +} + +func (g *BuildISOAction) PrepareISO(rootDir, imageDir string) error { + + err := utils.MkdirAll(g.cfg.Fs, filepath.Join(imageDir, constants.GrubPrefixDir), constants.DirPerm) + if err != nil { + return err + } + + switch g.cfg.Arch { + case constants.ArchAmd64, constants.Archx86: + // Create eltorito image + eltorito, err := g.BuildEltoritoImg(rootDir) + if err != nil { + return err + } + + // Inlude loaders in expected paths + loaderDir := filepath.Join(imageDir, constants.IsoLoaderPath) + err = utils.MkdirAll(g.cfg.Fs, loaderDir, constants.DirPerm) + if err != nil { + return err + } + loaderFiles := []string{eltorito, constants.GrubBootHybridImg} + loaderFiles = append(loaderFiles, strings.Split(constants.SyslinuxFiles, " ")...) + for _, f := range loaderFiles { + err = utils.CopyFile(g.cfg.Fs, filepath.Join(rootDir, f), loaderDir) + if err != nil { + return err + } + } + fontsDir := filepath.Join(loaderDir, "/grub2/fonts") + err = utils.MkdirAll(g.cfg.Fs, fontsDir, constants.DirPerm) + if err != nil { + return err + } + err = utils.CopyFile(g.cfg.Fs, filepath.Join(rootDir, constants.GrubFont), fontsDir) + if err != nil { + return err + } + case constants.ArchArm64: + // TBC + default: + return fmt.Errorf("Not supported architecture: %v", g.cfg.Arch) + } + + // Write grub.cfg file + err = g.cfg.Fs.WriteFile( + filepath.Join(imageDir, constants.GrubPrefixDir, constants.GrubCfg), + []byte(fmt.Sprintf(constants.GrubCfgTemplate, g.spec.GrubEntry, g.spec.Label)), + constants.FilePerm, + ) + if err != nil { + return err + } + + // Include EFI contents in iso root too + return g.PrepareEFI(rootDir, imageDir) +} + +func (g *BuildISOAction) BuildEltoritoImg(rootDir string) (string, error) { + var args []string + args = append(args, "-O", constants.GrubBiosTarget) + args = append(args, "-o", constants.GrubBiosImg) + args = append(args, "-p", constants.GrubPrefixDir) + args = append(args, "-d", constants.GrubI386BinDir) + args = append(args, strings.Split(constants.GrubModules, " ")...) + + chRoot := utils.NewChroot(rootDir, &g.cfg.Config) + out, err := chRoot.Run("grub2-mkimage", args...) + if err != nil { + g.cfg.Logger.Errorf("grub2-mkimage failed: %s", string(out)) + g.cfg.Logger.Errorf("Error: %v", err) + return "", err + } + + concatFiles := func() error { + return utils.ConcatFiles( + g.cfg.Fs, []string{constants.GrubBiosCDBoot, constants.GrubBiosImg}, + constants.GrubEltoritoImg, + ) + } + err = chRoot.RunCallback(concatFiles) + if err != nil { + return "", err + } + return constants.GrubEltoritoImg, nil +} diff --git a/tools-image/enki/pkg/config/config.go b/tools-image/enki/pkg/config/config.go new file mode 100644 index 0000000..5e8ad02 --- /dev/null +++ b/tools-image/enki/pkg/config/config.go @@ -0,0 +1,295 @@ +package config + +import ( + "fmt" + "io" + "io/fs" + "os" + "reflect" + "runtime" + "strings" + + "github.com/kairos-io/enki/internal/version" + "github.com/kairos-io/enki/pkg/constants" + "github.com/kairos-io/enki/pkg/utils" + "github.com/kairos-io/kairos-agent/v2/pkg/cloudinit" + "github.com/kairos-io/kairos-agent/v2/pkg/http" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/mitchellh/mapstructure" + "github.com/sanity-io/litter" + "github.com/sirupsen/logrus" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "github.com/twpayne/go-vfs" + "k8s.io/mount-utils" +) + +var decodeHook = viper.DecodeHook( + mapstructure.ComposeDecodeHookFunc( + UnmarshalerHook(), + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + ), +) + +func WithLogger(logger v1.Logger) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Logger = logger + return nil + } +} + +func WithMounter(mounter mount.Interface) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Mounter = mounter + return nil + } +} + +type GenericOptions func(a *v1.Config) error + +func ReadConfigBuild(configDir string, flags *pflag.FlagSet, mounter mount.Interface) (*v1.BuildConfig, error) { + logger := v1.NewLogger() + if configDir == "" { + configDir = "." + } + + cfg := NewBuildConfig( + WithLogger(logger), + WithMounter(mounter), + ) + + configLogger(cfg.Logger, cfg.Fs) + + viper.AddConfigPath(configDir) + viper.SetConfigType("yaml") + viper.SetConfigName("manifest.yaml") + // If a config file is found, read it in. + _ = viper.MergeInConfig() + + // Bind buildconfig flags + bindGivenFlags(viper.GetViper(), flags) + // merge environment variables on top for rootCmd + viperReadEnv(viper.GetViper(), "BUILD", constants.GetBuildKeyEnvMap()) + + // unmarshal all the vars into the config object + err := viper.Unmarshal(cfg, setDecoder, decodeHook) + if err != nil { + cfg.Logger.Warnf("error unmarshalling config: %s", err) + } + + err = cfg.Sanitize() + cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg)) + return cfg, err +} + +func ReadBuildISO(b *v1.BuildConfig, flags *pflag.FlagSet) (*v1.LiveISO, error) { + iso := NewISO() + vp := viper.Sub("iso") + if vp == nil { + vp = viper.New() + } + // Bind build-iso cmd flags + bindGivenFlags(vp, flags) + // Bind build-iso env vars + viperReadEnv(vp, "ISO", constants.GetISOKeyEnvMap()) + + err := vp.Unmarshal(iso, setDecoder, decodeHook) + if err != nil { + b.Logger.Warnf("error unmarshalling LiveISO: %s", err) + } + err = iso.Sanitize() + b.Logger.Debugf("Loaded LiveISO: %s", litter.Sdump(iso)) + return iso, err +} + +func NewISO() *v1.LiveISO { + return &v1.LiveISO{ + Label: constants.ISOLabel, + GrubEntry: constants.GrubDefEntry, + UEFI: []*v1.ImageSource{}, + Image: []*v1.ImageSource{}, + } +} + +func NewBuildConfig(opts ...GenericOptions) *v1.BuildConfig { + b := &v1.BuildConfig{ + Config: *NewConfig(opts...), + Name: constants.BuildImgName, + } + if len(b.Repos) == 0 { + repo := constants.LuetDefaultRepoURI + if b.Arch != constants.Archx86 { + repo = fmt.Sprintf("%s-%s", constants.LuetDefaultRepoURI, b.Arch) + } + b.Repos = []v1.Repository{{ + Name: "cos", + Type: "docker", + URI: repo, + Arch: b.Arch, + Priority: constants.LuetDefaultRepoPrio, + }} + } + return b +} + +func NewConfig(opts ...GenericOptions) *v1.Config { + log := v1.NewLogger() + arch, err := utils.GolangArchToArch(runtime.GOARCH) + if err != nil { + log.Errorf("invalid arch: %s", err.Error()) + return nil + } + + c := &v1.Config{ + Fs: vfs.OSFS, + Logger: log, + Syscall: &v1.RealSyscall{}, + Client: http.NewClient(), + Repos: []v1.Repository{}, + Arch: arch, + SquashFsNoCompression: true, + } + for _, o := range opts { + err := o(c) + if err != nil { + log.Errorf("error applying config option: %s", err.Error()) + return nil + } + } + + // delay runner creation after we have run over the options in case we use WithRunner + if c.Runner == nil { + c.Runner = &v1.RealRunner{Logger: c.Logger} + } + + // Now check if the runner has a logger inside, otherwise point our logger into it + // This can happen if we set the WithRunner option as that doesn't set a logger + if c.Runner.GetLogger() == nil { + c.Runner.SetLogger(c.Logger) + } + + // Delay the yip runner creation, so we set the proper logger instead of blindly setting it to the logger we create + // at the start of NewRunConfig, as WithLogger can be passed on init, and that would result in 2 different logger + // instances, on the config.Logger and the other on config.CloudInitRunner + if c.CloudInitRunner == nil { + c.CloudInitRunner = cloudinit.NewYipCloudInitRunner(c.Logger, c.Runner, vfs.OSFS) + } + + if c.Mounter == nil { + c.Mounter = mount.New(constants.MountBinary) + } + + return c +} + +func configLogger(log v1.Logger, vfs v1.FS) { + // Set debug level + if viper.GetBool("debug") { + log.SetLevel(v1.DebugLevel()) + } + + // Set formatter so both file and stdout format are equal + log.SetFormatter(&logrus.TextFormatter{ + ForceColors: true, + DisableColors: false, + DisableTimestamp: false, + FullTimestamp: true, + }) + + // Logfile + logfile := viper.GetString("logfile") + if logfile != "" { + o, err := vfs.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, fs.ModePerm) + + if err != nil { + log.Errorf("Could not open %s for logging to file: %s", logfile, err.Error()) + } + + // else set it to both stdout and the file + mw := io.MultiWriter(os.Stdout, o) + log.SetOutput(mw) + } else { // no logfile + if viper.GetBool("quiet") { // quiet is enabled so discard all logging + log.SetOutput(io.Discard) + } else { // default to stdout + log.SetOutput(os.Stdout) + } + } + + v := version.Get() + if log.GetLevel() == logrus.DebugLevel { + log.Debugf("Starting enki version %s on commit %s", v.Version, v.GitCommit) + } else { + log.Infof("Starting enki version %s", v.Version) + } +} + +// BindGivenFlags binds to viper only passed flags, ignoring any non provided flag +func bindGivenFlags(vp *viper.Viper, flagSet *pflag.FlagSet) { + if flagSet != nil { + flagSet.VisitAll(func(f *pflag.Flag) { + if f.Changed { + _ = vp.BindPFlag(f.Name, f) + } + }) + } +} + +// setDecoder sets ZeroFields mastructure attribute to true +func setDecoder(config *mapstructure.DecoderConfig) { + // Make sure we zero fields before applying them, this is relevant for slices + // so we do not merge with any already present value and directly apply whatever + // we got form configs. + config.ZeroFields = true +} + +type Unmarshaler interface { + CustomUnmarshal(interface{}) (bool, error) +} + +func UnmarshalerHook() mapstructure.DecodeHookFunc { + return func(from reflect.Value, to reflect.Value) (interface{}, error) { + // get the destination object address if it is not passed by reference + if to.CanAddr() { + to = to.Addr() + } + // If the destination implements the unmarshaling interface + u, ok := to.Interface().(Unmarshaler) + if !ok { + return from.Interface(), nil + } + // If it is nil and a pointer, create and assign the target value first + if to.IsNil() && to.Type().Kind() == reflect.Ptr { + to.Set(reflect.New(to.Type().Elem())) + u = to.Interface().(Unmarshaler) + } + // Call the custom unmarshaling method + cont, err := u.CustomUnmarshal(from.Interface()) + if cont { + // Continue with the decoding stack + return from.Interface(), err + } + // Decoding finalized + return to.Interface(), err + } +} + +func viperReadEnv(vp *viper.Viper, prefix string, keyMap map[string]string) { + // If we expect to override complex keys in the config, i.e. configs + // that are nested, we probably need to manually do the env stuff + // ourselves, as this will only match keys in the config root + replacer := strings.NewReplacer("-", "_") + vp.SetEnvKeyReplacer(replacer) + + if prefix == "" { + prefix = "ELEMENTAL" + } else { + prefix = fmt.Sprintf("ELEMENTAL_%s", prefix) + } + + // Manually bind keys to env variable if custom names are needed. + for k, v := range keyMap { + _ = vp.BindEnv(k, fmt.Sprintf("%s_%s", prefix, v)) + } +} diff --git a/tools-image/enki/pkg/constants/constants.go b/tools-image/enki/pkg/constants/constants.go new file mode 100644 index 0000000..b1d22de --- /dev/null +++ b/tools-image/enki/pkg/constants/constants.go @@ -0,0 +1,139 @@ +package constants + +import ( + "fmt" + "os" + "path/filepath" +) + +const ( + GrubDefEntry = "Kairos" + EfiLabel = "COS_GRUB" + ISOLabel = "COS_LIVE" + MountBinary = "/usr/bin/mount" + EfiFs = "vfat" + IsoRootFile = "rootfs.squashfs" + IsoEFIPath = "/boot/uefi.img" + LuetDefaultRepoURI = "quay.io/costoolkit/releases-green" + LuetDefaultRepoPrio = 90 + BuildImgName = "elemental" + EfiBootPath = "/EFI/BOOT" + GrubEfiImagex86 = "/usr/share/grub2/x86_64-efi/grub.efi" + GrubEfiImageArm64 = "/usr/share/grub2/arm64-efi/grub.efi" + GrubEfiImagex86Dest = EfiBootPath + "/bootx64.efi" + GrubEfiImageArm64Dest = EfiBootPath + "/bootaa64.efi" + GrubCfg = "grub.cfg" + GrubPrefixDir = "/boot/grub2" + GrubEfiCfg = "search --no-floppy --file --set=root " + IsoKernelPath + + "\nset prefix=($root)" + GrubPrefixDir + + "\nconfigfile $prefix/" + GrubCfg + + GrubFont = "/usr/share/grub2/unicode.pf2" + GrubBootHybridImg = "/usr/share/grub2/i386-pc/boot_hybrid.img" + SyslinuxFiles = "/usr/share/syslinux/isolinux.bin " + + "/usr/share/syslinux/menu.c32 " + + "/usr/share/syslinux/chain.c32 " + + "/usr/share/syslinux/mboot.c32" + IsoLoaderPath = "/boot/x86_64/loader" + GrubCfgTemplate = `search --no-floppy --file --set=root /boot/kernel + set default=0 + set timeout=10 + set timeout_style=menu + set linux=linux + set initrd=initrd + if [ "${grub_cpu}" = "x86_64" -o "${grub_cpu}" = "i386" -o "${grub_cpu}" = "arm64" ];then + if [ "${grub_platform}" = "efi" ]; then + if [ "${grub_cpu}" != "arm64" ]; then + set linux=linuxefi + set initrd=initrdefi + fi + fi + fi + if [ "${grub_platform}" = "efi" ]; then + echo "Please press 't' to show the boot menu on this console" + fi + set font=($root)/boot/${grub_cpu}/loader/grub2/fonts/unicode.pf2 + if [ -f ${font} ];then + loadfont ${font} + fi + menuentry "%s" --class os --unrestricted { + echo Loading kernel... + $linux ($root)/boot/kernel cdroot root=live:CDLABEL=%s rd.live.dir=/ rd.live.squashimg=rootfs.squashfs console=tty1 console=ttyS0 rd.cos.disable + echo Loading initrd... + $initrd ($root)/boot/initrd + } + + if [ "${grub_platform}" = "efi" ]; then + hiddenentry "Text mode" --hotkey "t" { + set textmode=true + terminal_output console + } + fi` + GrubBiosTarget = "i386-pc" + GrubI386BinDir = "/usr/share/grub2/i386-pc" + GrubBiosImg = GrubI386BinDir + "/core.img" + GrubBiosCDBoot = GrubI386BinDir + "/cdboot.img" + GrubEltoritoImg = GrubI386BinDir + "/eltorito.img" + //TODO this list could be optimized + GrubModules = "ext2 iso9660 linux echo configfile search_label search_fs_file search search_fs_uuid " + + "ls normal gzio png fat gettext font minicmd gfxterm gfxmenu all_video xfs btrfs lvm luks " + + "gcry_rijndael gcry_sha256 gcry_sha512 crypto cryptodisk test true loadenv part_gpt " + + "part_msdos biosdisk vga vbe chain boot" + + IsoHybridMBR = "/boot/x86_64/loader/boot_hybrid.img" + IsoBootCatalog = "/boot/x86_64/boot.catalog" + IsoBootFile = "/boot/x86_64/loader/eltorito.img" + + // These paths are arbitrary but coupled to grub.cfg + IsoKernelPath = "/boot/kernel" + IsoInitrdPath = "/boot/initrd" + + // Default directory and file fileModes + DirPerm = os.ModeDir | os.ModePerm + FilePerm = 0666 + NoWriteDirPerm = 0555 | os.ModeDir + TempDirPerm = os.ModePerm | os.ModeSticky | os.ModeDir + + ArchAmd64 = "amd64" + Archx86 = "x86_64" + ArchArm64 = "arm64" +) + +// GetDefaultSquashfsOptions returns the default options to use when creating a squashfs +func GetDefaultSquashfsOptions() []string { + return []string{"-b", "1024k"} +} + +func GetXorrisoBooloaderArgs(root string) []string { + args := []string{ + "-boot_image", "grub", fmt.Sprintf("bin_path=%s", IsoBootFile), + "-boot_image", "grub", fmt.Sprintf("grub2_mbr=%s/%s", root, IsoHybridMBR), + "-boot_image", "grub", "grub2_boot_info=on", + "-boot_image", "any", "partition_offset=16", + "-boot_image", "any", fmt.Sprintf("cat_path=%s", IsoBootCatalog), + "-boot_image", "any", "cat_hidden=on", + "-boot_image", "any", "boot_info_table=on", + "-boot_image", "any", "platform_id=0x00", + "-boot_image", "any", "emul_type=no_emulation", + "-boot_image", "any", "load_size=2048", + "-append_partition", "2", "0xef", filepath.Join(root, IsoEFIPath), + "-boot_image", "any", "next", + "-boot_image", "any", "efi_path=--interval:appended_partition_2:all::", + "-boot_image", "any", "platform_id=0xef", + "-boot_image", "any", "emul_type=no_emulation", + } + return args +} + +// GetBuildKeyEnvMap returns environment variable bindings to BuildConfig data +func GetBuildKeyEnvMap() map[string]string { + return map[string]string{ + "name": "NAME", + } +} + +// GetISOKeyEnvMap returns environment variable bindings to LiveISO data +func GetISOKeyEnvMap() map[string]string { + // None for the time being + return map[string]string{} +} diff --git a/tools-image/enki/pkg/utils/chroot.go b/tools-image/enki/pkg/utils/chroot.go new file mode 100644 index 0000000..01439a0 --- /dev/null +++ b/tools-image/enki/pkg/utils/chroot.go @@ -0,0 +1,218 @@ +/* +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 utils + +import ( + "errors" + "fmt" + "os" + "sort" + "strings" + + "github.com/kairos-io/enki/pkg/constants" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" +) + +// Chroot represents the struct that will allow us to run commands inside a given chroot +type Chroot struct { + path string + defaultMounts []string + extraMounts map[string]string + activeMounts []string + config *v1.Config +} + +func NewChroot(path string, config *v1.Config) *Chroot { + return &Chroot{ + path: path, + defaultMounts: []string{"/dev", "/dev/pts", "/proc", "/sys"}, + extraMounts: map[string]string{}, + activeMounts: []string{}, + config: config, + } +} + +// ChrootedCallback runs the given callback in a chroot environment +func ChrootedCallback(cfg *v1.Config, path string, bindMounts map[string]string, callback func() error) error { + chroot := NewChroot(path, cfg) + chroot.SetExtraMounts(bindMounts) + return chroot.RunCallback(callback) +} + +// Sets additional bind mounts for the chroot enviornment. They are represented +// in a map where the key is the path outside the chroot and the value is the +// path inside the chroot. +func (c *Chroot) SetExtraMounts(extraMounts map[string]string) { + c.extraMounts = extraMounts +} + +// Prepare will mount the defaultMounts as bind mounts, to be ready when we run chroot +func (c *Chroot) Prepare() error { + var err error + keys := []string{} + mountOptions := []string{"bind"} + + if len(c.activeMounts) > 0 { + return errors.New("There are already active mountpoints for this instance") + } + + defer func() { + if err != nil { + c.Close() + } + }() + + for _, mnt := range c.defaultMounts { + mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), mnt) + err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm) + if err != nil { + return err + } + err = c.config.Mounter.Mount(mnt, mountPoint, "bind", mountOptions) + if err != nil { + return err + } + c.activeMounts = append(c.activeMounts, mountPoint) + } + + for k := range c.extraMounts { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), c.extraMounts[k]) + err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm) + if err != nil { + return err + } + err = c.config.Mounter.Mount(k, mountPoint, "bind", mountOptions) + if err != nil { + return err + } + c.activeMounts = append(c.activeMounts, mountPoint) + } + + return nil +} + +// Close will unmount all active mounts created in Prepare on reverse order +func (c *Chroot) Close() error { + failures := []string{} + for len(c.activeMounts) > 0 { + curr := c.activeMounts[len(c.activeMounts)-1] + c.config.Logger.Debugf("Unmounting %s from chroot", curr) + c.activeMounts = c.activeMounts[:len(c.activeMounts)-1] + err := c.config.Mounter.Unmount(curr) + if err != nil { + c.config.Logger.Errorf("Error unmounting %s: %s", curr, err) + failures = append(failures, curr) + } + } + if len(failures) > 0 { + c.activeMounts = failures + return fmt.Errorf("failed closing chroot environment. Unmount failures: %v", failures) + } + return nil +} + +// RunCallback runs the given callback in a chroot environment +func (c *Chroot) RunCallback(callback func() error) (err error) { + var currentPath string + var oldRootF *os.File + + // Store current path + currentPath, err = os.Getwd() + if err != nil { + c.config.Logger.Error("Failed to get current path") + return err + } + defer func() { + tmpErr := os.Chdir(currentPath) + if err == nil && tmpErr != nil { + err = tmpErr + } + }() + + // Store current root + oldRootF, err = c.config.Fs.Open("/") + if err != nil { + c.config.Logger.Errorf("Can't open current root") + return err + } + defer oldRootF.Close() + + if len(c.activeMounts) == 0 { + err = c.Prepare() + if err != nil { + c.config.Logger.Errorf("Can't mount default mounts") + return err + } + defer func() { + tmpErr := c.Close() + if err == nil { + err = tmpErr + } + }() + } + // Change to new dir before running chroot! + err = c.config.Syscall.Chdir(c.path) + if err != nil { + c.config.Logger.Errorf("Can't chdir %s: %s", c.path, err) + return err + } + + err = c.config.Syscall.Chroot(c.path) + if err != nil { + c.config.Logger.Errorf("Can't chroot %s: %s", c.path, err) + return err + } + + // Restore to old root + defer func() { + tmpErr := oldRootF.Chdir() + if tmpErr != nil { + c.config.Logger.Errorf("Can't change to old root dir") + if err == nil { + err = tmpErr + } + } else { + tmpErr = c.config.Syscall.Chroot(".") + if tmpErr != nil { + c.config.Logger.Errorf("Can't chroot back to old root") + if err == nil { + err = tmpErr + } + } + } + }() + + return callback() +} + +// Run executes a command inside a chroot +func (c *Chroot) Run(command string, args ...string) (out []byte, err error) { + callback := func() error { + out, err = c.config.Runner.Run(command, args...) + return err + } + err = c.RunCallback(callback) + if err != nil { + c.config.Logger.Errorf("Cant run command %s with args %v on chroot: %s", command, args, err) + c.config.Logger.Debugf("Output from command: %s", out) + } + return out, err +} diff --git a/tools-image/enki/pkg/utils/cleanstack.go b/tools-image/enki/pkg/utils/cleanstack.go new file mode 100644 index 0000000..92a661f --- /dev/null +++ b/tools-image/enki/pkg/utils/cleanstack.go @@ -0,0 +1,50 @@ +package utils + +import ( + "github.com/hashicorp/go-multierror" +) + +type CleanJob func() error + +// NewCleanStack returns a new stack. +func NewCleanStack() *CleanStack { + return &CleanStack{} +} + +// Stack is a basic LIFO stack that resizes as needed. +type CleanStack struct { + jobs []CleanJob + count int +} + +// Push adds a node to the stack +func (clean *CleanStack) Push(job CleanJob) { + clean.jobs = append(clean.jobs[:clean.count], job) + clean.count++ +} + +// Pop removes and returns a node from the stack in last to first order. +func (clean *CleanStack) Pop() CleanJob { + if clean.count == 0 { + return nil + } + clean.count-- + return clean.jobs[clean.count] +} + +// Cleanup runs the whole cleanup stack. In case of error it runs all jobs +// and returns the first error occurrence. +func (clean *CleanStack) Cleanup(err error) error { + var errs error + if err != nil { + errs = multierror.Append(errs, err) + } + for clean.count > 0 { + job := clean.Pop() + err = job() + if err != nil { + errs = multierror.Append(errs, err) + } + } + return errs +} diff --git a/tools-image/enki/pkg/utils/common.go b/tools-image/enki/pkg/utils/common.go new file mode 100644 index 0000000..05c1349 --- /dev/null +++ b/tools-image/enki/pkg/utils/common.go @@ -0,0 +1,40 @@ +package utils + +import ( + "fmt" + "github.com/kairos-io/enki/pkg/constants" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "strings" +) + +// CreateSquashFS creates a squash file at destination from a source, with options +// TODO: Check validity of source maybe? +func CreateSquashFS(runner v1.Runner, logger v1.Logger, source string, destination string, options []string) error { + // create args + args := []string{source, destination} + // append options passed to args in order to have the correct order + // protect against options passed together in the same string , i.e. "-x add" instead of "-x", "add" + var optionsExpanded []string + for _, op := range options { + optionsExpanded = append(optionsExpanded, strings.Split(op, " ")...) + } + args = append(args, optionsExpanded...) + out, err := runner.Run("mksquashfs", args...) + if err != nil { + logger.Debugf("Error running squashfs creation, stdout: %s", out) + logger.Errorf("Error while creating squashfs from %s to %s: %s", source, destination, err) + return err + } + return nil +} + +func GolangArchToArch(arch string) (string, error) { + switch strings.ToLower(arch) { + case constants.ArchAmd64: + return constants.Archx86, nil + case constants.ArchArm64: + return constants.ArchArm64, nil + default: + return "", fmt.Errorf("invalid arch") + } +} diff --git a/tools-image/enki/pkg/utils/fs.go b/tools-image/enki/pkg/utils/fs.go new file mode 100644 index 0000000..c5fbd8a --- /dev/null +++ b/tools-image/enki/pkg/utils/fs.go @@ -0,0 +1,223 @@ +package utils + +import ( + "crypto/sha256" + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "sync" + "syscall" + "time" + + "github.com/kairos-io/enki/pkg/constants" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + "github.com/twpayne/go-vfs" + "github.com/twpayne/go-vfs/vfst" +) + +// MkdirAll directory and all parents if not existing +func MkdirAll(fs v1.FS, name string, mode os.FileMode) (err error) { + if _, isReadOnly := fs.(*vfs.ReadOnlyFS); isReadOnly { + return permError("mkdir", name) + } + if name, err = fs.RawPath(name); err != nil { + return &os.PathError{Op: "mkdir", Path: name, Err: err} + } + return os.MkdirAll(name, mode) +} + +// permError returns an *os.PathError with Err syscall.EPERM. +func permError(op, path string) error { + return &os.PathError{ + Op: op, + Path: path, + Err: syscall.EPERM, + } +} + +// Copies source file to target file using Fs interface +func CreateDirStructure(fs v1.FS, target string) error { + for _, dir := range []string{"/run", "/dev", "/boot", "/usr/local", "/oem"} { + err := MkdirAll(fs, filepath.Join(target, dir), constants.DirPerm) + if err != nil { + return err + } + } + for _, dir := range []string{"/proc", "/sys"} { + err := MkdirAll(fs, filepath.Join(target, dir), constants.NoWriteDirPerm) + if err != nil { + return err + } + } + err := MkdirAll(fs, filepath.Join(target, "/tmp"), constants.DirPerm) + if err != nil { + return err + } + // Set /tmp permissions regardless the umask setup + err = fs.Chmod(filepath.Join(target, "/tmp"), constants.TempDirPerm) + if err != nil { + return err + } + return nil +} + +// TempDir creates a temp file in the virtual fs +// Took from afero.FS code and adapted +func TempDir(fs v1.FS, dir, prefix string) (name string, err error) { + if dir == "" { + dir = os.TempDir() + } + // This skips adding random stuff to the created temp dir so the temp dir created is predictable for testing + if _, isTestFs := fs.(*vfst.TestFS); isTestFs { + err = MkdirAll(fs, filepath.Join(dir, prefix), 0700) + if err != nil { + return "", err + } + name = filepath.Join(dir, prefix) + return + } + nconflict := 0 + for i := 0; i < 10000; i++ { + try := filepath.Join(dir, prefix+nextRandom()) + err = MkdirAll(fs, try, 0700) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + randmu.Lock() + rand = reseed() + randmu.Unlock() + } + continue + } + if err == nil { + name = try + } + break + } + return +} + +// Random number state. +// We generate random temporary file names so that there's a good +// chance the file doesn't exist yet - keeps the number of tries in +// TempFile to a minimum. +var rand uint32 +var randmu sync.Mutex + +func reseed() uint32 { + return uint32(time.Now().UnixNano() + int64(os.Getpid())) +} + +func nextRandom() string { + randmu.Lock() + r := rand + if r == 0 { + r = reseed() + } + r = r*1664525 + 1013904223 // constants from Numerical Recipes + rand = r + randmu.Unlock() + return strconv.Itoa(int(1e9 + r%1e9))[1:] +} + +// CopyFile Copies source file to target file using Fs interface. If target +// is directory source is copied into that directory using source name file. +func CopyFile(fs v1.FS, source string, target string) (err error) { + return ConcatFiles(fs, []string{source}, target) +} + +// IsDir check if the path is a dir +func IsDir(fs v1.FS, path string) (bool, error) { + fi, err := fs.Stat(path) + if err != nil { + return false, err + } + return fi.IsDir(), nil +} + +// ConcatFiles Copies source files to target file using Fs interface. +// Source files are concatenated into target file in the given order. +// If target is a directory source is copied into that directory using +// 1st source name file. +func ConcatFiles(fs v1.FS, sources []string, target string) (err error) { + if len(sources) == 0 { + return fmt.Errorf("Empty sources list") + } + if dir, _ := IsDir(fs, target); dir { + target = filepath.Join(target, filepath.Base(sources[0])) + } + + targetFile, err := fs.Create(target) + if err != nil { + return err + } + defer func() { + if err == nil { + err = targetFile.Close() + } else { + _ = fs.Remove(target) + } + }() + + var sourceFile *os.File + for _, source := range sources { + sourceFile, err = fs.Open(source) + if err != nil { + break + } + _, err = io.Copy(targetFile, sourceFile) + if err != nil { + break + } + err = sourceFile.Close() + if err != nil { + break + } + } + + return err +} + +// DirSize returns the accumulated size of all files in folder +func DirSize(fs v1.FS, path string) (int64, error) { + var size int64 + err := vfs.Walk(fs, path, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + size += info.Size() + } + return err + }) + return size, err +} + +// Check if a file or directory exists. +func Exists(fs v1.FS, path string) (bool, error) { + _, err := fs.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +// CalcFileChecksum opens the given file and returns the sha256 checksum of it. +func CalcFileChecksum(fs v1.FS, fileName string) (string, error) { + f, err := fs.Open(fileName) + if err != nil { + return "", err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + + return fmt.Sprintf("%x", h.Sum(nil)), nil +} diff --git a/tools-image/entrypoint.sh b/tools-image/entrypoint.sh index dc0f4f7..6263936 100755 --- a/tools-image/entrypoint.sh +++ b/tools-image/entrypoint.sh @@ -2,4 +2,4 @@ set -ex -elemental --config-dir /config $@ \ No newline at end of file +enki --config-dir /config $@ \ No newline at end of file From 664c8d163d8af60d9235ecdd3af886d62d806355 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Tue, 18 Jul 2023 14:14:51 +0200 Subject: [PATCH 2/8] Install packages by luet and merge them Install all packages via luet, converges the rpi packages into one, makes arm use the same generic packages as x86 as they now come from the proper architecture and reduces dockerfile complexity Signed-off-by: Itxaka --- tools-image/Dockerfile | 81 ++++++++----------------------- tools-image/arm/boards/rpi64.sh | 6 +-- tools-image/build-arm-image.sh | 2 +- tools-image/prepare_arm_images.sh | 2 +- 4 files changed, 25 insertions(+), 66 deletions(-) diff --git a/tools-image/Dockerfile b/tools-image/Dockerfile index eea12fc..35c6211 100644 --- a/tools-image/Dockerfile +++ b/tools-image/Dockerfile @@ -19,82 +19,43 @@ RUN go build \ -X github.com/kairos-io/enki/internal/version.gitCommit=$ENKI_COMMIT" \ -o /usr/bin/enki -FROM opensuse/leap:$LEAP_VERSION as luet-install +FROM opensuse/leap:$LEAP_VERSION as default COPY --from=luet /usr/bin/luet /usr/bin/luet ENV LUET_NOLOCK=true ENV TMPDIR=/tmp COPY luet.yaml /etc/luet/luet.yaml -RUN luet install -y livecd/grub2 --system-target /grub2 -RUN luet install -y livecd/grub2-efi-image --system-target /efi -# remove luet tmp files. Side effect of setting the system-target is that it treats it as a root fs -RUN rm -Rf /grub2/var -RUN rm -Rf /efi/var +RUN zypper ref && zypper dup -y +## ISO+ Arm image + Netboot + cloud images Build depedencies +RUN zypper ref && zypper in -y bc qemu-tools jq cdrtools docker git curl gptfdisk kpartx sudo xfsprogs parted util-linux-systemd e2fsprogs curl util-linux udev rsync grub2 dosfstools grub2-x86_64-efi squashfs mtools xorriso lvm2 zstd -## amd64 Live CD artifacts -FROM quay.io/kairos/packages:grub2-livecd-0.0.6 AS grub2 -FROM quay.io/kairos/packages:grub2-efi-image-livecd-0.0.6 AS efi +## Live CD artifacts +RUN luet install -y livecd/grub2 --system-target /grub2 +RUN luet install -y livecd/grub2-efi-image --system-target /efi ## RPI64 - -## Firmware is in the amd64 repo (noarch) -FROM quay.io/kairos/packages:u-boot-rpi64-firmware-2021.01-5.1 AS rpi-u-boot -FROM quay.io/kairos/packages:raspberrypi-firmware-firmware-2021.03.10-2.1 AS rpi-firmware -FROM quay.io/kairos/packages:raspberrypi-firmware-config-firmware-2021.03.10-2.1 AS rpi-firmware-config -FROM quay.io/kairos/packages:raspberrypi-firmware-dt-firmware-2021.03.15-2.1 AS rpi-firmware-dt +RUN luet install -y firmware/u-boot-rpi64 firmware/raspberrypi-firmware firmware/raspberrypi-firmware-config firmware/raspberrypi-firmware-dt --system-target /rpi/ ## PineBook64 Pro -FROM quay.io/kairos/packages:u-boot-rockchip-arm-vendor-blob-0.1 AS pinebook-u-boot - -## Generic ARM artifacts -FROM quay.io/kairos/packages-arm64:grub-efi-static-0.2 AS grub-efi -FROM quay.io/kairos/packages-arm64:grub-config-static-0.3 AS grub-config -FROM quay.io/kairos/packages-arm64:grub-artifacts-static-0.2 AS grub-artifacts +RUN luet install -y arm-vendor-blob/u-boot-rockchip --system-target /pinebookpro/u-boot ## RAW images -FROM quay.io/kairos/packages:grub-efi-static-0.1 AS grub-raw-efi -FROM quay.io/kairos/packages:grub-config-static-0.1 AS grub-raw-config -FROM quay.io/kairos/packages:grub-artifacts-static-0.1 AS grub-raw-artifacts - -FROM opensuse/leap:$LEAP_VERSION -COPY --from=luet /usr/bin/luet /usr/bin/luet - -# ISO files -COPY --from=luet-install /grub2 /grub2 -COPY --from=luet-install /efi /efi - -# RAW images -COPY --from=grub-raw-efi / /raw/grub -COPY --from=grub-raw-config / /raw/grubconfig -COPY --from=grub-raw-artifacts / /raw/grubartifacts - -# RPI64 -COPY --from=rpi-u-boot / /rpi/u-boot -COPY --from=rpi-firmware / /rpi/rpi-firmware -COPY --from=rpi-firmware-config / /rpi/rpi-firmware-config -COPY --from=rpi-firmware-dt / /rpi/rpi-firmware-dt - -# Pinebook -COPY --from=pinebook-u-boot / /pinebookpro/u-boot +RUN luet install -y static/grub-efi --system-target /raw/grub +RUN luet install -y static/grub-config --system-target /raw/grubconfig +RUN luet install -y static/grub-artifacts --system-target /raw/grubartifacts -# Generic -COPY --from=grub-efi / /arm/grub/efi -COPY --from=grub-config / /arm/grub/config -COPY --from=grub-artifacts / /arm/grub/artifacts - -RUN zypper ref && zypper dup -y +# remove luet tmp files. Side effect of setting the system-target is that it treats it as a root fs +# so temporal files are stored in each dir +RUN rm -Rf /grub2/var/tmp +RUN rm -Rf /efi/var/tmp +RUN rm -Rf /rpi/var/tmp +RUN rm -Rf /pinebookpro/u-boot/var/tmp +RUN rm -Rf /raw/grub/var/tmp +RUN rm -Rf /raw/grubconfig/var/tmp +RUN rm -Rf /raw/grubartifacts/var/tmp -## ISO Build depedencies -RUN zypper ref && zypper in -y xfsprogs parted util-linux-systemd e2fsprogs curl util-linux udev rsync grub2 dosfstools grub2-x86_64-efi squashfs mtools xorriso lvm2 zstd RUN mkdir /config -# Arm image build deps -RUN zypper in -y jq docker git curl gptfdisk kpartx sudo -# Netboot -RUN zypper in -y cdrtools -# cloud images -RUN zypper in -y bc qemu-tools - # ISO build config COPY ./config.yaml /config/manifest.yaml COPY ./entrypoint.sh /entrypoint.sh diff --git a/tools-image/arm/boards/rpi64.sh b/tools-image/arm/boards/rpi64.sh index 035d1c0..86fe0aa 100755 --- a/tools-image/arm/boards/rpi64.sh +++ b/tools-image/arm/boards/rpi64.sh @@ -16,9 +16,7 @@ TEMPDIR="$(mktemp -d)" echo $TEMPDIR mount "${device}p1" "${TEMPDIR}" -for dir in /rpi/u-boot /rpi/rpi-firmware /rpi/rpi-firmware-config /rpi/rpi-firmware-dt -do - cp -rfv ${dir}/* $TEMPDIR -done +# Copy all rpi files +cp -rfv /rpi/* $TEMPDIR umount "${TEMPDIR}" diff --git a/tools-image/build-arm-image.sh b/tools-image/build-arm-image.sh index a27a92f..e2f4e1b 100755 --- a/tools-image/build-arm-image.sh +++ b/tools-image/build-arm-image.sh @@ -335,7 +335,7 @@ if [ -z "$EFI" ]; then exit 1 fi -cp -rfv /arm/grub/efi/* $EFI +cp -rfv /efi/* $EFI if [ -n "$EFI" ] && [ -n "$efi_dir" ]; then echo "Copy $efi_dir to EFI directory" cp -rfv $efi_dir/* $EFI diff --git a/tools-image/prepare_arm_images.sh b/tools-image/prepare_arm_images.sh index 21a5a21..6d5bd3c 100755 --- a/tools-image/prepare_arm_images.sh +++ b/tools-image/prepare_arm_images.sh @@ -38,7 +38,7 @@ mkdir -p $WORKDIR/tmpefi # Create the EFI partition FAT16 and include the EFI image and a basic grub.cfg truncate -s $((20*1024*1024)) bootloader/efi.img -cp -rfv /arm/grub/efi/* $WORKDIR/tmpefi +cp -rfv /efi/* $WORKDIR/tmpefi mkfs.fat -F16 -n COS_GRUB bootloader/efi.img mcopy -s -i bootloader/efi.img $WORKDIR/tmpefi/EFI ::EFI From 338b9eed08461e3ef963c05bfde23744a06bc7a6 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Tue, 18 Jul 2023 19:33:49 +0200 Subject: [PATCH 3/8] Fix script location Signed-off-by: Itxaka --- tools-image/build-arm-image.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools-image/build-arm-image.sh b/tools-image/build-arm-image.sh index 0e12a67..053b8e9 100755 --- a/tools-image/build-arm-image.sh +++ b/tools-image/build-arm-image.sh @@ -320,9 +320,9 @@ cp -rfv ${STATEDIR}/cOS/active.img ${RECOVERY}/cOS/recovery.img tune2fs -L ${SYSTEM_LABEL} ${RECOVERY}/cOS/recovery.img # Install real grub config to recovery -cp -rfv /arm/grub/config/* $RECOVERY +cp -rfv /raw/grubconfig/* $RECOVERY mkdir -p $RECOVERY/grub2/fonts -cp -rfv /arm/grub/artifacts/* $RECOVERY/grub2 +cp -rfv /raw/grubartifacts/* $RECOVERY/grub2 mv $RECOVERY/grub2/*pf2 $RECOVERY/grub2/fonts sync From 9ea3d77bb954a75608378216a02df0393f298b95 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Wed, 19 Jul 2023 12:14:44 +0200 Subject: [PATCH 4/8] Rework cmds so they are inline with cobra examples Signed-off-by: Itxaka --- .github/workflows/enki.yml | 24 +++++++++ tools-image/enki/Earthfile | 19 +++++++ tools-image/enki/cmd/build-iso.go | 18 +++---- tools-image/enki/cmd/build-iso_test.go | 70 ++++++++++++++++++++++++++ tools-image/enki/cmd/cmd_suite_test.go | 29 +++++++++++ tools-image/enki/cmd/command_test.go | 53 +++++++++++++++++++ tools-image/enki/go.mod | 5 ++ tools-image/enki/go.sum | 5 ++ 8 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/enki.yml create mode 100644 tools-image/enki/Earthfile create mode 100644 tools-image/enki/cmd/build-iso_test.go create mode 100644 tools-image/enki/cmd/cmd_suite_test.go create mode 100644 tools-image/enki/cmd/command_test.go diff --git a/.github/workflows/enki.yml b/.github/workflows/enki.yml new file mode 100644 index 0000000..fd84ca5 --- /dev/null +++ b/.github/workflows/enki.yml @@ -0,0 +1,24 @@ +--- +name: 'run enki unit tests' + +on: + pull_request: + +concurrency: + group: enki-${{ github.ref || github.head_ref }} + cancel-in-progress: true + +env: + FORCE_COLOR: 1 + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: earthly/actions/setup-earthly@v1 + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Build + run: cd tools-image/enki && earthly -P +test diff --git a/tools-image/enki/Earthfile b/tools-image/enki/Earthfile new file mode 100644 index 0000000..9419411 --- /dev/null +++ b/tools-image/enki/Earthfile @@ -0,0 +1,19 @@ +VERSION 0.7 + +# renovate: datasource=docker depName=golang +ARG --global GO_VERSION=1.20-alpine3.18 + +test: + FROM golang:$GO_VERSION + RUN apk add rsync gcc musl-dev docker jq + WORKDIR /build + COPY . . + RUN go mod download + ARG TEST_PATHS=./... + ARG LABEL_FILTER= + ENV CGO_ENABLED=1 + # Some test require the docker sock exposed + WITH DOCKER + RUN go run github.com/onsi/ginkgo/v2/ginkgo run --label-filter "$LABEL_FILTER" -v --fail-fast --race --covermode=atomic --coverprofile=coverage.out --coverpkg=github.com/rancher/elemental-cli/... -p -r $TEST_PATHS + END + SAVE ARTIFACT coverage.out AS LOCAL coverage.out diff --git a/tools-image/enki/cmd/build-iso.go b/tools-image/enki/cmd/build-iso.go index 21c0ba6..1a0be30 100644 --- a/tools-image/enki/cmd/build-iso.go +++ b/tools-image/enki/cmd/build-iso.go @@ -13,10 +13,9 @@ import ( "k8s.io/mount-utils" ) -// NewBuildISO returns a new instance of the buid-iso subcommand and appends it to -// the root command. requireRoot is to initiate it with or without the CheckRoot -// pre-run check. This method is mostly used for testing purposes. -func NewBuildISO(root *cobra.Command, addCheckRoot bool) *cobra.Command { +// NewBuildISOCmd returns a new instance of the build-iso subcommand and appends it to +// the root command. +func NewBuildISOCmd() *cobra.Command { c := &cobra.Command{ Use: "build-iso SOURCE", Short: "Build bootable installation media ISOs", @@ -26,10 +25,7 @@ func NewBuildISO(root *cobra.Command, addCheckRoot bool) *cobra.Command { " * - is path to file or directory, image name with tag version", Args: cobra.MaximumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { - if addCheckRoot { - return CheckRoot() - } - return nil + return CheckRoot() }, RunE: func(cmd *cobra.Command, args []string) error { path, err := exec.LookPath("mount") @@ -108,7 +104,6 @@ func NewBuildISO(root *cobra.Command, addCheckRoot bool) *cobra.Command { return nil }, } - root.AddCommand(c) c.Flags().StringP("name", "n", "", "Basename of the generated ISO file") c.Flags().StringP("output", "o", "", "Output directory (defaults to current directory)") c.Flags().Bool("date", false, "Adds a date suffix into the generated ISO file") @@ -122,5 +117,6 @@ func NewBuildISO(root *cobra.Command, addCheckRoot bool) *cobra.Command { return c } -// register the subcommand into rootCmd -var _ = NewBuildISO(rootCmd, true) +func init() { + rootCmd.AddCommand(NewBuildISOCmd()) +} diff --git a/tools-image/enki/cmd/build-iso_test.go b/tools-image/enki/cmd/build-iso_test.go new file mode 100644 index 0000000..c38dfe1 --- /dev/null +++ b/tools-image/enki/cmd/build-iso_test.go @@ -0,0 +1,70 @@ +/* +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 cmd + +import ( + "bytes" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spf13/viper" +) + +var _ = Describe("BuildISO", Label("iso", "cmd"), func() { + var buf *bytes.Buffer + BeforeEach(func() { + buf = new(bytes.Buffer) + rootCmd.SetOut(buf) + rootCmd.SetErr(buf) + }) + AfterEach(func() { + viper.Reset() + }) + It("Errors out if no rootfs sources are defined", Label("flags"), func() { + _, _, err := executeCommandC(rootCmd, "build-iso") + fmt.Println(buf) + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("rootfs source image for building ISO was not provided")) + }) + It("Errors out if rootfs is a non valid argument", Label("flags"), func() { + _, _, err := executeCommandC(rootCmd, "build-iso", "/no/image/reference") + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("invalid image reference")) + }) + It("Errors out if overlay roofs path does not exist", Label("flags"), func() { + _, _, err := executeCommandC( + rootCmd, "build-iso", "system/cos", "--overlay-rootfs", "/nonexistingpath", + ) + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("Invalid path")) + }) + It("Errors out if overlay uefi path does not exist", Label("flags"), func() { + _, _, err := executeCommandC( + rootCmd, "build-iso", "someimage:latest", "--overlay-uefi", "/nonexistingpath", + ) + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("Invalid path")) + }) + It("Errors out if overlay iso path does not exist", Label("flags"), func() { + _, _, err := executeCommandC( + rootCmd, "build-iso", "some/image:latest", "--overlay-iso", "/nonexistingpath", + ) + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("Invalid path")) + }) +}) diff --git a/tools-image/enki/cmd/cmd_suite_test.go b/tools-image/enki/cmd/cmd_suite_test.go new file mode 100644 index 0000000..c406f75 --- /dev/null +++ b/tools-image/enki/cmd/cmd_suite_test.go @@ -0,0 +1,29 @@ +/* +Copyright © 2021 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 cmd + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestWhitebox(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "CLI whitebox test suite") +} diff --git a/tools-image/enki/cmd/command_test.go b/tools-image/enki/cmd/command_test.go new file mode 100644 index 0000000..3288d9f --- /dev/null +++ b/tools-image/enki/cmd/command_test.go @@ -0,0 +1,53 @@ +/* +Copyright © 2021 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 cmd + +import ( + "io/ioutil" + "os" + + "github.com/spf13/cobra" +) + +func executeCommandC(cmd *cobra.Command, args ...string) (c *cobra.Command, output string, err error) { + // Set args to command + cmd.SetArgs(args) + // store old stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + // Change stdout to our pipe + os.Stdout = w + // run the command + c, err = cmd.ExecuteC() + if err != nil { + // Remember to restore stdout! + os.Stdout = oldStdout + return nil, "", err + } + err = w.Close() + if err != nil { + // Remember to restore stdout! + os.Stdout = oldStdout + return nil, "", err + } + // Read output from our pipe + out, _ := ioutil.ReadAll(r) + // restore stdout + os.Stdout = oldStdout + + return c, string(out), nil +} diff --git a/tools-image/enki/go.mod b/tools-image/enki/go.mod index 967bfec..53685b2 100644 --- a/tools-image/enki/go.mod +++ b/tools-image/enki/go.mod @@ -6,6 +6,8 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6 github.com/mitchellh/mapstructure v1.5.0 + github.com/onsi/ginkgo/v2 v2.9.7 + github.com/onsi/gomega v1.27.8 github.com/sanity-io/litter v1.5.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 @@ -54,10 +56,13 @@ require ( github.com/go-git/go-git/v5 v5.4.2 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-containerregistry v0.15.2 // indirect + github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.3 // indirect diff --git a/tools-image/enki/go.sum b/tools-image/enki/go.sum index 3ba9200..38b0917 100644 --- a/tools-image/enki/go.sum +++ b/tools-image/enki/go.sum @@ -192,6 +192,7 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -245,6 +246,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -261,6 +263,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -398,9 +401,11 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= From a296b96af5050c4209981d804a4c9f23f8de3774 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Wed, 19 Jul 2023 13:51:29 +0200 Subject: [PATCH 5/8] Add more testing Signed-off-by: Itxaka --- .../enki/pkg/action/action_suite_test.go | 28 ++ tools-image/enki/pkg/action/build-iso.go | 2 +- tools-image/enki/pkg/action/build_test.go | 195 ++++++++++ tools-image/enki/pkg/config/config.go | 49 +++ .../enki/pkg/utils/utils_suite_test.go | 29 ++ tools-image/enki/pkg/utils/utils_test.go | 368 ++++++++++++++++++ 6 files changed, 670 insertions(+), 1 deletion(-) create mode 100644 tools-image/enki/pkg/action/action_suite_test.go create mode 100644 tools-image/enki/pkg/action/build_test.go create mode 100644 tools-image/enki/pkg/utils/utils_suite_test.go create mode 100644 tools-image/enki/pkg/utils/utils_test.go diff --git a/tools-image/enki/pkg/action/action_suite_test.go b/tools-image/enki/pkg/action/action_suite_test.go new file mode 100644 index 0000000..b6d388b --- /dev/null +++ b/tools-image/enki/pkg/action/action_suite_test.go @@ -0,0 +1,28 @@ +/* +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 action_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestActionSuite(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Actions test suite") +} diff --git a/tools-image/enki/pkg/action/build-iso.go b/tools-image/enki/pkg/action/build-iso.go index a2e2e8e..5382693 100644 --- a/tools-image/enki/pkg/action/build-iso.go +++ b/tools-image/enki/pkg/action/build-iso.go @@ -37,7 +37,7 @@ func (b *BuildISOAction) ISORun() (err error) { cleanup := utils.NewCleanStack() defer func() { err = cleanup.Cleanup(err) }() - isoTmpDir, err := utils.TempDir(b.cfg.Fs, "", "elemental-iso") + isoTmpDir, err := utils.TempDir(b.cfg.Fs, "", "enki-iso") if err != nil { return err } diff --git a/tools-image/enki/pkg/action/build_test.go b/tools-image/enki/pkg/action/build_test.go new file mode 100644 index 0000000..fc72b16 --- /dev/null +++ b/tools-image/enki/pkg/action/build_test.go @@ -0,0 +1,195 @@ +/* + 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 action_test + +import ( + "bytes" + "errors" + "fmt" + "github.com/kairos-io/enki/pkg/action" + "github.com/kairos-io/enki/pkg/config" + "github.com/kairos-io/enki/pkg/constants" + "github.com/kairos-io/enki/pkg/utils" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" + "github.com/twpayne/go-vfs" + "github.com/twpayne/go-vfs/vfst" + "path/filepath" +) + +var _ = Describe("Runtime Actions", func() { + var cfg *v1.BuildConfig + var runner *v1mock.FakeRunner + var fs vfs.FS + var logger v1.Logger + var mounter *v1mock.ErrorMounter + var syscall *v1mock.FakeSyscall + var client *v1mock.FakeHTTPClient + var cloudInit *v1mock.FakeCloudInitRunner + var cleanup func() + var memLog *bytes.Buffer + var imageExtractor *v1mock.FakeImageExtractor + BeforeEach(func() { + runner = v1mock.NewFakeRunner() + syscall = &v1mock.FakeSyscall{} + mounter = v1mock.NewErrorMounter() + client = &v1mock.FakeHTTPClient{} + memLog = &bytes.Buffer{} + logger = v1.NewBufferLogger(memLog) + logger.SetLevel(logrus.DebugLevel) + cloudInit = &v1mock.FakeCloudInitRunner{} + fs, cleanup, _ = vfst.NewTestFS(map[string]interface{}{}) + imageExtractor = v1mock.NewFakeImageExtractor(logger) + + cfg = config.NewBuildConfig( + config.WithFs(fs), + config.WithRunner(runner), + config.WithLogger(logger), + config.WithMounter(mounter), + config.WithSyscall(syscall), + config.WithClient(client), + config.WithCloudInitRunner(cloudInit), + config.WithImageExtractor(imageExtractor), + ) + }) + AfterEach(func() { + cleanup() + }) + Describe("Build ISO", Label("iso"), func() { + var iso *v1.LiveISO + BeforeEach(func() { + iso = config.NewISO() + + tmpDir, err := utils.TempDir(fs, "", "test") + Expect(err).ShouldNot(HaveOccurred()) + + cfg.Date = false + cfg.OutDir = tmpDir + + runner.SideEffect = func(cmd string, args ...string) ([]byte, error) { + switch cmd { + case "xorriso": + err := fs.WriteFile(filepath.Join(tmpDir, "elemental.iso"), []byte("profound thoughts"), constants.FilePerm) + return []byte{}, err + default: + return []byte{}, nil + } + } + }) + It("Successfully builds an ISO from a Docker image", func() { + rootSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.RootFS = []*v1.ImageSource{rootSrc} + uefiSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.UEFI = []*v1.ImageSource{uefiSrc} + imageSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.Image = []*v1.ImageSource{imageSrc} + + // Create kernel and vmlinuz + // Thanks to the testfs stuff in utils.TempDir we know what the temp fs is gonna be as + // its predictable + bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot") + err := utils.MkdirAll(fs, bootDir, constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create(filepath.Join(bootDir, "vmlinuz")) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create(filepath.Join(bootDir, "initrd")) + Expect(err).ShouldNot(HaveOccurred()) + + buildISO := action.NewBuildISOAction(cfg, iso) + err = buildISO.ISORun() + + Expect(err).ShouldNot(HaveOccurred()) + }) + It("Fails if kernel or initrd is not found in rootfs", func() { + rootSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.RootFS = []*v1.ImageSource{rootSrc} + uefiSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.UEFI = []*v1.ImageSource{uefiSrc} + imageSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.Image = []*v1.ImageSource{imageSrc} + + By("fails without kernel") + buildISO := action.NewBuildISOAction(cfg, iso) + err := buildISO.ISORun() + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("No file found with prefixes")) + Expect(err.Error()).To(ContainSubstring("uImage Image zImage vmlinuz image")) + + bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot") + err = utils.MkdirAll(fs, bootDir, constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create(filepath.Join(bootDir, "vmlinuz")) + Expect(err).ShouldNot(HaveOccurred()) + + By("fails without initrd") + buildISO = action.NewBuildISOAction(cfg, iso) + err = buildISO.ISORun() + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("No file found with prefixes")) + Expect(err.Error()).To(ContainSubstring("initrd initramfs")) + }) + It("Fails installing image sources", func() { + rootSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.RootFS = []*v1.ImageSource{rootSrc} + uefiSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.UEFI = []*v1.ImageSource{uefiSrc} + imageSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.Image = []*v1.ImageSource{imageSrc} + + imageExtractor.SideEffect = func(imageRef, destination, platformRef string) error { + return fmt.Errorf("uh oh") + } + + buildISO := action.NewBuildISOAction(cfg, iso) + err := buildISO.ISORun() + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("uh oh")) + }) + It("Fails on ISO filesystem creation", func() { + rootSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.RootFS = []*v1.ImageSource{rootSrc} + uefiSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.UEFI = []*v1.ImageSource{uefiSrc} + imageSrc, _ := v1.NewSrcFromURI("oci:image:version") + iso.Image = []*v1.ImageSource{imageSrc} + + bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot") + err := utils.MkdirAll(fs, bootDir, constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create(filepath.Join(bootDir, "vmlinuz")) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create(filepath.Join(bootDir, "initrd")) + Expect(err).ShouldNot(HaveOccurred()) + + runner.SideEffect = func(command string, args ...string) ([]byte, error) { + if command == "xorriso" { + return []byte{}, errors.New("Burn ISO error") + } + return []byte{}, nil + } + + buildISO := action.NewBuildISOAction(cfg, iso) + err = buildISO.ISORun() + + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Burn ISO error")) + }) + }) +}) diff --git a/tools-image/enki/pkg/config/config.go b/tools-image/enki/pkg/config/config.go index 5e8ad02..ba32bf9 100644 --- a/tools-image/enki/pkg/config/config.go +++ b/tools-image/enki/pkg/config/config.go @@ -32,6 +32,13 @@ var decodeHook = viper.DecodeHook( ), ) +func WithFs(fs v1.FS) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Fs = fs + return nil + } +} + func WithLogger(logger v1.Logger) func(r *v1.Config) error { return func(r *v1.Config) error { r.Logger = logger @@ -39,6 +46,13 @@ func WithLogger(logger v1.Logger) func(r *v1.Config) error { } } +func WithSyscall(syscall v1.SyscallInterface) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Syscall = syscall + return nil + } +} + func WithMounter(mounter mount.Interface) func(r *v1.Config) error { return func(r *v1.Config) error { r.Mounter = mounter @@ -46,6 +60,41 @@ func WithMounter(mounter mount.Interface) func(r *v1.Config) error { } } +func WithRunner(runner v1.Runner) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Runner = runner + return nil + } +} + +func WithClient(client v1.HTTPClient) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Client = client + return nil + } +} + +func WithCloudInitRunner(ci v1.CloudInitRunner) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.CloudInitRunner = ci + return nil + } +} + +func WithArch(arch string) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.Arch = arch + return nil + } +} + +func WithImageExtractor(extractor v1.ImageExtractor) func(r *v1.Config) error { + return func(r *v1.Config) error { + r.ImageExtractor = extractor + return nil + } +} + type GenericOptions func(a *v1.Config) error func ReadConfigBuild(configDir string, flags *pflag.FlagSet, mounter mount.Interface) (*v1.BuildConfig, error) { diff --git a/tools-image/enki/pkg/utils/utils_suite_test.go b/tools-image/enki/pkg/utils/utils_suite_test.go new file mode 100644 index 0000000..ec88947 --- /dev/null +++ b/tools-image/enki/pkg/utils/utils_suite_test.go @@ -0,0 +1,29 @@ +/* +Copyright © 2021 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 utils_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestWhitebox(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Utils test suite") +} diff --git a/tools-image/enki/pkg/utils/utils_test.go b/tools-image/enki/pkg/utils/utils_test.go new file mode 100644 index 0000000..fa19baf --- /dev/null +++ b/tools-image/enki/pkg/utils/utils_test.go @@ -0,0 +1,368 @@ +/* +Copyright © 2021 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 utils_test + +import ( + "errors" + "fmt" + conf "github.com/kairos-io/enki/pkg/config" + "github.com/kairos-io/enki/pkg/constants" + "github.com/kairos-io/enki/pkg/utils" + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/twpayne/go-vfs" + "github.com/twpayne/go-vfs/vfst" + "os" + "strings" +) + +var _ = Describe("Utils", Label("utils"), func() { + var config *v1.Config + var runner *v1mock.FakeRunner + var logger v1.Logger + var syscall *v1mock.FakeSyscall + var client *v1mock.FakeHTTPClient + var mounter *v1mock.ErrorMounter + var fs vfs.FS + var cleanup func() + + BeforeEach(func() { + runner = v1mock.NewFakeRunner() + syscall = &v1mock.FakeSyscall{} + mounter = v1mock.NewErrorMounter() + client = &v1mock.FakeHTTPClient{} + logger = v1.NewNullLogger() + // Ensure /tmp exists in the VFS + fs, cleanup, _ = vfst.NewTestFS(nil) + fs.Mkdir("/tmp", constants.DirPerm) + fs.Mkdir("/run", constants.DirPerm) + fs.Mkdir("/etc", constants.DirPerm) + + config = conf.NewConfig( + conf.WithFs(fs), + conf.WithRunner(runner), + conf.WithLogger(logger), + conf.WithMounter(mounter), + conf.WithSyscall(syscall), + conf.WithClient(client), + ) + }) + AfterEach(func() { cleanup() }) + + Describe("Chroot", Label("chroot"), func() { + var chroot *utils.Chroot + BeforeEach(func() { + chroot = utils.NewChroot( + "/whatever", + config, + ) + }) + Describe("ChrootedCallback method", func() { + It("runs a callback in a chroot", func() { + err := utils.ChrootedCallback(config, "/somepath", map[string]string{}, func() error { + return nil + }) + Expect(err).ShouldNot(HaveOccurred()) + err = utils.ChrootedCallback(config, "/somepath", map[string]string{}, func() error { + return fmt.Errorf("callback error") + }) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("callback error")) + }) + }) + Describe("on success", func() { + It("command should be called in the chroot", func() { + _, err := chroot.Run("chroot-command") + Expect(err).To(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + }) + It("commands should be called with a customized chroot", func() { + chroot.SetExtraMounts(map[string]string{"/real/path": "/in/chroot/path"}) + Expect(chroot.Prepare()).To(BeNil()) + defer chroot.Close() + _, err := chroot.Run("chroot-command") + Expect(err).To(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + _, err = chroot.Run("chroot-another-command") + Expect(err).To(BeNil()) + }) + It("runs a callback in a custom chroot", func() { + called := false + callback := func() error { + called = true + return nil + } + err := chroot.RunCallback(callback) + Expect(err).To(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + Expect(called).To(BeTrue()) + }) + }) + Describe("on failure", func() { + It("should return error if chroot-command fails", func() { + runner.ReturnError = errors.New("run error") + _, err := chroot.Run("chroot-command") + Expect(err).NotTo(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + }) + It("should return error if callback fails", func() { + called := false + callback := func() error { + called = true + return errors.New("Callback error") + } + err := chroot.RunCallback(callback) + Expect(err).NotTo(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + Expect(called).To(BeTrue()) + }) + It("should return error if preparing twice before closing", func() { + Expect(chroot.Prepare()).To(BeNil()) + defer chroot.Close() + Expect(chroot.Prepare()).NotTo(BeNil()) + Expect(chroot.Close()).To(BeNil()) + Expect(chroot.Prepare()).To(BeNil()) + }) + It("should return error if failed to chroot", func() { + syscall.ErrorOnChroot = true + _, err := chroot.Run("chroot-command") + Expect(err).ToNot(BeNil()) + Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue()) + Expect(err.Error()).To(ContainSubstring("chroot error")) + }) + It("should return error if failed to mount on prepare", Label("mount"), func() { + mounter.ErrorOnMount = true + _, err := chroot.Run("chroot-command") + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("mount error")) + }) + It("should return error if failed to unmount on close", Label("unmount"), func() { + mounter.ErrorOnUnmount = true + _, err := chroot.Run("chroot-command") + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("failed closing chroot")) + }) + }) + }) + Describe("CopyFile", Label("CopyFile"), func() { + It("Copies source file to target file", func() { + err := utils.MkdirAll(fs, "/some", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create("/some/file") + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Stat("/some/otherfile") + Expect(err).Should(HaveOccurred()) + Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).ShouldNot(HaveOccurred()) + e, err := utils.Exists(fs, "/some/otherfile") + Expect(err).ShouldNot(HaveOccurred()) + Expect(e).To(BeTrue()) + }) + It("Copies source file to target folder", func() { + err := utils.MkdirAll(fs, "/some", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + err = utils.MkdirAll(fs, "/someotherfolder", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Create("/some/file") + Expect(err).ShouldNot(HaveOccurred()) + _, err = fs.Stat("/someotherfolder/file") + Expect(err).Should(HaveOccurred()) + Expect(utils.CopyFile(fs, "/some/file", "/someotherfolder")).ShouldNot(HaveOccurred()) + e, err := utils.Exists(fs, "/someotherfolder/file") + Expect(err).ShouldNot(HaveOccurred()) + Expect(e).To(BeTrue()) + }) + It("Fails to open non existing file", func() { + err := utils.MkdirAll(fs, "/some", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil()) + _, err = fs.Stat("/some/otherfile") + Expect(err).NotTo(BeNil()) + }) + It("Fails to copy on non writable target", func() { + err := utils.MkdirAll(fs, "/some", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + fs.Create("/some/file") + _, err = fs.Stat("/some/otherfile") + Expect(err).NotTo(BeNil()) + fs = vfs.NewReadOnlyFS(fs) + Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil()) + _, err = fs.Stat("/some/otherfile") + Expect(err).NotTo(BeNil()) + }) + }) + Describe("CreateDirStructure", Label("CreateDirStructure"), func() { + It("Creates essential directories", func() { + dirList := []string{"sys", "proc", "dev", "tmp", "boot", "usr/local", "oem"} + for _, dir := range dirList { + _, err := fs.Stat(fmt.Sprintf("/my/root/%s", dir)) + Expect(err).NotTo(BeNil()) + } + Expect(utils.CreateDirStructure(fs, "/my/root")).To(BeNil()) + for _, dir := range dirList { + fi, err := fs.Stat(fmt.Sprintf("/my/root/%s", dir)) + Expect(err).To(BeNil()) + if fi.Name() == "tmp" { + Expect(fmt.Sprintf("%04o", fi.Mode().Perm())).To(Equal("0777")) + Expect(fi.Mode() & os.ModeSticky).NotTo(Equal(0)) + } + if fi.Name() == "sys" { + Expect(fmt.Sprintf("%04o", fi.Mode().Perm())).To(Equal("0555")) + } + } + }) + It("Fails on non writable target", func() { + fs = vfs.NewReadOnlyFS(fs) + Expect(utils.CreateDirStructure(fs, "/my/root")).NotTo(BeNil()) + }) + }) + Describe("DirSize", Label("fs"), func() { + BeforeEach(func() { + err := utils.MkdirAll(fs, "/folder/subfolder", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + f, err := fs.Create("/folder/file") + Expect(err).ShouldNot(HaveOccurred()) + err = f.Truncate(1024) + Expect(err).ShouldNot(HaveOccurred()) + f, err = fs.Create("/folder/subfolder/file") + Expect(err).ShouldNot(HaveOccurred()) + err = f.Truncate(2048) + Expect(err).ShouldNot(HaveOccurred()) + }) + It("Returns the expected size of a test folder", func() { + size, err := utils.DirSize(fs, "/folder") + Expect(err).ShouldNot(HaveOccurred()) + Expect(size).To(Equal(int64(3072))) + }) + }) + Describe("CalcFileChecksum", Label("checksum"), func() { + It("compute correct sha256 checksum", func() { + testData := strings.Repeat("abcdefghilmnopqrstuvz\n", 20) + testDataSHA256 := "7f182529f6362ae9cfa952ab87342a7180db45d2c57b52b50a68b6130b15a422" + + err := fs.Mkdir("/iso", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + err = fs.WriteFile("/iso/test.iso", []byte(testData), 0644) + Expect(err).ShouldNot(HaveOccurred()) + + checksum, err := utils.CalcFileChecksum(fs, "/iso/test.iso") + Expect(err).ShouldNot(HaveOccurred()) + Expect(checksum).To(Equal(testDataSHA256)) + }) + }) + Describe("CreateSquashFS", Label("CreateSquashFS"), func() { + It("runs with no options if none given", func() { + err := utils.CreateSquashFS(runner, logger, "source", "dest", []string{}) + Expect(runner.IncludesCmds([][]string{ + {"mksquashfs", "source", "dest"}, + })).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) + }) + It("runs with options if given", func() { + err := utils.CreateSquashFS(runner, logger, "source", "dest", constants.GetDefaultSquashfsOptions()) + cmd := []string{"mksquashfs", "source", "dest"} + cmd = append(cmd, constants.GetDefaultSquashfsOptions()...) + Expect(runner.IncludesCmds([][]string{ + cmd, + })).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) + }) + It("returns an error if it fails", func() { + runner.ReturnError = errors.New("error") + err := utils.CreateSquashFS(runner, logger, "source", "dest", []string{}) + Expect(runner.IncludesCmds([][]string{ + {"mksquashfs", "source", "dest"}, + })).To(BeNil()) + Expect(err).To(HaveOccurred()) + }) + }) + Describe("CleanStack", Label("CleanStack"), func() { + var cleaner *utils.CleanStack + BeforeEach(func() { + cleaner = utils.NewCleanStack() + }) + It("Adds a callback to the stack and pops it", func() { + var flag bool + callback := func() error { + flag = true + return nil + } + Expect(cleaner.Pop()).To(BeNil()) + cleaner.Push(callback) + poppedJob := cleaner.Pop() + Expect(poppedJob).NotTo(BeNil()) + poppedJob() + Expect(flag).To(BeTrue()) + }) + It("On Cleanup runs callback stack in reverse order", func() { + result := "" + callback1 := func() error { + result = result + "one " + return nil + } + callback2 := func() error { + result = result + "two " + return nil + } + callback3 := func() error { + result = result + "three " + return nil + } + cleaner.Push(callback1) + cleaner.Push(callback2) + cleaner.Push(callback3) + cleaner.Cleanup(nil) + Expect(result).To(Equal("three two one ")) + }) + It("On Cleanup keeps former error and all callbacks are executed", func() { + err := errors.New("Former error") + count := 0 + callback := func() error { + count++ + if count == 2 { + return errors.New("Cleanup Error") + } + return nil + } + cleaner.Push(callback) + cleaner.Push(callback) + cleaner.Push(callback) + err = cleaner.Cleanup(err) + Expect(count).To(Equal(3)) + Expect(err.Error()).To(ContainSubstring("Former error")) + }) + It("On Cleanup error reports first error and all callbacks are executed", func() { + var err error + count := 0 + callback := func() error { + count++ + if count >= 2 { + return errors.New(fmt.Sprintf("Cleanup error %d", count)) + } + return nil + } + cleaner.Push(callback) + cleaner.Push(callback) + cleaner.Push(callback) + err = cleaner.Cleanup(err) + Expect(count).To(Equal(3)) + Expect(err.Error()).To(ContainSubstring("Cleanup error 2")) + Expect(err.Error()).To(ContainSubstring("Cleanup error 3")) + }) + }) +}) From 3938a66c5653b69777f85b57b2f40b22af8f8b01 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Wed, 19 Jul 2023 14:03:37 +0200 Subject: [PATCH 6/8] Drop uneeded stuff Signed-off-by: Itxaka --- .github/workflows/enki.yml | 2 +- tools-image/enki/pkg/action/build-iso.go | 14 ------ tools-image/enki/pkg/config/config.go | 55 +++------------------ tools-image/enki/pkg/constants/constants.go | 15 ------ 4 files changed, 8 insertions(+), 78 deletions(-) diff --git a/.github/workflows/enki.yml b/.github/workflows/enki.yml index fd84ca5..a4521ad 100644 --- a/.github/workflows/enki.yml +++ b/.github/workflows/enki.yml @@ -15,7 +15,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: earthly/actions/setup-earthly@v1 + - uses: earthly/actions-setup@v1.0.7 - name: Checkout code uses: actions/checkout@v3 with: diff --git a/tools-image/enki/pkg/action/build-iso.go b/tools-image/enki/pkg/action/build-iso.go index 5382693..f2408eb 100644 --- a/tools-image/enki/pkg/action/build-iso.go +++ b/tools-image/enki/pkg/action/build-iso.go @@ -82,13 +82,6 @@ func (b *BuildISOAction) ISORun() (err error) { } b.cfg.Logger.Infof("Preparing EFI image...") - if b.spec.BootloaderInRootFs { - err = b.PrepareEFI(rootDir, uefiDir) - if err != nil { - b.cfg.Logger.Errorf("Failed fetching EFI data: %v", err) - return err - } - } err = b.applySources(uefiDir, b.spec.UEFI...) if err != nil { b.cfg.Logger.Errorf("Failed installing EFI packages: %v", err) @@ -96,13 +89,6 @@ func (b *BuildISOAction) ISORun() (err error) { } b.cfg.Logger.Infof("Preparing ISO image root tree...") - if b.spec.BootloaderInRootFs { - err = b.PrepareISO(rootDir, isoDir) - if err != nil { - b.cfg.Logger.Errorf("Failed fetching bootloader binaries: %v", err) - return err - } - } err = b.applySources(isoDir, b.spec.Image...) if err != nil { b.cfg.Logger.Errorf("Failed installing ISO image packages: %v", err) diff --git a/tools-image/enki/pkg/config/config.go b/tools-image/enki/pkg/config/config.go index ba32bf9..0922ebe 100644 --- a/tools-image/enki/pkg/config/config.go +++ b/tools-image/enki/pkg/config/config.go @@ -1,14 +1,6 @@ package config import ( - "fmt" - "io" - "io/fs" - "os" - "reflect" - "runtime" - "strings" - "github.com/kairos-io/enki/internal/version" "github.com/kairos-io/enki/pkg/constants" "github.com/kairos-io/enki/pkg/utils" @@ -21,7 +13,12 @@ import ( "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/twpayne/go-vfs" + "io" + "io/fs" "k8s.io/mount-utils" + "os" + "reflect" + "runtime" ) var decodeHook = viper.DecodeHook( @@ -118,8 +115,6 @@ func ReadConfigBuild(configDir string, flags *pflag.FlagSet, mounter mount.Inter // Bind buildconfig flags bindGivenFlags(viper.GetViper(), flags) - // merge environment variables on top for rootCmd - viperReadEnv(viper.GetViper(), "BUILD", constants.GetBuildKeyEnvMap()) // unmarshal all the vars into the config object err := viper.Unmarshal(cfg, setDecoder, decodeHook) @@ -140,8 +135,6 @@ func ReadBuildISO(b *v1.BuildConfig, flags *pflag.FlagSet) (*v1.LiveISO, error) } // Bind build-iso cmd flags bindGivenFlags(vp, flags) - // Bind build-iso env vars - viperReadEnv(vp, "ISO", constants.GetISOKeyEnvMap()) err := vp.Unmarshal(iso, setDecoder, decodeHook) if err != nil { @@ -166,19 +159,6 @@ func NewBuildConfig(opts ...GenericOptions) *v1.BuildConfig { Config: *NewConfig(opts...), Name: constants.BuildImgName, } - if len(b.Repos) == 0 { - repo := constants.LuetDefaultRepoURI - if b.Arch != constants.Archx86 { - repo = fmt.Sprintf("%s-%s", constants.LuetDefaultRepoURI, b.Arch) - } - b.Repos = []v1.Repository{{ - Name: "cos", - Type: "docker", - URI: repo, - Arch: b.Arch, - Priority: constants.LuetDefaultRepoPrio, - }} - } return b } @@ -266,11 +246,9 @@ func configLogger(log v1.Logger, vfs v1.FS) { } } - v := version.Get() + log.Infof("Starting enki version %s", version.GetVersion()) if log.GetLevel() == logrus.DebugLevel { - log.Debugf("Starting enki version %s on commit %s", v.Version, v.GitCommit) - } else { - log.Infof("Starting enki version %s", v.Version) + log.Debugf("%+v\n", version.Get()) } } @@ -323,22 +301,3 @@ func UnmarshalerHook() mapstructure.DecodeHookFunc { return to.Interface(), err } } - -func viperReadEnv(vp *viper.Viper, prefix string, keyMap map[string]string) { - // If we expect to override complex keys in the config, i.e. configs - // that are nested, we probably need to manually do the env stuff - // ourselves, as this will only match keys in the config root - replacer := strings.NewReplacer("-", "_") - vp.SetEnvKeyReplacer(replacer) - - if prefix == "" { - prefix = "ELEMENTAL" - } else { - prefix = fmt.Sprintf("ELEMENTAL_%s", prefix) - } - - // Manually bind keys to env variable if custom names are needed. - for k, v := range keyMap { - _ = vp.BindEnv(k, fmt.Sprintf("%s_%s", prefix, v)) - } -} diff --git a/tools-image/enki/pkg/constants/constants.go b/tools-image/enki/pkg/constants/constants.go index b1d22de..afeba5c 100644 --- a/tools-image/enki/pkg/constants/constants.go +++ b/tools-image/enki/pkg/constants/constants.go @@ -14,8 +14,6 @@ const ( EfiFs = "vfat" IsoRootFile = "rootfs.squashfs" IsoEFIPath = "/boot/uefi.img" - LuetDefaultRepoURI = "quay.io/costoolkit/releases-green" - LuetDefaultRepoPrio = 90 BuildImgName = "elemental" EfiBootPath = "/EFI/BOOT" GrubEfiImagex86 = "/usr/share/grub2/x86_64-efi/grub.efi" @@ -124,16 +122,3 @@ func GetXorrisoBooloaderArgs(root string) []string { } return args } - -// GetBuildKeyEnvMap returns environment variable bindings to BuildConfig data -func GetBuildKeyEnvMap() map[string]string { - return map[string]string{ - "name": "NAME", - } -} - -// GetISOKeyEnvMap returns environment variable bindings to LiveISO data -func GetISOKeyEnvMap() map[string]string { - // None for the time being - return map[string]string{} -} From e6071f8764c87e86116e48e29e8d14ced388a063 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Wed, 19 Jul 2023 14:12:05 +0200 Subject: [PATCH 7/8] Fix coverage Signed-off-by: Itxaka --- tools-image/enki/Earthfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools-image/enki/Earthfile b/tools-image/enki/Earthfile index 9419411..6f97b0c 100644 --- a/tools-image/enki/Earthfile +++ b/tools-image/enki/Earthfile @@ -14,6 +14,6 @@ test: ENV CGO_ENABLED=1 # Some test require the docker sock exposed WITH DOCKER - RUN go run github.com/onsi/ginkgo/v2/ginkgo run --label-filter "$LABEL_FILTER" -v --fail-fast --race --covermode=atomic --coverprofile=coverage.out --coverpkg=github.com/rancher/elemental-cli/... -p -r $TEST_PATHS + RUN go run github.com/onsi/ginkgo/v2/ginkgo run --label-filter "$LABEL_FILTER" -v --fail-fast --race --covermode=atomic --coverprofile=coverage.out --coverpkg=github.com/kairos-io/enki/... -p -r $TEST_PATHS END SAVE ARTIFACT coverage.out AS LOCAL coverage.out From de9b7bbb7c51703978870fd59c93dfb129246cd7 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Thu, 20 Jul 2023 08:57:54 +0200 Subject: [PATCH 8/8] Use cleanstack from sdk Signed-off-by: Itxaka --- tools-image/enki/go.mod | 14 +++---- tools-image/enki/go.sum | 23 +++++------ tools-image/enki/pkg/action/build-iso.go | 3 +- tools-image/enki/pkg/utils/cleanstack.go | 50 ------------------------ 4 files changed, 21 insertions(+), 69 deletions(-) delete mode 100644 tools-image/enki/pkg/utils/cleanstack.go diff --git a/tools-image/enki/go.mod b/tools-image/enki/go.mod index 53685b2..e3e4914 100644 --- a/tools-image/enki/go.mod +++ b/tools-image/enki/go.mod @@ -3,8 +3,8 @@ module github.com/kairos-io/enki go 1.20 require ( - github.com/hashicorp/go-multierror v1.1.1 github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6 + github.com/kairos-io/kairos-sdk v0.0.9-0.20230719194412-fe26d1de9166 github.com/mitchellh/mapstructure v1.5.0 github.com/onsi/ginkgo/v2 v2.9.7 github.com/onsi/gomega v1.27.8 @@ -19,7 +19,7 @@ require ( ) require ( - atomicgo.dev/cursor v0.1.1 // indirect + atomicgo.dev/cursor v0.1.3 // indirect atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.0.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -67,6 +67,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.15 // indirect @@ -77,7 +78,6 @@ require ( github.com/jaypipes/pcidb v1.0.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07 // indirect github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.16.5 // indirect @@ -102,7 +102,7 @@ require ( github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/xattr v0.4.9 // indirect - github.com/pterm/pterm v0.12.62 // indirect + github.com/pterm/pterm v0.12.63 // indirect github.com/qeesung/image2ascii v1.0.1 // indirect github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09 // indirect github.com/rivo/uniseg v0.4.4 // indirect @@ -132,9 +132,9 @@ require ( golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.9.1 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect diff --git a/tools-image/enki/go.sum b/tools-image/enki/go.sum index 38b0917..f606405 100644 --- a/tools-image/enki/go.sum +++ b/tools-image/enki/go.sum @@ -1,6 +1,6 @@ atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= -atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4= -atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/cursor v0.1.3 h1:w8GcylMdZRyFzvDiGm3wy3fhZYYT7BwaqNjUFHxo0NU= +atomicgo.dev/cursor v0.1.3/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= atomicgo.dev/schedule v0.0.2 h1:2e/4KY6t3wokja01Cyty6qgkQM8MotJzjtqCH70oX2Q= @@ -326,8 +326,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6 h1:5tl86nNswp+f91Oudzoo7ceSfQXd/Fhd1fkO85/mVSU= github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6/go.mod h1:+zG2JtLuTE9TDwiXJg9/jqcD/G59PhdN+Z0G5dcGiJk= -github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07 h1:WctdkLqZBl8bViFPoqnRtxU5Vf63G9c1lTLem6F3d4s= -github.com/kairos-io/kairos-sdk v0.0.9-0.20230620064343-df990bf49a07/go.mod h1:Z+1CLqMZq97bzwX2XSIArr8EoniMth3mMYkOOb8L3QY= +github.com/kairos-io/kairos-sdk v0.0.9-0.20230719194412-fe26d1de9166 h1:xAsvPm5a7ivervVjkJ5DIZWOQww4Za75erEwZ1Xcd7I= +github.com/kairos-io/kairos-sdk v0.0.9-0.20230719194412-fe26d1de9166/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0= github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk= github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c/go.mod h1:VOfm8h1NySetVlpHDSnbpCMsvCgYaU+YDn4XezUy2+4= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -448,8 +448,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.62 h1:Xjj5Wl6UR4Il9xOiDUOZRwReRTdO75if/JdWsn9I59s= -github.com/pterm/pterm v0.12.62/go.mod h1:+c3ujjE7N5qmNx6eKAa7YVSC6m/gCorJJKhzwYTbL90= +github.com/pterm/pterm v0.12.63 h1:fHlrpFiI9qLtEU0TWDWMU+tAt4qKJ/s157BEAPtGm8w= +github.com/pterm/pterm v0.12.63/go.mod h1:Bq1eoUJ6BhUzzXG8WxA4l7T3s7d3Ogwg7v9VXlsVat0= github.com/qeesung/image2ascii v1.0.1 h1:Fe5zTnX/v/qNC3OC4P/cfASOXS501Xyw2UUcgrLgtp4= github.com/qeesung/image2ascii v1.0.1/go.mod h1:kZKhyX0h2g/YXa/zdJR3JnLnJ8avHjZ3LrvEKSYyAyU= github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09 h1:/yNp//3ZC5J7KUaUPDmomQ78j8VUD/2T/uT+TvS4M0w= @@ -764,16 +764,16 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -784,8 +784,9 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/tools-image/enki/pkg/action/build-iso.go b/tools-image/enki/pkg/action/build-iso.go index f2408eb..78c6bf0 100644 --- a/tools-image/enki/pkg/action/build-iso.go +++ b/tools-image/enki/pkg/action/build-iso.go @@ -10,6 +10,7 @@ import ( "github.com/kairos-io/enki/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/elemental" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + sdk "github.com/kairos-io/kairos-sdk/utils" ) type BuildISOAction struct { @@ -34,7 +35,7 @@ func NewBuildISOAction(cfg *v1.BuildConfig, spec *v1.LiveISO, opts ...BuildISOAc // ISORun will install the system from a given configuration func (b *BuildISOAction) ISORun() (err error) { - cleanup := utils.NewCleanStack() + cleanup := sdk.NewCleanStack() defer func() { err = cleanup.Cleanup(err) }() isoTmpDir, err := utils.TempDir(b.cfg.Fs, "", "enki-iso") diff --git a/tools-image/enki/pkg/utils/cleanstack.go b/tools-image/enki/pkg/utils/cleanstack.go deleted file mode 100644 index 92a661f..0000000 --- a/tools-image/enki/pkg/utils/cleanstack.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "github.com/hashicorp/go-multierror" -) - -type CleanJob func() error - -// NewCleanStack returns a new stack. -func NewCleanStack() *CleanStack { - return &CleanStack{} -} - -// Stack is a basic LIFO stack that resizes as needed. -type CleanStack struct { - jobs []CleanJob - count int -} - -// Push adds a node to the stack -func (clean *CleanStack) Push(job CleanJob) { - clean.jobs = append(clean.jobs[:clean.count], job) - clean.count++ -} - -// Pop removes and returns a node from the stack in last to first order. -func (clean *CleanStack) Pop() CleanJob { - if clean.count == 0 { - return nil - } - clean.count-- - return clean.jobs[clean.count] -} - -// Cleanup runs the whole cleanup stack. In case of error it runs all jobs -// and returns the first error occurrence. -func (clean *CleanStack) Cleanup(err error) error { - var errs error - if err != nil { - errs = multierror.Append(errs, err) - } - for clean.count > 0 { - job := clean.Pop() - err = job() - if err != nil { - errs = multierror.Append(errs, err) - } - } - return errs -}