From a9075902a3ed4dbb6d0a9e7ff76a2fecd6f71f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Wed, 28 Jan 2026 18:17:56 +0200 Subject: [PATCH] working commit --- Makefile.am | 18 ++++-- Makefile.in | 111 ++++++++++++++++++++++++-------- app/config/config.go | 80 ++++++++++++++++++++--- app/config/variant.go | 1 + app/config/variant.go.in | 1 + app/server/server.go | 135 +++++++++++++++++++++++++++++++++++++-- go.mod | 2 + go.sum | 7 ++ 8 files changed, 308 insertions(+), 47 deletions(-) diff --git a/Makefile.am b/Makefile.am index 78f9f47..4e11396 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,21 +2,29 @@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo GOFLAGS= -v - +bin_PROGRAMS = mstorectl sbin_PROGRAMS = mstored -mstored_SOURCES = cmd/mstored/main.go +mstorectl_SOURCES = \ + cmd/mstorectl/main.go + cmd/mstorectl/file.go + +mstored_SOURCES = \ + cmd/mstored/main.go + +mstorectl$(EXEEXT): $(mstorectl_SOURCES) + env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o mstorectl$(EXEEXT) $(mstorectl_SOURCES) mstored$(EXEEXT): $(mstored_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES) -run: mstored$(EXEEXT) - $(CWD)/mstored$(EXEEXT) +run: $(mstored_SOURCES) + cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . CWD=$(shell pwd) format: - dirs=$$($(FIND) $(CWD) -name '*.go' | $(XARGS) -n1 dirname | $(SORT) | $(UNIQ)); \ + @dirs=$$($(FIND) $(CWD) -name '*.go' | $(XARGS) -n1 dirname | $(SORT) | $(UNIQ)); \ for dir in $$dirs;do \ (echo "====$$dir===="; cd $$dir && $(GO) fmt .); \ done diff --git a/Makefile.in b/Makefile.in index 349d8cf..c2ecc1d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,6 +88,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +bin_PROGRAMS = mstorectl$(EXEEXT) sbin_PROGRAMS = mstored$(EXEEXT) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -101,8 +102,11 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = app/config/variant.go CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(sbindir)" -PROGRAMS = $(sbin_PROGRAMS) +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" +PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) +am_mstorectl_OBJECTS = +mstorectl_OBJECTS = $(am_mstorectl_OBJECTS) +mstorectl_LDADD = $(LDADD) am_mstored_OBJECTS = mstored_OBJECTS = $(am_mstored_OBJECTS) mstored_LDADD = $(LDADD) @@ -133,8 +137,8 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(mstored_SOURCES) -DIST_SOURCES = $(mstored_SOURCES) +SOURCES = $(mstorectl_SOURCES) $(mstored_SOURCES) +DIST_SOURCES = $(mstorectl_SOURCES) $(mstored_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -282,7 +286,12 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo GOFLAGS = -v -mstored_SOURCES = cmd/mstored/main.go +mstorectl_SOURCES = \ + cmd/mstorectl/main.go + +mstored_SOURCES = \ + cmd/mstored/main.go + CWD = $(shell pwd) all: all-am @@ -322,6 +331,48 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): app/config/variant.go: $(top_builddir)/config.status $(top_srcdir)/app/config/variant.go.in cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ @@ -605,7 +656,7 @@ check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: - for dir in "$(DESTDIR)$(sbindir)"; do \ + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -640,7 +691,8 @@ maintainer-clean-generic: @echo "it deletes files that may require special tools to rebuild." clean: clean-am -clean-am: clean-generic clean-local clean-sbinPROGRAMS mostlyclean-am +clean-am: clean-binPROGRAMS clean-generic clean-local \ + clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) @@ -666,7 +718,7 @@ install-dvi: install-dvi-am install-dvi-am: -install-exec-am: install-sbinPROGRAMS +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS install-html: install-html-am @@ -706,38 +758,43 @@ ps: ps-am ps-am: -uninstall-am: uninstall-sbinPROGRAMS +uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \ - clean-cscope clean-generic clean-local clean-sbinPROGRAMS \ - cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ - dist-zstd distcheck distclean distclean-compile \ - distclean-generic distclean-tags distcleancheck distdir \ - distuninstallcheck dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-sbinPROGRAMS install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am uninstall-sbinPROGRAMS + clean-binPROGRAMS clean-cscope clean-generic clean-local \ + clean-sbinPROGRAMS cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip dist-zstd distcheck distclean \ + distclean-compile distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-sbinPROGRAMS .PRECIOUS: Makefile + cmd/mstorectl/file.go + +mstorectl$(EXEEXT): $(mstorectl_SOURCES) + env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o mstorectl$(EXEEXT) $(mstorectl_SOURCES) mstored$(EXEEXT): $(mstored_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES) -run: mstored$(EXEEXT) - $(CWD)/mstored$(EXEEXT) +run: $(mstored_SOURCES) + cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . format: - dirs=$$($(FIND) $(CWD) -name '*.go' | $(XARGS) -n1 dirname | $(SORT) | $(UNIQ)); \ + @dirs=$$($(FIND) $(CWD) -name '*.go' | $(XARGS) -n1 dirname | $(SORT) | $(UNIQ)); \ for dir in $$dirs;do \ (echo "====$$dir===="; cd $$dir && $(GO) fmt .); \ done diff --git a/app/config/config.go b/app/config/config.go index b437f19..d3f0a51 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -1,10 +1,14 @@ package config -type Config struct { - Service Service `json:"service" yaml:"service"` - Database Database `json:"database" yaml:"database"` - Storage Storage `json:"storage" yaml:"storage"` -} +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "sigs.k8s.io/yaml" +) type Service struct { Address string `json:"address" yaml:"address"` @@ -19,8 +23,23 @@ type Storage struct { Basepath string `json:"basepath" yaml:"basepath"` } -func NewConfig() (*Config, error) { - var err error +type Config struct { + Service Service `json:"service" yaml:"service"` + Database Database `json:"database" yaml:"database"` + Storage Storage `json:"storage" yaml:"storage"` + AsDaemon bool `json:"asDaemon" yaml:"asDaemon"` + Logpath string `json:"logpath" yaml:"logpath"` + Runpath string `json:"runpath" yaml:"runpath"` + Version string `json:"version" yaml:"version"` +} + +func NewConfig() *Config { + logfile := fmt.Sprintf("%s.log", srvname) + logpath := filepath.Join(logdir, logfile) + + runfile := fmt.Sprintf("%s.run", srvname) + runpath := filepath.Join(rundir, runfile) + return &Config{ Service: Service{ Address: "0.0.0.0", @@ -32,5 +51,50 @@ func NewConfig() (*Config, error) { Storage: Storage{ Basepath: datadir, }, - }, err + AsDaemon: false, + Logpath: logpath, + Runpath: runpath, + Version: version, + } +} + +func (conf *Config) String() string { + confbytes, _ := yaml.Marshal(conf) + return string(confbytes) +} + +func (conf *Config) ReadConfigfile() error { + conffile := fmt.Sprintf("%sd.yaml", srvname) + confpath := filepath.Join(confdir, conffile) + + confdata, err := ioutil.ReadFile(confpath) + if err != nil { + return err + } + err = yaml.Unmarshal(confdata, conf) + if err != nil { + return err + } + return err +} + +func (conf *Config) ReadOptions() error { + var err error + exename := filepath.Base(os.Args[0]) + + flag.Int64Var(&conf.Service.Port, "port", conf.Service.Port, "listen port") + flag.BoolVar(&conf.AsDaemon, "daemon", conf.AsDaemon, "run as daemon") + + help := func() { + fmt.Println("") + fmt.Printf("Usage: %s [option]\n", exename) + fmt.Println("") + fmt.Println("Options:") + flag.PrintDefaults() + fmt.Println("") + } + flag.Usage = help + flag.Parse() + + return err } diff --git a/app/config/variant.go b/app/config/variant.go index e6d4d37..9bba10e 100644 --- a/app/config/variant.go +++ b/app/config/variant.go @@ -6,4 +6,5 @@ const ( logdir = "/home/ziggi/Projects/mstore/tmp/log" datadir = "/home/ziggi/Projects/mstore/tmp/data" version = "0.1.0" + srvname = "mstored" ) diff --git a/app/config/variant.go.in b/app/config/variant.go.in index 21466af..2854366 100644 --- a/app/config/variant.go.in +++ b/app/config/variant.go.in @@ -6,4 +6,5 @@ const ( logdir = "@srv_logdir@" datadir = "@srv_datadir@" version = "@PACKAGE_VERSION@" + srvname = "@PACKAGE_NAME@d" ) diff --git a/app/server/server.go b/app/server/server.go index e704f95..5d0f422 100644 --- a/app/server/server.go +++ b/app/server/server.go @@ -6,8 +6,8 @@ import ( "os/signal" "os/user" //"os/user" - //"path/filepath" - //"strconv" + "path/filepath" + "strconv" //"sync" "syscall" //"time" @@ -45,11 +45,19 @@ func (srv *Server) Handler() *handler.Handler { func (srv *Server) Configure() error { var err error srv.logg.Infof("Server configure") - srv.conf, err = config.NewConfig() + srv.conf = config.NewConfig() + if err != nil { + return err + } + err = srv.conf.ReadConfigfile() + if err != nil { + //srv.logg.Warningf("Error loading config file: %v", err) + //return err + } + err = srv.conf.ReadOptions() if err != nil { return err } - return err } @@ -57,21 +65,39 @@ func (srv *Server) Build() error { var err error srv.logg.Infof("Server build") + confDump := srv.conf.String() + srv.logg.Infof("Current server configuration is:\n%s\n", confDump) + + if srv.conf.AsDaemon { + logdir := filepath.Dir(srv.conf.Logpath) + srv.logg.Infof("Create log directory %s", logdir) + err = os.MkdirAll(logdir, 0750) + if err != nil { + return err + } + rundir := filepath.Dir(srv.conf.Runpath) + srv.logg.Infof("Create run directory %s", rundir) + err = os.MkdirAll(rundir, 0750) + if err != nil { + return err + } + } + // Database create - srv.logg.Infof("Create database directory") dbdir := srv.conf.Database.Basepath + srv.logg.Infof("Create database directory %s ", dbdir) err = os.MkdirAll(dbdir, 0750) if err != nil { return err } mdb := maindb.NewDatabase(dbdir) - srv.logg.Infof("Open database") + srv.logg.Infof("Open main database") err = mdb.OpenDatabase() if err != nil { return err } - srv.logg.Infof("Initialize database") + srv.logg.Infof("Initialize main database") err = mdb.InitDatabase() if err != nil { return err @@ -162,3 +188,98 @@ func (srv *Server) Run() error { } return err } + +func (srv *Server) PseudoFork() error { + const successExit int = 0 + var keyEnv string = "IMX0LTSELMRF8K" + var err error + + _, isChild := os.LookupEnv(keyEnv) + switch { + case !isChild: + os.Setenv(keyEnv, "TRUE") + + procAttr := syscall.ProcAttr{} + cwd, err := os.Getwd() + if err != nil { + return err + } + var sysFiles = make([]uintptr, 3) + sysFiles[0] = uintptr(syscall.Stdin) + sysFiles[1] = uintptr(syscall.Stdout) + sysFiles[2] = uintptr(syscall.Stderr) + + procAttr.Files = sysFiles + procAttr.Env = os.Environ() + procAttr.Dir = cwd + + _, err = syscall.ForkExec(os.Args[0], os.Args, &procAttr) + if err != nil { + return err + } + os.Exit(successExit) + case isChild: + _, err = syscall.Setsid() + if err != nil { + return err + } + } + os.Unsetenv(keyEnv) + return err +} + +func (srv *Server) Daemonize() error { + var err error + if srv.conf.AsDaemon { + // Restart process process + err = srv.PseudoFork() + if err != nil { + return err + } + + // Redirect stdin + nullFile, err := os.OpenFile("/dev/null", os.O_RDWR, 0) + if err != nil { + return err + } + err = syscall.Dup2(int(nullFile.Fd()), int(os.Stdin.Fd())) + if err != nil { + return err + } + // Redirect stderr and stout + logdir := filepath.Dir(srv.conf.Logpath) + err = os.MkdirAll(logdir, 0750) + if err != nil { + return err + } + logFile, err := os.OpenFile(srv.conf.Logpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640) + if err != nil { + return err + } + err = syscall.Dup2(int(logFile.Fd()), int(os.Stdout.Fd())) + if err != nil { + return err + } + err = syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())) + if err != nil { + return err + } + // Write process ID + rundir := filepath.Dir(srv.conf.Runpath) + err = os.MkdirAll(rundir, 0750) + if err != nil { + return err + } + pidFile, err := os.OpenFile(srv.conf.Runpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + return err + } + defer pidFile.Close() + currPid := os.Getpid() + _, err = pidFile.WriteString(strconv.Itoa(currPid)) + if err != nil { + return err + } + } + return err +} diff --git a/go.mod b/go.mod index 24e5008..49b77cf 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.33 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 + sigs.k8s.io/yaml v1.6.0 ) require ( @@ -15,5 +16,6 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.9 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index ae0b668..e8031a7 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ 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/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -25,8 +27,13 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=