From 286da66f5a2231e628d0fd25e9618d778072f383 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Thu, 21 Dec 2023 13:24:27 -0600 Subject: [PATCH] implement persistent storage for services The manifest.yaml now has a storage section where requests for additional named partitions can be added, e.g. storage: - label: zot-data persistent: true nsgroup: "zot" size: 30G Each target also has a storage section specifying a list of labels to mount and destinations at which to mount them. A nonpersistent storage label can be used if some target expects to use a lot of temporary space with which it doesn't want to fill up the shared /scratch-writes. Persistent volumes can be used to maintain data across reboots. Signed-off-by: Serge Hallyn --- cmd/trust/launch.go | 8 +- docs/storage.md | 74 ++++++++++++++++ go.mod | 44 +++++----- go.sum | 80 ++++++++++-------- pkg/mosconfig/files.go | 172 +++++++++++++++++++++++++++++++++----- pkg/mosconfig/install.go | 9 ++ pkg/mosconfig/manifest.go | 8 +- pkg/mosconfig/mos.go | 62 ++++++++++++-- pkg/mosconfig/uidmap.go | 18 ++-- pkg/mosconfig/update.go | 22 ++++- pkg/mosconfig/utils.go | 13 +++ pkg/provider/kvm.go | 19 +++-- pkg/provider/provider.go | 4 +- pkg/utils/utils.go | 26 ++++++ 14 files changed, 453 insertions(+), 106 deletions(-) create mode 100644 docs/storage.md diff --git a/cmd/trust/launch.go b/cmd/trust/launch.go index d8212ce..9505c28 100644 --- a/cmd/trust/launch.go +++ b/cmd/trust/launch.go @@ -31,6 +31,10 @@ var launchCmd = cli.Command{ Usage: "Serial number UUID to assign to the machine, empty to use a random UUID", Value: "", }, + cli.BoolFlag{ + Name: "debug", + Usage: "show console during provision and install", + }, cli.BoolFlag{ Name: "skip-provisioning", Usage: "Skip provisioning the machine", @@ -142,7 +146,7 @@ func doLaunch(ctx *cli.Context) error { } }() - if err := m.RunProvision(); err != nil { + if err := m.RunProvision(ctx.Bool("debug")); err != nil { return errors.Wrapf(err, "Failed to run provisioning ISO") } @@ -151,7 +155,7 @@ func doLaunch(ctx *cli.Context) error { return nil } - if err := m.RunInstall(); err != nil { + if err := m.RunInstall(ctx.Bool("debug")); err != nil { return errors.Wrapf(err, "Failed to run install ISO") } diff --git a/docs/storage.md b/docs/storage.md new file mode 100644 index 0000000..5045441 --- /dev/null +++ b/docs/storage.md @@ -0,0 +1,74 @@ +# Storage for targes + +Following is an example manifest.yaml showing how to specify storage +for targets: + +``` +storage: + - label: zot-data + persistent: true + nsgroup: "zot" + size: 30G + - label: zot-config + persistent: true + nsgroup: "zot" + size: 1G + - label: zot-tmp + persistent: false + nsgroup: "zot" + size: 1G + - label: nginx-data + persistent: true + nsgroup: "zot" + size: 1G +targets: + - service_name: zot + source: docker://zothub.io/machine/bootkit/demo-zot:0.0.4-squashfs + version: 1.0.0 + nsgroup: zot + storage: + - dest: /zot + label: zot-data + - dest: /etc/zot + label: zot-config + - dest: /tmp + label: zot-tmp + - service_name: nginx + source: docker://zothub.io/machine/bootkit/demo-nginx:0.0.4-squashfs + version: 1.0.0 + nsgroup: zot + storage: + - dest: /data/zot + label: zot-data + - dest: /var/lib/www + label: nginx-data +``` + +When a target starts up, its rootfs is an overlay of a writeable tmpfs +over the source OCI image (which itself is an overlay of dmverity-protected +squashfs images). The writeable overlays are all in a shared partition +mounted at /scratch-writes. In order to provide persistent storage +across boots, shared storage between containers, or a larger private +ephemeral storage which does not risk filling up /scratch-writes, +extra storage can be requested. + +In the above example, four additional storage volumes are requested. The +30G volume called zot-data will be persistent, so its contents will be +saved across boots. In contrast, zot-tmp is not persistent, so its contents +will be deleted across reboots. All four are in the 'nsgroup zot', which +both of the targets, zot and nginx, run in. The nsgroup is a named +user namespace mapping, so uid 0 will be represented by the same host +uid (for instance 100000) for all. + +Note that if nginx were not placed into nsgroup 'zot', it would still +be able to mount zot-data, however all files would appear as +owned by nobody:nogroup, and nginx would get the world access rights. + +Each target now has an optional storage section, where it can +specify which volumes it should mount, and where. + +On boot, the machine will first create the storage volumes, and uid-shift +them if needed. If a non-persistent volume already exists, it will be +deleted and recreated. + +All storage volumes are created as ext4 filesystems. diff --git a/go.mod b/go.mod index 4be3fe3..6f69685 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/fatih/color v1.15.0 github.com/foxboron/go-uefi v0.0.0-20230218004016-d1bb9a12f92c github.com/go-git/go-git/v5 v5.4.2 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.5.0 github.com/jsipprell/keyctl v1.0.4 github.com/lxc/lxd v0.0.0-20230130192612-1e882f91a2da github.com/msoap/byline v1.1.1 @@ -22,7 +22,7 @@ require ( github.com/project-machine/machine v0.1.2 github.com/project-stacker/stacker v0.21.2 github.com/rekby/gpt v0.0.0-20200614112001-7da10aec5566 - github.com/stretchr/testify v1.8.3 + github.com/stretchr/testify v1.8.4 github.com/urfave/cli v1.22.12 golang.org/x/sys v0.15.0 golang.org/x/text v0.14.0 @@ -49,10 +49,10 @@ require ( github.com/containers/ocicrypt v1.1.7 // indirect github.com/containers/storage v1.45.4 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect @@ -85,8 +85,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-containerregistry v0.14.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/imdario/mergo v0.3.15 // indirect @@ -95,18 +95,18 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect - github.com/klauspost/compress v1.16.3 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/letsencrypt/boulder v0.0.0-20230213213521-fdfea0d469b6 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/martinjungblut/go-cryptsetup v0.0.0-20220520180014-fd0874fd07a6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect @@ -116,7 +116,7 @@ require ( github.com/opencontainers/runc v1.1.5 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pborman/uuid v1.2.1 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/pkg/xattr v0.4.9 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/proglottis/gpgme v0.1.3 // indirect @@ -131,8 +131,8 @@ require ( github.com/sigstore/fulcio v1.1.0 // indirect github.com/sigstore/rekor v1.2.0 // indirect github.com/sigstore/sigstore v1.6.4 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/spf13/afero v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/afero v1.11.0 // indirect github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/theupdateframework/go-tuf v0.5.2 // indirect @@ -151,16 +151,16 @@ require ( go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.17.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.2.0 // indirect + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/term v0.15.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.16.1 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/grpc v1.60.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 13a7d6c..067193c 100644 --- a/go.sum +++ b/go.sum @@ -1159,8 +1159,9 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -1182,8 +1183,9 @@ github.com/danieljoos/wincred v1.1.1/go.mod h1:gSBQmTx6G0VmLowygiA7ZD0p0E09HJ68v github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCFFnBUn4RN0nRcs1LJA= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= @@ -1793,8 +1795,9 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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.2.0/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/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= @@ -1834,16 +1837,18 @@ github.com/gorilla/handlers v0.0.0-20170224193955-13d73096a474/go.mod h1:Qkdc/uu github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a/go.mod h1:IEJaV4/6J0VpoQ33kFCUUP6umRjrcBVEbOva6XCub/Q= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= @@ -2223,14 +2228,15 @@ github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 h1:BcxbplxjtczA1a6d3wYoa7a0WL3rq9DKBMGHeKyjEF0= github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -2358,8 +2364,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -2367,8 +2373,9 @@ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 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/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= @@ -2417,8 +2424,9 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcs github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mistifyio/go-zfs/v3 v3.0.0/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -2649,8 +2657,8 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -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/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -2898,8 +2906,9 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= 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/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= @@ -2937,8 +2946,9 @@ github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY52 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= 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= @@ -3005,8 +3015,8 @@ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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.2/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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -3472,8 +3482,8 @@ golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZ golang.org/x/exp v0.0.0-20230118134722-a68e582fa157/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 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= @@ -3518,8 +3528,8 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.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/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20150829230318-ea47fc708ee3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180306060152-d25186b37f34/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -3633,8 +3643,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -3690,8 +3700,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/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/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -3851,7 +3861,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -3918,8 +3927,9 @@ golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.2.0/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/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -4066,8 +4076,9 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -4330,8 +4341,8 @@ google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -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/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -4384,8 +4395,8 @@ google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= +google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY= google.golang.org/grpc/examples v0.0.0-20230103192020-f2fbb0e07ebf/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI= @@ -4405,8 +4416,9 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -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= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= diff --git a/pkg/mosconfig/files.go b/pkg/mosconfig/files.go index 8aab653..e7e7c24 100644 --- a/pkg/mosconfig/files.go +++ b/pkg/mosconfig/files.go @@ -4,10 +4,17 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" + "syscall" + "github.com/apex/log" ispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/project-machine/mos/pkg/trust" + "github.com/project-machine/mos/pkg/utils" + + "machinerun.io/disko" + "machinerun.io/disko/partid" ) // Update can be full, meaning all existing Targets are replaced, or @@ -81,30 +88,154 @@ const ( FsService ServiceType = "fs-only" ) +type TargetStorage struct { + Dest string `json:"dest" yaml:"dest"` + Label string `json:"label" yaml:"label"` +} +type TargetStorageList []TargetStorage + // Target defines a single service. This includes the rootfs // and every container and fs-only service. // NSGroup is a user namespace group. Two services both in // NSGroup 'ran' will have the same uid mapping. A service // in NSGroup "none" (or "") runs in the host uid network. type Target struct { - ServiceName string `json:"service_name"` // name of target - Version string `json:"version"` // docker or oci version tag - ServiceType ServiceType `json:"service_type"` - Network TargetNetwork `json:"network"` - NSGroup string `json:"nsgroup"` - Digest string `json:"digest"` - Size int64 `json:"size"` + ServiceName string `json:"service_name"` // name of target + Version string `json:"version"` // docker or oci version tag + ServiceType ServiceType `json:"service_type"` + Network TargetNetwork `json:"network"` + NSGroup string `json:"nsgroup"` + Digest string `json:"digest"` + Storage TargetStorageList `json:"storage"` + Size int64 `json:"size"` } type InstallTargets []Target func (t *Target) NeedsIdmap() bool { - return t.NSGroup != "" && t.NSGroup != "none" + return needsIdmap(t.NSGroup) +} +func needsIdmap(nsgroup string) bool { + return nsgroup != "" && nsgroup != "none" +} + +// Note - Storage is an interface, an implementation detail +// to abstract atomfs vs puzzlefs etc. So for the 'storage' +// information in manifest.yaml, we use StorageItem and +// StorageList. + +// StorageItem is a request for a volume to be mounted into +// a Target. +type StorageItem struct { + Label string `json:"label" yaml:"label"` + Persistent bool `json:"persistent" yaml:"persistent"` + NSGroup string `json:"nsgroup" yaml:"nsgroup"` + Size uint64 `json:"size" yaml:"size"` // size in Mib +} + +func (i *StorageItem) Delete(allDisks disko.DiskSet, mysys disko.System) error { + for _, d := range allDisks { + for _, p := range d.Partitions { + if p.Name == i.Label { + err := mysys.DeletePartition(d, p.Number) + if err != nil { + return err + } + return nil + } + } + } + return nil +} + +func (i *StorageItem) IsReserved() bool { + for _, n := range []string{"esp", "machine-config", "machine-store", "machine-scratch"} { + if i.Label == n { + return true + } + } + return false +} + +const mib, gib = disko.Mebibyte, disko.Mebibyte * 1024 + +// Create a user-requested storage item if it does not yet exist. +// We accept the mos struct so we can find its nsgroup (uid mapping) +func (i *StorageItem) Create(mos *Mos, allDisks disko.DiskSet, mysys disko.System) error { + size := i.Size * disko.Mebibyte + for _, d := range allDisks { + fslist := d.FreeSpacesWithMin(size) + if len(fslist) == 0 { + continue + } + num := uint(0) + for i := uint(1); i <= 128; i++ { + if _, ok := d.Partitions[i]; !ok { + num = i + break + } + } + if num == 0 { + return errors.Errorf("No free partition numbers") + } + freespace := fslist[0] + start := freespace.Start + p := disko.Partition{ + Start: start, + Last: start + size - 1, + Number: num, + ID: disko.GenGUID(), + Type: partid.LinuxFS, + Name: i.Label, + } + if err := mysys.CreatePartition(d, p); err != nil { + return errors.Wrapf(err, "Failed creating storage %#v", i) + } + dev := filepath.Join("/dev", pathForPartition(d.Name, p.Number)) + cmd := []string{"mkfs.ext4", "-F", dev} + if err := utils.RunCommand(cmd...); err != nil { + return errors.Wrapf(err, "Failed creating fs on %#v", i) + } + + // mount + dest := filepath.Join("/storage", i.Label) + if err := utils.EnsureDir(dest); err != nil { + return errors.Wrapf(err, "Failed creating mount dir %q", dest) + } + if err := syscall.Mount(dev, dest, "ext4", 0, ""); err != nil { + return errors.Wrapf(err, "Failed mounting %#v", i) + } + + idmapset, _, err := mos.GetUIDMapStr(i.NSGroup) + if err != nil { + return err + } + if len(idmapset.Idmap) != 0 { + if err := idmapset.ShiftFile(dest); err != nil { + return errors.Wrapf(err, "Failed shifting %q to %#v", dest, idmapset.Idmap) + } + } + log.Infof("Created and mounted %#v onto %q", i, dest) + return nil + } + return errors.Errorf("Failed to find free space for %#v", i) +} + +type StorageList []StorageItem + +func (s StorageList) Contains(n StorageItem) bool { + for _, i := range s { + if i.Label == n.Label { + return true + } + } + return false } // This describes an install manifest type InstallFile struct { Version int `json:"version"` Product string `json:"product"` + Storage StorageList `json:"storage"` Targets InstallTargets `json:"targets"` UpdateType UpdateType `json:"update_type"` } @@ -128,19 +259,20 @@ type SysTarget struct { } type SysTargets []SysTarget -func (s *SysTargets) Contains(needle SysTarget) (SysTarget, bool) { +func (s *SysTargets) Contains(needle SysTarget) bool { for _, t := range *s { if t.Name == needle.Name { - return t, true + return true } } - return SysTarget{}, false + return false } type SysManifest struct { // Persistent stored information UidMaps []IdmapSet `json:"uidmaps"` SysTargets []SysTarget `json:"targets"` + Storage StorageList `json:"storage"` // Runtime information DefaultNic string @@ -270,6 +402,7 @@ func (ts InstallTargets) Validate() error { type ImportFile struct { Version int `yaml:"version"` Product string `yaml:"product"` + Storage StorageList `yaml:"storage"` Targets UserTargets `yaml:"targets"` UpdateType UpdateType `yaml:"update_type"` } @@ -313,13 +446,14 @@ func (i *ImportFile) CompleteTargets(keyProject string) (UserTargets, error) { } type UserTarget struct { - ServiceName string `yaml:"service_name"` // name of target - Source string `yaml:"source"` // docker url from which to fetch - Version string `yaml:"version"` // A version for internal use. - ServiceType ServiceType `yaml:"service_type"` - Network TargetNetwork `yaml:"network"` - NSGroup string `yaml:"nsgroup"` - Digest string `yaml:"digest"` - Size int64 `yaml:"size"` + ServiceName string `yaml:"service_name"` // name of target + Source string `yaml:"source"` // docker url from which to fetch + Version string `yaml:"version"` // A version for internal use. + Storage TargetStorageList `yaml:"storage"` + ServiceType ServiceType `yaml:"service_type"` + Network TargetNetwork `yaml:"network"` + NSGroup string `yaml:"nsgroup"` + Digest string `yaml:"digest"` + Size int64 `yaml:"size"` } type UserTargets []UserTarget diff --git a/pkg/mosconfig/install.go b/pkg/mosconfig/install.go index e59dffd..0a91d72 100644 --- a/pkg/mosconfig/install.go +++ b/pkg/mosconfig/install.go @@ -329,6 +329,13 @@ func PublishManifest(project, repo, destpath, manifestpath string, skipBootkit b UpdateType: imports.UpdateType, } + for _, s := range imports.Storage { + if s.IsReserved() { + return errors.Errorf("Invalid storage name %q", s.Label) + } + install.Storage = append(install.Storage, s) + } + // Copy each of the targets to specified oci repo, // verify digest and size, and append them to the install // manifest's list. @@ -361,9 +368,11 @@ func PublishManifest(project, repo, destpath, manifestpath string, skipBootkit b ServiceType: t.ServiceType, Network: t.Network, NSGroup: t.NSGroup, + Storage: t.Storage, Digest: digest, Size: size}, ) + log.Infof("appending storage item %#v", t.Storage) } workdir, err := os.MkdirTemp("", "manifest") diff --git a/pkg/mosconfig/manifest.go b/pkg/mosconfig/manifest.go index 4978e35..868b036 100644 --- a/pkg/mosconfig/manifest.go +++ b/pkg/mosconfig/manifest.go @@ -87,6 +87,7 @@ func (mos *Mos) initManifest(manifestPath, manifestCert, manifestCA, configPath dest = filepath.Join(dir, "manifest.json") targets := SysTargets{} uidmaps := []IdmapSet{} + s := StorageList{} for _, t := range cf.Targets { newT := SysTarget{ @@ -95,7 +96,11 @@ func (mos *Mos) initManifest(manifestPath, manifestCert, manifestCA, configPath } targets = append(targets, newT) - uidmaps = addUIDMap([]IdmapSet{}, uidmaps, t) + uidmaps = addUIDMap([]IdmapSet{}, uidmaps, t.NSGroup) + } + + for _, n := range cf.Storage { + s = append(s, n) } sysmanifest := SysManifest{ @@ -103,6 +108,7 @@ func (mos *Mos) initManifest(manifestPath, manifestCert, manifestCA, configPath SysTargets: targets, UsedPorts: make(map[uint]string), IpAddrs: make(map[string]string), + Storage: s, } bytes, err := json.Marshal(&sysmanifest) diff --git a/pkg/mosconfig/mos.go b/pkg/mosconfig/mos.go index f5a30ba..a7a2046 100644 --- a/pkg/mosconfig/mos.go +++ b/pkg/mosconfig/mos.go @@ -12,6 +12,9 @@ import ( "github.com/pkg/errors" "github.com/project-machine/mos/pkg/utils" "golang.org/x/sys/unix" + + "machinerun.io/disko" + "machinerun.io/disko/linux" ) type MosOptions struct { @@ -172,6 +175,10 @@ func (mos *Mos) Current(name string) (*Target, error) { // Called at system boot to do basic setup and // activate all services func (mos *Mos) Boot() error { + m, err := mos.CurrentManifest() + if err != nil { + return errors.Wrapf(err, "Failed opening manifest") + } // For containers to start, /var/lib/lxc needs to be world-x // at each point so that subuids can get to their RFS. p := "" @@ -182,16 +189,43 @@ func (mos *Mos) Boot() error { } } + if err := mos.SetupStorage(m); err != nil { + return errors.Wrapf(err, "Failed setting up storage") + } // Now start the services - return mos.ActivateAll() + return mos.ActivateAll(m) } -// Activate all services -func (mos *Mos) ActivateAll() error { - m, err := mos.CurrentManifest() +// Set up the user-requested storage +func (mos *Mos) SetupStorage(m *SysManifest) error { + sys := linux.System() + allDisks, err := sys.ScanAllDisks(func(disko.Disk) bool { return true }) if err != nil { - return errors.Wrapf(err, "Failed opening manifest") + return err } + + // First delete any non-persistent storage which already exists + for _, n := range m.Storage { + if !n.Persistent { + continue + } + if err := n.Delete(allDisks, sys); err != nil { + return errors.Wrapf(err, "Failed deleting %#v", n) + } + } + + // Create all needed storage partitions, and mount them + for _, n := range m.Storage { + if err := n.Create(mos, allDisks, sys); err != nil { + return errors.Wrapf(err, "Failed creating %#v", n) + } + } + + return nil +} + +// Activate all services +func (mos *Mos) ActivateAll(m *SysManifest) error { for _, t := range m.SysTargets { if t.Name == "hostfs" || t.Name == "bootkit" { continue @@ -325,6 +359,7 @@ func (mos *Mos) setupContainerService(t *Target) error { func (mos *Mos) writeLxcConfig(t *Target) error { // We are guaranteed to have stopped the container before reaching // here + log.Infof("Writing lxc config for %#v", t) lxcStateDir := filepath.Join(mos.opts.RootDir, "var/lib/lxc") lxcconfigDir := filepath.Join(lxcStateDir, t.ServiceName) lxclogDir := filepath.Join(mos.opts.RootDir, "/var/log/lxc") @@ -350,7 +385,7 @@ func (mos *Mos) writeLxcConfig(t *Target) error { return err } - idmapset, lxcIdrange, err := mos.GetUIDMapStr(t) + idmapset, lxcIdrange, err := mos.GetUIDMapStr(t.NSGroup) if err != nil { return err } @@ -424,7 +459,20 @@ func (mos *Mos) writeLxcConfig(t *Target) error { lxcConf = append(lxcConf, fmt.Sprintf("lxc.environment = %s", env)) } - // TODO - setup the mounts + // setup the storage mounts + for _, m := range t.Storage { + dest := strings.TrimPrefix(m.Dest, "/") + src := filepath.Join("/storage", m.Label) + isdir, err := utils.IsDirErr(src) + if err != nil { + return errors.Wrapf(err, "Source for storage not found: %q", src) + } + filetype := "file" + if isdir { + filetype = "dir" + } + lxcConf = append(lxcConf, fmt.Sprintf("lxc.mount.entry = %s %s none bind,create=%s 0 0", src, dest, filetype)) + } // Write the result lxcConfFile := filepath.Join(lxcconfigDir, "config") diff --git a/pkg/mosconfig/uidmap.go b/pkg/mosconfig/uidmap.go index 9a4d448..9f31f1b 100644 --- a/pkg/mosconfig/uidmap.go +++ b/pkg/mosconfig/uidmap.go @@ -58,19 +58,19 @@ func firstUnusedUID(uidmaps []IdmapSet) int64 { return min } -func addUIDMap(old []IdmapSet, uidmaps []IdmapSet, t Target) []IdmapSet { - if !t.NeedsIdmap() { +func addUIDMap(old []IdmapSet, uidmaps []IdmapSet, nsgroup string) []IdmapSet { + if !needsIdmap(nsgroup) { return uidmaps } for _, u := range uidmaps { - if u.Name == t.NSGroup { + if u.Name == nsgroup { // use the nsgroup already defined in system manifest return uidmaps } } for _, u := range old { - if u.Name == t.NSGroup { + if u.Name == nsgroup { // use the nsgroup already defined in system manifest return append(uidmaps, u) } @@ -78,7 +78,7 @@ func addUIDMap(old []IdmapSet, uidmaps []IdmapSet, t Target) []IdmapSet { // Create a new idmap range uidmap := IdmapSet{ - Name: t.NSGroup, + Name: nsgroup, Hostid: firstUnusedUID(uidmaps), } uidmaps = append(uidmaps, uidmap) @@ -87,7 +87,7 @@ func addUIDMap(old []IdmapSet, uidmaps []IdmapSet, t Target) []IdmapSet { // The install/upgrade step should have created an idmap // already so we return an error if simply not found -func (mos *Mos) GetUIDMapStr(t *Target) (idmap.IdmapSet, []string, error) { +func (mos *Mos) GetUIDMapStr(nsgroup string) (idmap.IdmapSet, []string, error) { empty := idmap.IdmapSet{ Idmap: []idmap.IdmapEntry{}, } @@ -97,12 +97,12 @@ func (mos *Mos) GetUIDMapStr(t *Target) (idmap.IdmapSet, []string, error) { } rangedefs := chooseRangeDefaults() - if t.NSGroup == "none" { + if nsgroup == "" || nsgroup == "none" { return empty, []string{}, nil } for _, u := range manifest.UidMaps { - if u.Name == t.NSGroup { + if u.Name == nsgroup { uidmap := idmap.IdmapEntry{ Isuid: true, Isgid: true, @@ -117,7 +117,7 @@ func (mos *Mos) GetUIDMapStr(t *Target) (idmap.IdmapSet, []string, error) { } } - return empty, []string{}, fmt.Errorf("Error finding UID Mapping for %s", t.ServiceName) + return empty, []string{}, fmt.Errorf("Error finding UID Mapping for %q", nsgroup) } func addUidMapping(set idmap.IdmapSet) error { diff --git a/pkg/mosconfig/update.go b/pkg/mosconfig/update.go index f804861..1a8eb67 100644 --- a/pkg/mosconfig/update.go +++ b/pkg/mosconfig/update.go @@ -56,7 +56,7 @@ func (mos *Mos) Update(url string) error { } } - sysmanifest, err := mergeUpdateTargets(manifest, newtargets, newIF.UpdateType) + sysmanifest, err := mergeUpdateTargets(manifest, newtargets, newIF.Storage, newIF.UpdateType) if err != nil { return err } @@ -102,27 +102,41 @@ func (mos *Mos) Update(url string) error { // Any target in old which is also listed in updated, gets // switched for the one in updated. Any target in updated // which is not in old gets appended. -func mergeUpdateTargets(old *SysManifest, updated SysTargets, updateType UpdateType) (SysManifest, error) { +func mergeUpdateTargets(old *SysManifest, updated SysTargets, s StorageList, updateType UpdateType) (SysManifest, error) { newtargets := SysTargets{} + newstorage := StorageList{} if updateType == PartialUpdate { for _, t := range old.SysTargets { - if _, contained := updated.Contains(t); !contained { + if !updated.Contains(t) { newtargets = append(newtargets, t) } } + for _, n := range old.Storage { + if !s.Contains(n) { + newstorage = append(newstorage, n) + } + } } for _, t := range updated { newtargets = append(newtargets, t) } + for _, n := range s { + newstorage = append(newstorage, n) + } + uidmaps := []IdmapSet{} for _, t := range newtargets { - uidmaps = addUIDMap(old.UidMaps, uidmaps, *t.raw) + uidmaps = addUIDMap(old.UidMaps, uidmaps, t.raw.NSGroup) + } + for _, n := range newstorage { + uidmaps = addUIDMap(old.UidMaps, uidmaps, n.NSGroup) } return SysManifest{ UidMaps: uidmaps, SysTargets: newtargets, + Storage: newstorage, }, nil } diff --git a/pkg/mosconfig/utils.go b/pkg/mosconfig/utils.go index e6d3df6..454d1e8 100644 --- a/pkg/mosconfig/utils.go +++ b/pkg/mosconfig/utils.go @@ -159,3 +159,16 @@ func pingRepo(port int) error { url := fmt.Sprintf("127.0.0.1:%d", port) return PingRepo(url) } + +func pathForPartition(diskPath string, ptnum uint) string { + base := filepath.Base(diskPath) + sep := "" + for _, pre := range []string{"loop", "nvme", "nbd"} { + if strings.HasPrefix(base, pre) { + sep = "p" + break + } + } + + return diskPath + sep + fmt.Sprintf("%d", ptnum) +} diff --git a/pkg/provider/kvm.go b/pkg/provider/kvm.go index 7523da2..de5a80a 100644 --- a/pkg/provider/kvm.go +++ b/pkg/provider/kvm.go @@ -1,6 +1,7 @@ package provider import ( + "bufio" "fmt" "io" "net" @@ -149,7 +150,7 @@ const ( FAILED string = "status: failed" ) -func (m KVMMachine) RunProvision() error { +func (m KVMMachine) RunProvision(showConsole bool) error { // Start the machine, and watch the console for 'provision complete' if err := m.Start(); err != nil { return errors.Wrapf(err, "Failed starting the machine to provision") @@ -167,7 +168,7 @@ func (m KVMMachine) RunProvision() error { mdir := filepath.Join(home, ".local/state/machine/machines", m.Name, m.Name) msock := filepath.Join(mdir, "sockets", "console.sock") time.Sleep(2 * time.Second) - if err := waitForUnix(msock, "provisioned successfully", "XXX FAIL XXX"); err != nil { + if err := waitForUnix(msock, "provisioned successfully", "XXX FAIL XXX", showConsole); err != nil { return errors.Wrapf(err, "Provisioning failed") } @@ -243,7 +244,7 @@ func (m KVMMachine) updateForBoot() error { return nil } -func (m KVMMachine) RunInstall() error { +func (m KVMMachine) RunInstall(showConsole bool) error { log.Infof("Setting up to install %q\n", m.Name) if err := m.updateForInstall(); err != nil { return errors.Wrapf(err, "Failed updating %q for install", m.Name) @@ -264,7 +265,7 @@ func (m KVMMachine) RunInstall() error { mdir := filepath.Join(home, ".local/state/machine/machines", m.Name, m.Name) msock := filepath.Join(mdir, "sockets", "console.sock") time.Sleep(2 * time.Second) - if err := waitForUnix(msock, "installed successfully", "XXX FAIL XXX"); err != nil { + if err := waitForUnix(msock, "installed successfully", "XXX FAIL XXX", showConsole); err != nil { return errors.Wrapf(err, "Install failed") } @@ -281,12 +282,18 @@ func (m KVMMachine) RunInstall() error { // Connect to unix socket @sockPath, and waith for either EOF, // or for either @good or @string to be seen -func waitForUnix(sockPath, good, bad string) error { +func waitForUnix(sockPath, good, bad string, showConsole bool) error { c, err := net.Dial("unix", sockPath) if err != nil { return errors.Wrapf(err, "Failed opening console socket %q", sockPath) } - b, err := io.ReadAll(c) + var r io.Reader + if showConsole { + r = io.TeeReader(c, os.Stdout) + } else { + r = bufio.NewReader(c) + } + b, err := io.ReadAll(r) if err != nil { return errors.Wrapf(err, "Failed reading console socket") } diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index a9be0dc..56acad2 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -19,8 +19,8 @@ type Provider interface { } type Machine interface { - RunProvision() error - RunInstall() error + RunProvision(showConsole bool) error + RunInstall(showConsole bool) error Start() error Stop() error } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 7acfd40..2f07e17 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -253,3 +253,29 @@ func NewCpio(cpio, path string) error { return nil } + +func IsSymlink(path string) (bool, error) { + statInfo, err := os.Lstat(path) + if err != nil { + return false, err + } + return (statInfo.Mode() & os.ModeSymlink) != 0, nil +} + +func IsDirErr(path string) (bool, error) { + if !PathExists(path) { + return false, nil + } + isLink, err := IsSymlink(path) + if err != nil { + return false, err + } + if isLink { + return false, nil + } + statInfo, err := os.Stat(path) + if err != nil { + return false, err + } + return statInfo.IsDir(), nil +}