From a5b5853475aac332f857a7503aed9bc586881ffd Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Thu, 13 Jan 2022 12:39:25 -0500 Subject: [PATCH 1/4] Add or update mergify config Addresses https://github.com/tinkerbell/tink/issues/568 for repos that already had a mergify setup. Creates a mergify config for repos that did not, because many of us miss mergify when its not configured. Signed-off-by: Manuel Mendez --- .github/mergify.yml | 28 ++++++++++++++++++++++++++++ .mergify.yml | 13 ------------- 2 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 .github/mergify.yml delete mode 100644 .mergify.yml diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 000000000..672531406 --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,28 @@ +queue_rules: + - name: default + conditions: + # Conditions to get out of the queue (= merged) + - check-success=DCO + - check-success=docker-images + - check-success=validation + +pull_request_rules: + - name: Automatic merge on approval + conditions: + - base=main + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - "#review-requested=0" + - check-success=DCO + - check-success=docker-images + - check-success=validation + - label!=do-not-merge + - label=ready-to-merge + actions: + queue: + method: merge + name: default + commit_message_template: | + {{ title }} (#{{ number }}) + + {{ body }} diff --git a/.mergify.yml b/.mergify.yml deleted file mode 100644 index c5dbe993c..000000000 --- a/.mergify.yml +++ /dev/null @@ -1,13 +0,0 @@ -pull_request_rules: - - name: Automatic merge on approval - conditions: - - base=main - - "#approved-reviews-by>=1" - - "#review-requested=0" - - "#changes-requested-reviews-by=0" - - label=ready-to-merge - - label!=do-not-merge - actions: - merge: - commit_message: title+body - strict: smart+fastpath From 04a84315c558192df6fceb5367addf80fe54e006 Mon Sep 17 00:00:00 2001 From: Micah Hausler Date: Tue, 21 Dec 2021 21:25:02 +0000 Subject: [PATCH 2/4] Use system version of Go Signed-off-by: Micah Hausler --- shell.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/shell.nix b/shell.nix index a3100a85e..566986d6d 100644 --- a/shell.nix +++ b/shell.nix @@ -15,7 +15,6 @@ mkShell { git gnumake gnused - go_1_17 jq nixfmt nodePackages.prettier From 862c727eee1d341436a9493d07a5c55fffac197f Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Wed, 19 Jan 2022 11:08:18 -0500 Subject: [PATCH 3/4] mergify: Change docker-images check more explicit The previous check was never matching because mergify was not being given the name of the matrix job, it is only given the realized name for each matrix instance. We also need to spell each matrix permuation we care about instead of `check-success~=docker-image` because mergify will happily merge once the first image build succeeds, it has not way to know it needs to wait for all of them. Signed-off-by: Manuel Mendez --- .github/mergify.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 672531406..d7d503f79 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -3,7 +3,9 @@ queue_rules: conditions: # Conditions to get out of the queue (= merged) - check-success=DCO - - check-success=docker-images + - check-success~=docker-images.*tink-cli + - check-success~=docker-images.*tink-server + - check-success~=docker-images.*tink-worker - check-success=validation pull_request_rules: @@ -14,7 +16,9 @@ pull_request_rules: - "#changes-requested-reviews-by=0" - "#review-requested=0" - check-success=DCO - - check-success=docker-images + - check-success~=docker-images.*tink-cli + - check-success~=docker-images.*tink-server + - check-success~=docker-images.*tink-worker - check-success=validation - label!=do-not-merge - label=ready-to-merge From 38af099f05bdac2e913ca2b62638ea3b4fae4aa6 Mon Sep 17 00:00:00 2001 From: Micah Hausler Date: Mon, 29 Nov 2021 21:29:58 +0000 Subject: [PATCH 4/4] Add Kubernetes Controller * Add new cmd/tink-controller package * Remove the `status.data` field on Workflows * Add tests for methods on API types * Add `pkg/controllers` package with controller logic * Controllers for individual types (workflows, templates, hardware) will reside in individual sub-packages * Add `pkg/convert` for type conversions * Add `pkg/internal/tests` for testing utilities * Added FrozenTime with Kubernetes and Protobuf methods Signed-off-by: Micah Hausler --- .github/workflows/ci.yaml | 7 + .gitignore | 1 + Makefile | 2 +- cmd/tink-controller/.gitignore | 2 + cmd/tink-controller/Dockerfile | 10 + cmd/tink-controller/main.go | 125 +++ .../bases/tinkerbell.org_workflowdata.yaml | 3 - .../crd/bases/tinkerbell.org_workflows.yaml | 3 - go.mod | 10 +- go.sum | 206 ++++- pkg/apis/core/v1alpha1/hardware_methods.go | 20 + pkg/apis/core/v1alpha1/hardware_test.go | 57 ++ pkg/apis/core/v1alpha1/template_methods.go | 20 + pkg/apis/core/v1alpha1/template_test.go | 57 ++ pkg/apis/core/v1alpha1/workflow_methods.go | 19 + pkg/apis/core/v1alpha1/workflow_test.go | 182 +++++ pkg/apis/core/v1alpha1/workflow_types.go | 3 - pkg/controllers/manager.go | 134 ++++ pkg/controllers/retry.go | 17 + pkg/controllers/template/controller.go | 3 + pkg/controllers/types.go | 25 + pkg/controllers/workflow/controller.go | 120 +++ pkg/controllers/workflow/controller_test.go | 711 ++++++++++++++++++ pkg/convert/template.go | 63 ++ pkg/convert/template_test.go | 215 ++++++ pkg/convert/workflow.go | 129 ++++ pkg/convert/workflow_test.go | 391 ++++++++++ pkg/internal/tests/frozen_time.go | 64 ++ rules.mk | 13 +- workflow/template_validator.go | 30 +- workflow/template_validator_test.go | 104 +++ 31 files changed, 2703 insertions(+), 43 deletions(-) create mode 100644 cmd/tink-controller/.gitignore create mode 100644 cmd/tink-controller/Dockerfile create mode 100644 cmd/tink-controller/main.go create mode 100644 pkg/apis/core/v1alpha1/hardware_methods.go create mode 100644 pkg/apis/core/v1alpha1/hardware_test.go create mode 100644 pkg/apis/core/v1alpha1/template_methods.go create mode 100644 pkg/apis/core/v1alpha1/template_test.go create mode 100644 pkg/apis/core/v1alpha1/workflow_test.go create mode 100644 pkg/controllers/manager.go create mode 100644 pkg/controllers/retry.go create mode 100644 pkg/controllers/template/controller.go create mode 100644 pkg/controllers/types.go create mode 100644 pkg/controllers/workflow/controller.go create mode 100644 pkg/controllers/workflow/controller_test.go create mode 100644 pkg/convert/template.go create mode 100644 pkg/convert/template_test.go create mode 100644 pkg/convert/workflow.go create mode 100644 pkg/convert/workflow_test.go create mode 100644 pkg/internal/tests/frozen_time.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 026b09df0..de7afeeca 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -89,6 +89,11 @@ jobs: with: name: tink-worker path: cmd/tink-worker/tink-worker-* + - name: Upload tink-controller binaries + uses: actions/upload-artifact@v2 + with: + name: tink-controller + path: cmd/tink-controller/tink-controller-* docker-images: runs-on: ubuntu-latest needs: @@ -102,6 +107,8 @@ jobs: binary: tink-server - repository: quay.io/tinkerbell/tink-worker binary: tink-worker + - repository: quay.io/tinkerbell/tink-controller + binary: tink-controller steps: - name: Docker Image Tag for Sha id: docker-image-tag diff --git a/.gitignore b/.gitignore index 85c4eae69..9e665553f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bin/ certs/ cmd/tink-cli/tink-cli +cmd/tink-controller/tink-controller cmd/tink-server/tink-server cmd/tink-worker/tink-worker doc/ diff --git a/Makefile b/Makefile index 2fbe75630..35d46368b 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ run: crosscompile run-stack ## Builds and runs the Tink stack (tink, db, cli) vi test: ## Run tests go clean -testcache - go test ./... -v + go test -coverprofile=coverage.txt ./... -v verify: lint check-generated # Verify code style, is lint free, freshness ... gofumpt -s -d . diff --git a/cmd/tink-controller/.gitignore b/cmd/tink-controller/.gitignore new file mode 100644 index 000000000..789ea6c77 --- /dev/null +++ b/cmd/tink-controller/.gitignore @@ -0,0 +1,2 @@ +tink-controller +tink-controller-* diff --git a/cmd/tink-controller/Dockerfile b/cmd/tink-controller/Dockerfile new file mode 100644 index 000000000..eea1a771a --- /dev/null +++ b/cmd/tink-controller/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:3.15 +ENTRYPOINT ["/usr/bin/tink-controller"] +EXPOSE 42113 +EXPOSE 42114 + +ARG TARGETARCH +ARG TARGETVARIANT + +RUN apk add --update ca-certificates +COPY tink-controller-linux-${TARGETARCH:-amd64}${TARGETVARIANT} /usr/bin/tink-controller diff --git a/cmd/tink-controller/main.go b/cmd/tink-controller/main.go new file mode 100644 index 000000000..77294fe67 --- /dev/null +++ b/cmd/tink-controller/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/packethost/pkg/log" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "github.com/tinkerbell/tink/pkg/controllers" + wfctrl "github.com/tinkerbell/tink/pkg/controllers/workflow" + "k8s.io/client-go/tools/clientcmd" +) + +// version is set at build time. +var version = "devel" + +// DaemonConfig represents all the values you can configure as part of the tink-server. +// You can change the configuration via environment variable, or file, or command flags. +type DaemonConfig struct { + K8sAPI string + Kubeconfig string // only applies to out of cluster +} + +func (c *DaemonConfig) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&c.K8sAPI, "kubernetes", "", "The Kubernetes URL") + fs.StringVar(&c.Kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file") +} + +func main() { + logger, err := log.Init("github.com/tinkerbell/tink") + if err != nil { + panic(err) + } + defer logger.Close() + + config := &DaemonConfig{} + + cmd := NewRootCommand(config, logger) + if err := cmd.ExecuteContext(context.Background()); err != nil { + defer os.Exit(1) + } +} + +func NewRootCommand(config *DaemonConfig, logger log.Logger) *cobra.Command { + cmd := &cobra.Command{ + Use: "tink-controller", + PreRunE: func(cmd *cobra.Command, args []string) error { + viper, err := createViper(logger) + if err != nil { + return err + } + return applyViper(viper, cmd) + }, + RunE: func(cmd *cobra.Command, args []string) error { + logger.Info("starting controller version " + version) + + config, err := clientcmd.BuildConfigFromFlags(config.K8sAPI, config.Kubeconfig) + if err != nil { + return err + } + + manager, err := controllers.NewManager(config, controllers.GetControllerOptions()) + if err != nil { + return err + } + + return manager.RegisterControllers( + cmd.Context(), + wfctrl.NewController(manager.GetClient()), + ).Start(cmd.Context()) + }, + } + config.AddFlags(cmd.Flags()) + return cmd +} + +func createViper(logger log.Logger) (*viper.Viper, error) { + v := viper.New() + v.AutomaticEnv() + v.SetConfigName("tink-controller") + v.AddConfigPath("/etc/tinkerbell") + v.AddConfigPath(".") + v.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + + // If a config file is found, read it in. + if err := v.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); !ok { + logger.With("configFile", v.ConfigFileUsed()).Error(err, "could not load config file") + return nil, err + } + logger.Info("no config file found") + } else { + logger.With("configFile", v.ConfigFileUsed()).Info("loaded config file") + } + + return v, nil +} + +func applyViper(v *viper.Viper, cmd *cobra.Command) error { + errors := []error{} + + cmd.Flags().VisitAll(func(f *pflag.Flag) { + if !f.Changed && v.IsSet(f.Name) { + val := v.Get(f.Name) + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + errors = append(errors, err) + return + } + } + }) + + if len(errors) > 0 { + errs := []string{} + for _, err := range errors { + errs = append(errs, err.Error()) + } + return fmt.Errorf(strings.Join(errs, ", ")) + } + + return nil +} diff --git a/config/crd/bases/tinkerbell.org_workflowdata.yaml b/config/crd/bases/tinkerbell.org_workflowdata.yaml index 59ff561f6..e5c9d6daa 100644 --- a/config/crd/bases/tinkerbell.org_workflowdata.yaml +++ b/config/crd/bases/tinkerbell.org_workflowdata.yaml @@ -53,9 +53,6 @@ spec: status: description: WorkflowStatus defines the observed state of Workflow. properties: - data: - description: Data is the populated Workflow Data in Tinkerbell. - type: string globalTimeout: description: GlobalTimeout represents the max execution time format: int64 diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index d90efadce..8e966c0f2 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -60,9 +60,6 @@ spec: status: description: WorkflowStatus defines the observed state of Workflow. properties: - data: - description: Data is the populated Workflow Data in Tinkerbell. - type: string globalTimeout: description: GlobalTimeout represents the max execution time format: int64 diff --git a/go.mod b/go.mod index 8ccfcecaa..4446a9013 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,11 @@ require ( github.com/docker/distribution v2.7.1+incompatible github.com/docker/docker v20.10.7+incompatible github.com/equinix-labs/otel-init-go v0.0.1 + github.com/go-logr/zapr v0.4.0 github.com/go-openapi/strfmt v0.19.3 // indirect github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.6 - github.com/google/uuid v1.2.0 + github.com/google/uuid v1.3.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -30,12 +31,15 @@ require ( github.com/testcontainers/testcontainers-go v0.11.1 go.mongodb.org/mongo-driver v1.1.2 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.22.0 - google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 - google.golang.org/grpc v1.41.0-dev.0.20210907181116-2f3355d2244e + go.uber.org/multierr v1.7.0 + google.golang.org/genproto v0.0.0-20211021150943-2b146023228c + google.golang.org/grpc v1.42.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 + knative.dev/pkg v0.0.0-20211119170723-a99300deff34 mvdan.cc/gofumpt v0.1.1 sigs.k8s.io/controller-runtime v0.10.1 sigs.k8s.io/controller-tools v0.7.0 diff --git a/go.sum b/go.sum index 2bd96065a..af74e8108 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,15 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 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= @@ -49,10 +56,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl 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.15.0/go.mod h1:mjjQMoxxyGH7Jr8K5qrx6N2O0AHsczI61sMNn03GIZI= +cloud.google.com/go/storage v1.18.2/go.mod h1:AiIj7BWXyhO5gGVmYJ+S8tbkCx3yb0IMjua8Aw4naVM= code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs= contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= +contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= @@ -74,6 +85,7 @@ github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= @@ -134,12 +146,15 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/Songmu/gocredits v0.2.0/go.mod h1:JBywHzwOmBMF9uidu1EgS3mwVNqZCKOPLPrFd1h7qQo= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/jsonschema v0.0.0-20180308105923-f2c93856175a/go.mod h1:qpebaTNSsyUn5rPSJMsfqEtDw71TTggXM6stUDI16HA= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -197,7 +212,11 @@ github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbz github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bufbuild/buf v1.0.0-rc2 h1:OXo9Qm/g4nnY+HGS7llFT+QwUIn43ExFMz0Rb5QgSpo= @@ -206,6 +225,7 @@ github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= github.com/caarlos0/env/v6 v6.6.2/go.mod h1:P0BVSgU9zfkxfSpFUs6KsO3uWR4k3Ac0P66ibAGTybM= github.com/caarlos0/go-shellwords v1.0.12/go.mod h1:bYeeX1GrTLPl5cAMYEzdm272qdsQAZiaHgeF0KTk1Gw= @@ -240,8 +260,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk 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/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= @@ -361,6 +384,9 @@ github.com/dghubble/oauth1 v0.7.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4 github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20140819190930-201884a44051/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzkU0rAM92tn3hb3Anb7oz7KcnixF49+2wOMe4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= @@ -385,6 +411,7 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -409,7 +436,9 @@ github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+ github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -423,6 +452,7 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -459,6 +489,7 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= @@ -470,11 +501,13 @@ github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwoh github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -504,8 +537,9 @@ github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzz github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= -github.com/gobuffalo/flect v0.2.3 h1:f/ZukRnSNA/DUpSNDadko7Qc0PhGvsew35p/2tu+CRY= github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/flect v0.2.4 h1:BSYA8+T60cdyq+vynaSUjqSVI9mDEg9ZfQUXKmfjo4I= +github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8= github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg= github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= @@ -556,6 +590,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt 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/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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= @@ -577,6 +612,7 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= @@ -587,6 +623,15 @@ github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZ github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/golangci/revgrep v0.0.0-20210208091834-cd28932614b5/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/diff v0.0.0-20181124234638-500114f11e71/go.mod h1:22dM4PLscQl+Nzf64qNBurVJvfyvZELT0iRW2l/NN70= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/mathext v0.0.0-20181121095525-8a4bf007ea55/go.mod h1:fmo8aiSEWkJeiGXUJf+sPvuDgEFgqIoZSs843ePKrGg= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= 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/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= @@ -606,17 +651,21 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v1.0.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.2/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+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/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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= @@ -630,6 +679,9 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -638,13 +690,17 @@ github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4Mgqvf github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 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/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= 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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -663,6 +719,8 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z 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/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.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -687,6 +745,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -710,6 +769,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -738,15 +798,24 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/improbable-eng/grpc-web v0.12.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/tdigest v0.0.0-20180711151920-a7d76c6f093a/go.mod h1:9GkyshztGufsdPQWjH+ifgnIr3xNUL5syI70g2dzU1o= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -790,6 +859,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/julz/importas v0.0.0-20210419104244-841f0c0fe66d/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -868,6 +939,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= @@ -915,6 +987,7 @@ github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfp github.com/mgechev/revive v1.0.7/go.mod h1:vuE5ox/4L/HDd63MCcCk3H6wTLQ6XXezRphJ8cJJOxY= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -1003,8 +1076,9 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1014,8 +1088,9 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1048,6 +1123,7 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= github.com/packethost/pkg v0.0.0-20200903155310-0433e0605550 h1:/ojL7LAVjyH1MY+db0+j6rcWU3UWWpzHksYFsHWs9vQ= github.com/packethost/pkg v0.0.0-20200903155310-0433e0605550/go.mod h1:GSv7cTtIjns4yc0pyajaM1RE/KE4djJONoblFIRDrxA= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= @@ -1063,6 +1139,7 @@ github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +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-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1106,8 +1183,10 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1121,6 +1200,7 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= @@ -1132,9 +1212,11 @@ github.com/quasilyte/go-ruleguard/dsl v0.3.2/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQP github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= github.com/quasilyte/go-ruleguard/rules v0.0.0-20210203162857-b223e0831f88/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1231,6 +1313,7 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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= @@ -1273,6 +1356,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1 github.com/tomarrell/wrapcheck/v2 v2.1.0/go.mod h1:crK5eI4RGSUrb9duDTQ5GqcukbKZvi85vX6nbhsBAeI= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/tsenart/go-tsz v0.0.0-20180814232043-cdeb9e1e981e/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo= +github.com/tsenart/vegeta/v12 v12.8.4/go.mod h1:ZiJtwLn/9M4fTPdMY7bdbIeyNeFVE8/AHbWFqCsUuho= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -1285,6 +1370,7 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= @@ -1300,6 +1386,9 @@ github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr github.com/xanzy/go-gitlab v0.50.0/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= @@ -1389,8 +1478,10 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= @@ -1427,17 +1518,21 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 h1:kETrAMYZq6WVGPa8IIixL0CaEcIUNi+1WX7grUoi3y8= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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= @@ -1475,6 +1570,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.3.1-0.20200828183125-ce943fd02449/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.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= @@ -1531,6 +1627,7 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= @@ -1541,9 +1638,11 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1558,8 +1657,14 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5 h1:v79phzBz03tsVCUTbvTBmmC3CUXF5mKYt7DA4ZVldpM= +golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5/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= @@ -1676,16 +1781,25 @@ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/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-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210921065528-437939a70204 h1:JJhkWtBuTQKyz2bd5WG9H8iUsJRU3En/KRfN8B2RnDs= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210921065528-437939a70204/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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= @@ -1736,6 +1850,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/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-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/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-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1814,17 +1929,23 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f 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.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6 h1:SIasE1FVIQOWz2GEAHFOmoW7xchJcqlucjSULTL0Ag4= golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1842,6 +1963,7 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ 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.25.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= @@ -1853,6 +1975,16 @@ google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= +google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1901,6 +2033,7 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/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-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1925,9 +2058,27 @@ google.golang.org/genproto v0.0.0-20210420162539-3c870d7478d2/go.mod h1:P3QM42oQ google.golang.org/genproto v0.0.0-20210423144448-3a41ef94ed2b/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210506142907-4a47615972c2/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 h1:2ncG/LajxmrclaZH+ppVi02rQxz4eXYJzGHdFN4Y9UA= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k= +google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 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.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1961,9 +2112,12 @@ google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0-dev.0.20210907181116-2f3355d2244e h1:HKKXKZmOaf1UtYn+/ga7+QSLvK7l6K5Mppj9yGgXYCo= google.golang.org/grpc v1.41.0-dev.0.20210907181116-2f3355d2244e/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -2043,35 +2197,53 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.21.4/go.mod h1:fTVGP+M4D8+00FN2cMnJqk/eb/GH53bvmNs2SVTmpFk= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/apiextensions-apiserver v0.21.4/go.mod h1:OoC8LhI9LnV+wKjZkXIBbLUwtnOGJiTRE33qctH5CIk= k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4= k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.21.4/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.21.4/go.mod h1:SErUuFBBPZUcD2nsUU8hItxoYheqyYr2o/pCINEPW8g= k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.21.4/go.mod h1:t0/eMKyUAq/DoQ7vW8NVVA00/nomlwC+eInsS8PxSew= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= +k8s.io/code-generator v0.21.4/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.21.4/go.mod h1:ZKG0eHVX+tUDcaoIGpU3Vtk4TIjMddN9uhEWDmW6Nyg= +k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210915205010-39e73c8a59cd/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/hack v0.0.0-20211112192837-128cf0150a69/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/pkg v0.0.0-20211119170723-a99300deff34 h1:3PTfphK/gjxA+XJIwyDZ1g1KxRaADsI/BdhFlRAtdEE= +knative.dev/pkg v0.0.0-20211119170723-a99300deff34/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw= mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA= mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= @@ -2079,6 +2251,7 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= 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= @@ -2092,6 +2265,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/pkg/apis/core/v1alpha1/hardware_methods.go b/pkg/apis/core/v1alpha1/hardware_methods.go new file mode 100644 index 000000000..c12e18dbf --- /dev/null +++ b/pkg/apis/core/v1alpha1/hardware_methods.go @@ -0,0 +1,20 @@ +package v1alpha1 + +const ( + // HardwareIDAnnotation is used by the controller to store the + // ID assigned to the hardware by Tinkerbell for migrated hardware. + HardwareIDAnnotation = "hardware.tinkerbell.org/id" +) + +// TinkID returns the Tinkerbell ID associated with this Hardware. +func (h *Hardware) TinkID() string { + return h.Annotations[HardwareIDAnnotation] +} + +// SetTinkID sets the Tinkerbell ID associated with this Hardware. +func (h *Hardware) SetTinkID(id string) { + if h.Annotations == nil { + h.Annotations = make(map[string]string) + } + h.Annotations[HardwareIDAnnotation] = id +} diff --git a/pkg/apis/core/v1alpha1/hardware_test.go b/pkg/apis/core/v1alpha1/hardware_test.go new file mode 100644 index 000000000..8eca50ad5 --- /dev/null +++ b/pkg/apis/core/v1alpha1/hardware_test.go @@ -0,0 +1,57 @@ +package v1alpha1 + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestHardwareTinkID(t *testing.T) { + id := "d2c26e20-97e0-449c-b665-61efa7373f47" + cases := []struct { + name string + input *Hardware + want string + overwrite string + }{ + { + "Already set", + &Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: map[string]string{ + HardwareIDAnnotation: id, + }, + }, + }, + id, + "", + }, + { + "nil annotations", + &Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: nil, + }, + }, + "", + "abc", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + if tc.input.TinkID() != tc.want { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.want) + } + + tc.input.SetTinkID(tc.overwrite) + + if tc.input.TinkID() != tc.overwrite { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.overwrite) + } + }) + } +} diff --git a/pkg/apis/core/v1alpha1/template_methods.go b/pkg/apis/core/v1alpha1/template_methods.go new file mode 100644 index 000000000..afce6bb9a --- /dev/null +++ b/pkg/apis/core/v1alpha1/template_methods.go @@ -0,0 +1,20 @@ +package v1alpha1 + +const ( + // TemplateIDAnnotation is used by the controller to store the + // ID assigned to the template by Tinkerbell for migrated templates. + TemplateIDAnnotation = "template.tinkerbell.org/id" +) + +// TinkID returns the Tinkerbell ID associated with this Template. +func (t *Template) TinkID() string { + return t.Annotations[TemplateIDAnnotation] +} + +// SetTinkID sets the Tinkerbell ID associated with this Template. +func (t *Template) SetTinkID(id string) { + if t.Annotations == nil { + t.Annotations = make(map[string]string) + } + t.Annotations[TemplateIDAnnotation] = id +} diff --git a/pkg/apis/core/v1alpha1/template_test.go b/pkg/apis/core/v1alpha1/template_test.go new file mode 100644 index 000000000..c7f22ec3f --- /dev/null +++ b/pkg/apis/core/v1alpha1/template_test.go @@ -0,0 +1,57 @@ +package v1alpha1 + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestTemplateTinkID(t *testing.T) { + id := "d2c26e20-97e0-449c-b665-61efa7373f47" + cases := []struct { + name string + input *Template + want string + overwrite string + }{ + { + "Already set", + &Template{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: map[string]string{ + TemplateIDAnnotation: id, + }, + }, + }, + id, + "", + }, + { + "nil annotations", + &Template{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: nil, + }, + }, + "", + "abc", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + if tc.input.TinkID() != tc.want { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.want) + } + + tc.input.SetTinkID(tc.overwrite) + + if tc.input.TinkID() != tc.overwrite { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.overwrite) + } + }) + } +} diff --git a/pkg/apis/core/v1alpha1/workflow_methods.go b/pkg/apis/core/v1alpha1/workflow_methods.go index cdc488861..b2cad6045 100644 --- a/pkg/apis/core/v1alpha1/workflow_methods.go +++ b/pkg/apis/core/v1alpha1/workflow_methods.go @@ -2,6 +2,25 @@ package v1alpha1 import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +const ( + // WorkflowIDAnnotation is used by the controller to store the + // ID assigned to the workflow by Tinkerbell for migrated workflows. + WorkflowIDAnnotation = "workflow.tinkerbell.org/id" +) + +// TinkID returns the Tinkerbell ID associated with this Workflow. +func (w *Workflow) TinkID() string { + return w.Annotations[WorkflowIDAnnotation] +} + +// SetTinkID sets the Tinkerbell ID associated with this Workflow. +func (w *Workflow) SetTinkID(id string) { + if w.Annotations == nil { + w.Annotations = make(map[string]string) + } + w.Annotations[WorkflowIDAnnotation] = id +} + // GetStartTime returns the start time, for the first action of the first task. func (w *Workflow) GetStartTime() *metav1.Time { if len(w.Status.Tasks) > 0 { diff --git a/pkg/apis/core/v1alpha1/workflow_test.go b/pkg/apis/core/v1alpha1/workflow_test.go new file mode 100644 index 000000000..95af57dce --- /dev/null +++ b/pkg/apis/core/v1alpha1/workflow_test.go @@ -0,0 +1,182 @@ +package v1alpha1 + +import ( + "testing" + "time" + + "github.com/tinkerbell/tink/pkg/internal/tests" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var TestNow = tests.NewFrozenTimeUnix(1637361793) + +func TestWorkflowTinkID(t *testing.T) { + id := "d2c26e20-97e0-449c-b665-61efa7373f47" + cases := []struct { + name string + input *Workflow + want string + overwrite string + }{ + { + "Already set", + &Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: map[string]string{ + WorkflowIDAnnotation: id, + }, + }, + }, + id, + "", + }, + { + "nil annotations", + &Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + Annotations: nil, + }, + }, + "", + "abc", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + if tc.input.TinkID() != tc.want { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.want) + } + + tc.input.SetTinkID(tc.overwrite) + + if tc.input.TinkID() != tc.overwrite { + t.Errorf("Got unexpected ID: got %v, wanted %v", tc.input.TinkID(), tc.overwrite) + } + }) + } +} + +func TestGetStartTime(t *testing.T) { + cases := []struct { + name string + input *Workflow + want *metav1.Time + }{ + { + "Empty wflow", + &Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + }, + nil, + }, + { + "Running workflow", + &Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: WorkflowSpec{}, + Status: WorkflowStatus{ + State: "STATE_RUNNING", + GlobalTimeout: 600, + Tasks: []Task{ + { + Name: "os-installation", + WorkerAddr: "3c:ec:ef:4c:4f:54", + Actions: []Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 60, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_SUCCESS", + StartedAt: TestNow.MetaV1Now(), + Seconds: 20, + }, + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 60, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_RUNNING", + StartedAt: TestNow.MetaV1AfterSec(21), + }, + }, + }, + }, + }, + }, + TestNow.MetaV1Now(), + }, + { + "pending without a start time", + &Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: WorkflowSpec{}, + Status: WorkflowStatus{ + State: "STATE_PENDING", + GlobalTimeout: 600, + Tasks: []Task{ + { + Name: "os-installation", + WorkerAddr: "3c:ec:ef:4c:4f:54", + Actions: []Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 60, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_PENDING", + StartedAt: nil, + }, + }, + }, + }, + }, + }, + nil, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := tc.input.GetStartTime() + if got == nil && tc.want == nil { + return + } + if !got.Time.Equal(tc.want.Time) { + t.Errorf("Got time %s, wanted %s", got.Format(time.RFC1123), tc.want.Time.Format(time.RFC1123)) + } + }) + } +} diff --git a/pkg/apis/core/v1alpha1/workflow_types.go b/pkg/apis/core/v1alpha1/workflow_types.go index cbf06c115..bfcb311c1 100644 --- a/pkg/apis/core/v1alpha1/workflow_types.go +++ b/pkg/apis/core/v1alpha1/workflow_types.go @@ -18,9 +18,6 @@ type WorkflowStatus struct { // State is the state of the workflow in Tinkerbell. State string `json:"state,omitempty"` - // Data is the populated Workflow Data in Tinkerbell. - Data string `json:"data,omitempty"` - // GlobalTimeout represents the max execution time GlobalTimeout int64 `json:"globalTimeout,omitempty"` diff --git a/pkg/controllers/manager.go b/pkg/controllers/manager.go new file mode 100644 index 000000000..9571c4c17 --- /dev/null +++ b/pkg/controllers/manager.go @@ -0,0 +1,134 @@ +package controllers + +import ( + "context" + "fmt" + + "github.com/go-logr/zapr" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "knative.dev/pkg/logging" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +const ( + WorkerAddr = "status.tasks.workeraddr" +) + +var ( + runtimescheme = runtime.NewScheme() + options = Options{} +) + +func init() { + _ = clientgoscheme.AddToScheme(runtimescheme) + _ = v1alpha1.AddToScheme(runtimescheme) +} + +// Options for running this binary. +type Options struct { + MetricsPort int + HealthProbePort int +} + +// GetControllerOptions returns a set of options used by the Tink controller. +// These options include leader election enabled. +func GetControllerOptions() controllerruntime.Options { + return controllerruntime.Options{ + Logger: zapr.NewLogger(logging.FromContext(context.Background()).Desugar()), + LeaderElection: true, + LeaderElectionID: "tink-leader-election", + Scheme: runtimescheme, + MetricsBindAddress: fmt.Sprintf(":%d", options.MetricsPort), + HealthProbeBindAddress: fmt.Sprintf(":%d", options.HealthProbePort), + } +} + +// GetServerOptions returns a set of options used by the Tink API. +// These options include leader election disabled. +func GetServerOptions() controllerruntime.Options { + return controllerruntime.Options{ + Logger: zapr.NewLogger(logging.FromContext(context.Background()).Desugar()), + LeaderElection: false, + Scheme: runtimescheme, + MetricsBindAddress: fmt.Sprintf(":%d", options.MetricsPort), + HealthProbeBindAddress: fmt.Sprintf(":%d", options.HealthProbePort), + } +} + +// NewManagerOrDie instantiates a controller manager. +func NewManagerOrDie(config *rest.Config, options controllerruntime.Options) Manager { + m, err := NewManager(config, options) + if err != nil { + panic(err) + } + return m +} + +// NewManager instantiates a controller manager. +func NewManager(config *rest.Config, options controllerruntime.Options) (Manager, error) { + m, err := controllerruntime.NewManager(config, options) + if err != nil { + return nil, err + } + indexers := []struct { + obj client.Object + field string + extractValue client.IndexerFunc + }{ + { + &v1alpha1.Workflow{}, + WorkerAddr, + wokerIndexFunc, + }, + } + for _, indexer := range indexers { + if err := m.GetFieldIndexer().IndexField( + context.Background(), + indexer.obj, + indexer.field, + indexer.extractValue, + ); err != nil { + return nil, fmt.Errorf("failed to setup %s indexer, %w", indexer.field, err) + } + } + return &GenericControllerManager{Manager: m}, nil +} + +// GenericControllerManager is a manager.Manager that allows for registering of controllers. +type GenericControllerManager struct { + manager.Manager +} + +// RegisterControllers registers a set of controllers to the controller manager. +func (m *GenericControllerManager) RegisterControllers(ctx context.Context, controllers ...Controller) Manager { + for _, c := range controllers { + if err := c.Register(ctx, m); err != nil { + panic(err) + } + } + if err := m.AddHealthzCheck("healthz", healthz.Ping); err != nil { + panic(fmt.Sprintf("Failed to add readiness probe, %s", err.Error())) + } + return m +} + +// workerIndex func returns a list of worker addresses from a workflow. +func wokerIndexFunc(obj client.Object) []string { + wf, ok := obj.(*v1alpha1.Workflow) + if !ok { + return nil + } + resp := []string{} + for _, task := range wf.Status.Tasks { + if task.WorkerAddr != "" { + resp = append(resp, task.WorkerAddr) + } + } + return resp +} diff --git a/pkg/controllers/retry.go b/pkg/controllers/retry.go new file mode 100644 index 000000000..0c2e93900 --- /dev/null +++ b/pkg/controllers/retry.go @@ -0,0 +1,17 @@ +package controllers + +import ( + "context" + + "go.uber.org/multierr" + "knative.dev/pkg/logging" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// RetryIfError logs any errors and requeues if not nil. Supports multierr unwrapping. +func RetryIfError(ctx context.Context, err error) (reconcile.Result, error) { + for _, err := range multierr.Errors(err) { + logging.FromContext(ctx).Errorf("Failed reconciliation, %s", err.Error()) + } + return reconcile.Result{Requeue: err != nil}, nil +} diff --git a/pkg/controllers/template/controller.go b/pkg/controllers/template/controller.go new file mode 100644 index 000000000..7b5f4040e --- /dev/null +++ b/pkg/controllers/template/controller.go @@ -0,0 +1,3 @@ +package template + +// TODO: Create a controller that watches for Templates, validates them, and patches the .spec diff --git a/pkg/controllers/types.go b/pkg/controllers/types.go new file mode 100644 index 000000000..47f1555c7 --- /dev/null +++ b/pkg/controllers/types.go @@ -0,0 +1,25 @@ +package controllers + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// Controller is an interface implemented by Karpenter custom resources. +type Controller interface { + // Reconcile hands a hydrated kubernetes resource to the controller for + // reconciliation. Any changes made to the resource's status are persisted + // after Reconcile returns, even if it returns an error. + reconcile.Reconciler + + // Register will register the controller with the manager + Register(context.Context, manager.Manager) error +} + +// Manager manages a set of controllers and webhooks. +type Manager interface { + manager.Manager + RegisterControllers(context.Context, ...Controller) Manager +} diff --git a/pkg/controllers/workflow/controller.go b/pkg/controllers/workflow/controller.go new file mode 100644 index 000000000..ce30c8b3f --- /dev/null +++ b/pkg/controllers/workflow/controller.go @@ -0,0 +1,120 @@ +package workflow + +import ( + "context" + "fmt" + "time" + + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/tinkerbell/tink/pkg/controllers" + "github.com/tinkerbell/tink/pkg/convert" + protoworkflow "github.com/tinkerbell/tink/protos/workflow" + tinkworkflow "github.com/tinkerbell/tink/workflow" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "knative.dev/pkg/ptr" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// Controller is a type for managing Workflows. +type Controller struct { + kubeClient client.Client + nowFunc func() time.Time +} + +func NewController(kubeClient client.Client) *Controller { + return &Controller{ + kubeClient: kubeClient, + nowFunc: time.Now, + } +} + +func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + stored := &v1alpha1.Workflow{} + if err := c.kubeClient.Get(ctx, req.NamespacedName, stored); err != nil { + if errors.IsNotFound(err) { + return reconcile.Result{}, nil + } + return controllers.RetryIfError(ctx, err) + } + if !stored.DeletionTimestamp.IsZero() { + return reconcile.Result{}, nil + } + wflow := stored.DeepCopy() + + var ( + resp reconcile.Result + err error + ) + switch wflow.Status.State { + case "": + resp, err = c.processNewWorkflow(ctx, wflow) + case protoworkflow.State_name[int32(protoworkflow.State_STATE_RUNNING)]: + resp = c.processRunningWorkflow(ctx, wflow) + } + + // Patch any changes, regardless of errors + if !equality.Semantic.DeepEqual(wflow, stored) { + if perr := c.kubeClient.Status().Patch(ctx, wflow, client.MergeFrom(stored)); perr != nil { + err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) + } + } + return resp, err +} + +func (c *Controller) processNewWorkflow(ctx context.Context, stored *v1alpha1.Workflow) (reconcile.Result, error) { + tpl := &v1alpha1.Template{} + if err := c.kubeClient.Get(ctx, client.ObjectKey{Name: stored.Spec.TemplateRef, Namespace: stored.Namespace}, tpl); err != nil { + if errors.IsNotFound(err) { + return reconcile.Result{}, nil + } + return controllers.RetryIfError(ctx, err) + } + + tinkWf, _, err := tinkworkflow.RenderTemplateHardware(stored.Name, ptr.StringValue(tpl.Spec.Data), stored.Spec.HardwareMap) + if err != nil { + return reconcile.Result{}, err + } + + // populate Task and Action data + stored.Status = *convert.WorkflowYAMLToStatus(tinkWf) + + stored.Status.State = protoworkflow.State_name[int32(protoworkflow.State_STATE_PENDING)] + return reconcile.Result{}, nil +} + +func (c *Controller) processRunningWorkflow(_ context.Context, stored *v1alpha1.Workflow) reconcile.Result { + // Check for global timeout expiration + if c.nowFunc().After(stored.GetStartTime().Add(time.Duration(stored.Status.GlobalTimeout) * time.Second)) { + stored.Status.State = protoworkflow.State_name[int32(protoworkflow.State_STATE_TIMEOUT)] + } + + // check for any running actions that may have timed out + for ti, task := range stored.Status.Tasks { + for ai, action := range task.Actions { + // A running workflow task action has timed out + if action.Status == protoworkflow.State_name[int32(protoworkflow.State_STATE_RUNNING)] && + action.StartedAt != nil && + c.nowFunc().After(action.StartedAt.Add(time.Duration(action.Timeout)*time.Second)) { + // Set fields on the timed out action + stored.Status.Tasks[ti].Actions[ai].Status = protoworkflow.State_name[int32(protoworkflow.State_STATE_TIMEOUT)] + stored.Status.Tasks[ti].Actions[ai].Message = "Action timed out" + stored.Status.Tasks[ti].Actions[ai].Seconds = int64(c.nowFunc().Sub(action.StartedAt.Time).Seconds()) + // Mark the workflow as timed out + stored.Status.State = protoworkflow.State_name[int32(protoworkflow.State_STATE_TIMEOUT)] + } + } + } + + return reconcile.Result{} +} + +func (c *Controller) Register(_ context.Context, m manager.Manager) error { + return controllerruntime. + NewControllerManagedBy(m). + For(&v1alpha1.Workflow{}). + Complete(c) +} diff --git a/pkg/controllers/workflow/controller_test.go b/pkg/controllers/workflow/controller_test.go new file mode 100644 index 000000000..688a6151e --- /dev/null +++ b/pkg/controllers/workflow/controller_test.go @@ -0,0 +1,711 @@ +package workflow + +import ( + "context" + "errors" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/tinkerbell/tink/pkg/internal/tests" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var runtimescheme = runtime.NewScheme() + +// TestTime is a static time that can be used for testing. +var TestTime = tests.NewFrozenTimeUnix(1637361793) + +func init() { + _ = clientgoscheme.AddToScheme(runtimescheme) + _ = v1alpha1.AddToScheme(runtimescheme) +} + +func GetFakeClientBuilder() *fake.ClientBuilder { + return fake.NewClientBuilder().WithScheme( + runtimescheme, + ).WithRuntimeObjects( + &v1alpha1.Hardware{}, &v1alpha1.Template{}, &v1alpha1.Workflow{}, + ) +} + +var minimalTemplate = `version: "0.1" +name: debian +global_timeout: 1800 +tasks: + - name: "os-installation" + worker: "{{.device_1}}" + volumes: + - /dev:/dev + - /dev/console:/dev/console + - /lib/firmware:/lib/firmware:ro + actions: + - name: "stream-debian-image" + image: quay.io/tinkerbell-actions/image2disk:v1.0.0 + timeout: 600 + environment: + DEST_DISK: /dev/nvme0n1 + # Hegel IP + IMG_URL: "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz" + COMPRESSED: true` + +func TestReconcile(t *testing.T) { + cases := []struct { + name string + seedTemplate *v1alpha1.Template + seedWorkflow *v1alpha1.Workflow + seedHardware *v1alpha1.Hardware + req reconcile.Request + want reconcile.Result + wantWflow *v1alpha1.Workflow + wantErr error + }{ + { + name: "DoesNotExist", + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "notreal", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "999", + }, + }, + wantErr: nil, + }, + // ************** + { + name: "NewWorkflow", + seedTemplate: &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.TemplateSpec{ + Data: &minimalTemplate, + }, + Status: v1alpha1.TemplateStatus{}, + }, + seedWorkflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{}, + }, + seedHardware: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{ + Kind: "Hardware", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + Netboot: &v1alpha1.Netboot{ + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], + }, + DHCP: &v1alpha1.DHCP{ + Arch: "x86_64", + Hostname: "sm01", + IP: &v1alpha1.IP{ + Address: "172.16.10.100", + Gateway: "172.16.10.1", + Netmask: "255.255.255.0", + }, + LeaseTime: 86400, + MAC: "3c:ec:ef:4c:4f:54", + NameServers: []string{}, + UEFI: true, + }, + }, + }, + }, + }, + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "debian", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1000", + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_PENDING", + GlobalTimeout: 1800, + Tasks: []v1alpha1.Task{ + { + Name: "os-installation", + + WorkerAddr: "3c:ec:ef:4c:4f:54", + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + Actions: []v1alpha1.Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 600, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_PENDING", + }, + }, + }, + }, + }, + }, + wantErr: nil, + }, + // ***** + { + name: "MalformedWorkflow", + seedTemplate: &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.TemplateSpec{ + Data: &[]string{`version: "0.1" + name: debian +global_timeout: 1800 +tasks: + - name: "os-installation" + worker: "{{.device_1}}"`}[0], + }, + Status: v1alpha1.TemplateStatus{}, + }, + seedWorkflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{}, + }, + seedHardware: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{ + Kind: "Hardware", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + Netboot: &v1alpha1.Netboot{ + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], + }, + DHCP: &v1alpha1.DHCP{ + Arch: "x86_64", + Hostname: "sm01", + IP: &v1alpha1.IP{ + Address: "172.16.10.100", + Gateway: "172.16.10.1", + Netmask: "255.255.255.0", + }, + LeaseTime: 86400, + MAC: "3c:ec:ef:4c:4f:54", + NameServers: []string{}, + UEFI: true, + }, + }, + }, + }, + }, + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "debian", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1000", + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_PENDING", + GlobalTimeout: 1800, + Tasks: []v1alpha1.Task{ + { + Name: "os-installation", + + WorkerAddr: "3c:ec:ef:4c:4f:54", + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + Actions: []v1alpha1.Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 600, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_PENDING", + }, + }, + }, + }, + }, + }, + wantErr: errors.New("parsing yaml data: yaml: line 2: found character that cannot start any token"), + }, + // ***** + { + name: "Missing Template", + seedTemplate: &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy", + Namespace: "default", + }, + Spec: v1alpha1.TemplateSpec{}, + Status: v1alpha1.TemplateStatus{}, + }, + seedWorkflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", // doesn't exist + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{}, + }, + seedHardware: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{ + Kind: "Hardware", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + Netboot: &v1alpha1.Netboot{ + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], + }, + DHCP: &v1alpha1.DHCP{ + Arch: "x86_64", + Hostname: "sm01", + IP: &v1alpha1.IP{ + Address: "172.16.10.100", + Gateway: "172.16.10.1", + Netmask: "255.255.255.0", + }, + LeaseTime: 86400, + MAC: "3c:ec:ef:4c:4f:54", + NameServers: []string{}, + UEFI: true, + }, + }, + }, + }, + }, + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "debian", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "999", + }, + }, + wantErr: nil, + }, + // ***** + { + name: "Deleted Workflow", + seedTemplate: &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.TemplateSpec{}, + Status: v1alpha1.TemplateStatus{}, + }, + seedWorkflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + DeletionTimestamp: func() *metav1.Time { + t := metav1.NewTime(TestTime.BeforeSec(5)) + return &t + }(), + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", // doesn't exist + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{}, + }, + seedHardware: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{ + Kind: "Hardware", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + Netboot: &v1alpha1.Netboot{ + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], + }, + DHCP: &v1alpha1.DHCP{ + Arch: "x86_64", + Hostname: "sm01", + IP: &v1alpha1.IP{ + Address: "172.16.10.100", + Gateway: "172.16.10.1", + Netmask: "255.255.255.0", + }, + LeaseTime: 86400, + MAC: "3c:ec:ef:4c:4f:54", + NameServers: []string{}, + UEFI: true, + }, + }, + }, + }, + }, + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "debian", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "999", + }, + }, + wantErr: nil, + }, + // ************** + { + name: "Timed Out workflow Workflow", + seedTemplate: &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.TemplateSpec{ + Data: &minimalTemplate, + }, + Status: v1alpha1.TemplateStatus{}, + }, + seedWorkflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_RUNNING", + GlobalTimeout: 600, + Tasks: []v1alpha1.Task{ + { + Name: "os-installation", + WorkerAddr: "3c:ec:ef:4c:4f:54", + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + Actions: []v1alpha1.Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 60, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_RUNNING", + StartedAt: TestTime.MetaV1BeforeSec(601), + }, + }, + }, + }, + }, + }, + seedHardware: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{ + Kind: "Hardware", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + Netboot: &v1alpha1.Netboot{ + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], + }, + DHCP: &v1alpha1.DHCP{ + Arch: "x86_64", + Hostname: "sm01", + IP: &v1alpha1.IP{ + Address: "172.16.10.100", + Gateway: "172.16.10.1", + Netmask: "255.255.255.0", + }, + LeaseTime: 86400, + MAC: "3c:ec:ef:4c:4f:54", + NameServers: []string{}, + UEFI: true, + }, + }, + }, + }, + }, + req: reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "debian", + Namespace: "default", + }, + }, + want: reconcile.Result{}, + wantWflow: &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1000", + Name: "debian", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "debian", + HardwareMap: map[string]string{ + "device_1": "3c:ec:ef:4c:4f:54", + }, + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_TIMEOUT", + GlobalTimeout: 600, + Tasks: []v1alpha1.Task{ + { + Name: "os-installation", + WorkerAddr: "3c:ec:ef:4c:4f:54", + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + Actions: []v1alpha1.Action{ + { + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 60, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_TIMEOUT", + StartedAt: TestTime.MetaV1BeforeSec(601), + Seconds: 601, + Message: "Action timed out", + }, + }, + }, + }, + }, + }, + wantErr: nil, + }, + } + + for _, tc := range cases { + kc := GetFakeClientBuilder() + if tc.seedHardware != nil { + kc = kc.WithObjects(tc.seedHardware) + } + if tc.seedTemplate != nil { + kc = kc.WithObjects(tc.seedTemplate) + } + if tc.seedWorkflow != nil { + kc = kc.WithObjects(tc.seedWorkflow) + } + controller := &Controller{ + kubeClient: kc.Build(), + nowFunc: TestTime.Now, + } + + t.Run(tc.name, func(t *testing.T) { + got, gotErr := controller.Reconcile(context.Background(), tc.req) + if gotErr != nil { + if tc.wantErr == nil { + t.Errorf(`Got unexpected error: %v"`, gotErr) + } else if gotErr.Error() != tc.wantErr.Error() { + t.Errorf(`Got unexpected error: got "%v" wanted "%v"`, gotErr, tc.wantErr) + } + return + } + if gotErr == nil && tc.wantErr != nil { + t.Errorf("Missing expected error: %v", tc.wantErr) + return + } + if tc.want != got { + t.Errorf("Got unexpected result. Wanted %v, got %v", tc.want, got) + // Don't return, also check the modified object + } + wflow := &v1alpha1.Workflow{} + err := controller.kubeClient.Get( + context.Background(), + client.ObjectKey{Name: tc.wantWflow.Name, Namespace: tc.wantWflow.Namespace}, + wflow) + if err != nil { + t.Errorf("Error finding desired workflow: %v", err) + return + } + + if diff := cmp.Diff(tc.wantWflow, wflow); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} diff --git a/pkg/convert/template.go b/pkg/convert/template.go new file mode 100644 index 000000000..79b29f8b2 --- /dev/null +++ b/pkg/convert/template.go @@ -0,0 +1,63 @@ +package convert + +import ( + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + prototemplate "github.com/tinkerbell/tink/protos/template" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func metav1ToTimestamppb(in *metav1.Time) *timestamppb.Timestamp { + if in == nil { + return nil + } + return timestamppb.New(in.Time) +} + +// TemplateCRDToProto converts a K8s Template to a tinkerbell WorkflowTemplate. +func TemplateCRDToProto(t *v1alpha1.Template) *prototemplate.WorkflowTemplate { + if t == nil { + return nil + } + data := "" + if t.Spec.Data != nil { + data = *t.Spec.Data + } + return &prototemplate.WorkflowTemplate{ + Id: t.TinkID(), + Name: t.Name, + CreatedAt: timestamppb.New(t.CreationTimestamp.Time), + DeletedAt: metav1ToTimestamppb(t.DeletionTimestamp), + Data: data, + } +} + +// TemplateProtoToCRD converts a tinkerbell WorkflowTemplate to a K8s Template. +func TemplateProtoToCRD(t *prototemplate.WorkflowTemplate) *v1alpha1.Template { + if t == nil { + return nil + } + return &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: t.Name, + Annotations: map[string]string{ + "template.tinkerbell.org/id": t.Id, + }, + CreationTimestamp: metav1.NewTime(t.CreatedAt.AsTime()), + DeletionTimestamp: func() *metav1.Time { + if t.DeletedAt != nil { + resp := metav1.NewTime(t.DeletedAt.AsTime()) + return &resp + } + return nil + }(), + }, + Spec: v1alpha1.TemplateSpec{ + Data: &t.Data, + }, + } +} diff --git a/pkg/convert/template_test.go b/pkg/convert/template_test.go new file mode 100644 index 000000000..74f016216 --- /dev/null +++ b/pkg/convert/template_test.go @@ -0,0 +1,215 @@ +package convert + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/tinkerbell/tink/pkg/internal/tests" + prototemplate "github.com/tinkerbell/tink/protos/template" + "google.golang.org/protobuf/testing/protocmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TestTime is a static time that can be used for testing. +var TestTime = tests.NewFrozenTimeUnix(1637361794) + +func TestTemplateCRDToProto(t *testing.T) { + cases := []struct { + name string + input *v1alpha1.Template + want *prototemplate.WorkflowTemplate + }{ + { + "Full Example", + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + Annotations: map[string]string{ + "template.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + DeletionTimestamp: TestTime.MetaV1AfterSec(600), + }, + Spec: v1alpha1.TemplateSpec{ + Data: func() *string { + resp := `version: "0.1"` + return &resp + }(), + }, + }, + &prototemplate.WorkflowTemplate{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Name: "template1", + CreatedAt: TestTime.PbNow(), + DeletedAt: TestTime.PbAfterSec(600), + Data: `version: "0.1"`, + }, + }, + { + "No DeletionTime", + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + Annotations: map[string]string{ + "template.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.TemplateSpec{ + Data: func() *string { + resp := `version: "0.1"` + return &resp + }(), + }, + }, + &prototemplate.WorkflowTemplate{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Name: "template1", + CreatedAt: TestTime.PbNow(), + Data: `version: "0.1"`, + }, + }, + { + "No Annotation or data", + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.TemplateSpec{ + Data: nil, + }, + }, + &prototemplate.WorkflowTemplate{ + Id: "", + Name: "template1", + CreatedAt: TestTime.PbNow(), + Data: "", + }, + }, + { + "Empty", + nil, + nil, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := TemplateCRDToProto(tc.input) + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} + +func TestTemplateProtoToCRD(t *testing.T) { + cases := []struct { + name string + input *prototemplate.WorkflowTemplate + want *v1alpha1.Template + }{ + { + "Full Example", + &prototemplate.WorkflowTemplate{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Name: "template1", + CreatedAt: TestTime.PbNow(), + DeletedAt: TestTime.PbAfterSec(600), + Data: `version: "0.1"`, + }, + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + Annotations: map[string]string{ + "template.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + DeletionTimestamp: TestTime.MetaV1AfterSec(600), + }, + Spec: v1alpha1.TemplateSpec{ + Data: func() *string { + resp := `version: "0.1"` + return &resp + }(), + }, + }, + }, + { + "No DeletionTime", + &prototemplate.WorkflowTemplate{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Name: "template1", + CreatedAt: TestTime.PbNow(), + Data: `version: "0.1"`, + }, + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + Annotations: map[string]string{ + "template.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.TemplateSpec{ + Data: func() *string { + resp := `version: "0.1"` + return &resp + }(), + }, + }, + }, + { + "No id or data", + &prototemplate.WorkflowTemplate{ + Id: "", + Name: "template1", + CreatedAt: TestTime.PbNow(), + Data: "", + }, + &v1alpha1.Template{ + TypeMeta: metav1.TypeMeta{ + Kind: "Template", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "template1", + Annotations: map[string]string{ + "template.tinkerbell.org/id": "", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.TemplateSpec{ + Data: func(s string) *string { return &s }(""), + }, + }, + }, + { + "Empty", + nil, + nil, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := TemplateProtoToCRD(tc.input) + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} diff --git a/pkg/convert/workflow.go b/pkg/convert/workflow.go new file mode 100644 index 000000000..d552251b1 --- /dev/null +++ b/pkg/convert/workflow.go @@ -0,0 +1,129 @@ +package convert + +import ( + "fmt" + "sort" + + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + protoworkflow "github.com/tinkerbell/tink/protos/workflow" + "github.com/tinkerbell/tink/workflow" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func WorkflowYAMLToStatus(wf *workflow.Workflow) *v1alpha1.WorkflowStatus { + if wf == nil { + return nil + } + tasks := []v1alpha1.Task{} + for _, task := range wf.Tasks { + actions := []v1alpha1.Action{} + for _, action := range task.Actions { + actions = append(actions, v1alpha1.Action{ + Name: action.Name, + Image: action.Image, + Timeout: action.Timeout, + Command: action.Command, + Volumes: action.Volumes, + Status: protoworkflow.State_name[int32(protoworkflow.State_STATE_PENDING)], + Environment: action.Environment, + Pid: action.Pid, + }) + } + tasks = append(tasks, v1alpha1.Task{ + Name: task.Name, + WorkerAddr: task.WorkerAddr, + Volumes: task.Volumes, + Environment: task.Environment, + Actions: actions, + }) + } + return &v1alpha1.WorkflowStatus{ + GlobalTimeout: int64(wf.GlobalTimeout), + Tasks: tasks, + } +} + +func WorkflowCRDToProto(w *v1alpha1.Workflow) *protoworkflow.Workflow { + if w == nil { + return nil + } + v, ok := protoworkflow.State_value[w.Status.State] + state := protoworkflow.State(v) + if !ok { + state = protoworkflow.State_STATE_PENDING + } + return &protoworkflow.Workflow{ + Id: w.TinkID(), + Template: w.Spec.TemplateRef, + State: state, + CreatedAt: timestamppb.New(w.CreationTimestamp.Time), + DeletedAt: metav1ToTimestamppb(w.DeletionTimestamp), + } +} + +func WorkflowActionListCRDToProto(wf *v1alpha1.Workflow) *protoworkflow.WorkflowActionList { + if wf == nil { + return nil + } + resp := &protoworkflow.WorkflowActionList{ + ActionList: []*protoworkflow.WorkflowAction{}, + } + for _, task := range wf.Status.Tasks { + for _, action := range task.Actions { + resp.ActionList = append(resp.ActionList, &protoworkflow.WorkflowAction{ + TaskName: task.Name, + Name: action.Name, + Image: action.Image, + Timeout: action.Timeout, + Command: action.Command, + WorkerId: task.WorkerAddr, + Volumes: append(task.Volumes, action.Volumes...), + // TODO: (micahhausler) Dedupe task volume targets overridden in the action volumes? + // Also not sure how Docker handles nested mounts (ex: "/foo:/foo" and "/bar:/foo/bar") + Environment: func(env map[string]string) []string { + resp := []string{} + merged := map[string]string{} + for k, v := range env { + merged[k] = v + } + for k, v := range action.Environment { + merged[k] = v + } + for k, v := range merged { + resp = append(resp, fmt.Sprintf("%s=%s", k, v)) + } + sort.Strings(resp) + return resp + }(task.Environment), + Pid: action.Pid, + }) + } + } + return resp +} + +func WorkflowProtoToCRD(w *protoworkflow.Workflow) *v1alpha1.Workflow { + if w == nil { + return nil + } + resp := &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + v1alpha1.WorkflowIDAnnotation: w.Id, + }, + CreationTimestamp: metav1.NewTime(w.CreatedAt.AsTime()), + }, + Spec: v1alpha1.WorkflowSpec{}, + Status: v1alpha1.WorkflowStatus{}, + } + + if v, ok := protoworkflow.State_name[int32(w.State)]; ok { + resp.Status.State = v + } + return resp +} diff --git a/pkg/convert/workflow_test.go b/pkg/convert/workflow_test.go new file mode 100644 index 000000000..b8d048c49 --- /dev/null +++ b/pkg/convert/workflow_test.go @@ -0,0 +1,391 @@ +package convert + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + protoworkflow "github.com/tinkerbell/tink/protos/workflow" + "github.com/tinkerbell/tink/workflow" + "google.golang.org/protobuf/testing/protocmp" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestWorkflowCRDToProto(t *testing.T) { + cases := []struct { + name string + input *v1alpha1.Workflow + want *protoworkflow.Workflow + }{ + { + "nil arg", + nil, + nil, + }, + { + "empty workflow", + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "wf1", + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.WorkflowSpec{}, + Status: v1alpha1.WorkflowStatus{}, + }, + &protoworkflow.Workflow{ + Id: "", + Template: "", + State: protoworkflow.State_STATE_PENDING, + CreatedAt: TestTime.PbNow(), + }, + }, + { + "full workflow", + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "wf1", + Annotations: map[string]string{ + "workflow.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "MyCoolWorkflow", + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_SUCCESS", + }, + }, + &protoworkflow.Workflow{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Template: "MyCoolWorkflow", + State: protoworkflow.State_STATE_SUCCESS, + CreatedAt: TestTime.PbNow(), + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := WorkflowCRDToProto(tc.input) + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} + +func TestWorkflowActionListCRDToProto(t *testing.T) { + cases := []struct { + name string + input *v1alpha1.Workflow + want *protoworkflow.WorkflowActionList + }{ + { + "nil arg", + nil, + nil, + }, + { + "empty workflow", + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "wf1", + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.WorkflowSpec{}, + Status: v1alpha1.WorkflowStatus{}, + }, + &protoworkflow.WorkflowActionList{ + ActionList: []*protoworkflow.WorkflowAction{}, + }, + }, + { + "full workflow", + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "wf1", + Annotations: map[string]string{ + "workflow.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: *TestTime.MetaV1Now(), + }, + Spec: v1alpha1.WorkflowSpec{ + TemplateRef: "MyCoolWorkflow", + }, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_SUCCESS", + Tasks: []v1alpha1.Task{ + { + Name: "worker1", + WorkerAddr: "00:00:53:00:53:F4", + Actions: []v1alpha1.Action{ + { + Name: "stream-debian-image", + Timeout: 600, + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Environment: map[string]string{ + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + "COMPRESSED": "true", + "GODEBUG": "", + }, + Volumes: []string{ + "/tmp/debug:/tmp/debug", + }, + }, + { + Name: "kexec", + Image: "quay.io/tinkerbell-actions/kexec:v1.0.1", + Timeout: 90, + Pid: "host", + Environment: map[string]string{ + "FS_TYPE": "ext4", + "BLOCK_DEVICE": "/dev/nvme0n1p1", + }, + }, + }, + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + Environment: map[string]string{ + "GODEBUG": "http2debug=1", + "GOGC": "100", + }, + }, + }, + }, + }, + &protoworkflow.WorkflowActionList{ + ActionList: []*protoworkflow.WorkflowAction{ + { + TaskName: "worker1", + Name: "stream-debian-image", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 600, + WorkerId: "00:00:53:00:53:F4", + Environment: []string{ + "COMPRESSED=true", + "DEST_DISK=/dev/nvme0n1", + "GODEBUG=", + "GOGC=100", + "IMG_URL=http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + "/tmp/debug:/tmp/debug", + }, + }, + { + TaskName: "worker1", + Name: "kexec", + Image: "quay.io/tinkerbell-actions/kexec:v1.0.1", + Timeout: 90, + WorkerId: "00:00:53:00:53:F4", + Environment: []string{ + "BLOCK_DEVICE=/dev/nvme0n1p1", + "FS_TYPE=ext4", + "GODEBUG=http2debug=1", + "GOGC=100", + }, + Pid: "host", + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + }, + }, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := WorkflowActionListCRDToProto(tc.input) + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} + +func TestWorkflowProtoToCRD(t *testing.T) { + cases := []struct { + name string + input *protoworkflow.Workflow + want *v1alpha1.Workflow + }{ + { + "nil arg", + nil, + nil, + }, + { + "empty workflow", + &protoworkflow.Workflow{ + Id: "", + Template: "", + // State: protoworkflow.State_STATE_PENDING, + CreatedAt: timestamppb.New(time.Unix(1637361794, 0)), + }, + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"workflow.tinkerbell.org/id": ""}, + CreationTimestamp: metav1.NewTime(time.Unix(1637361794, 0)), + }, + Spec: v1alpha1.WorkflowSpec{}, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_PENDING", + }, + }, + }, + { + "full workflow", + &protoworkflow.Workflow{ + Id: "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + Template: "MyCoolWorkflow", + State: protoworkflow.State_STATE_SUCCESS, + CreatedAt: timestamppb.New(time.Unix(1637361794, 0)), + }, + &v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + Kind: "Workflow", + APIVersion: "tinkerbell.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + + Annotations: map[string]string{ + "workflow.tinkerbell.org/id": "7d9031ee-18d4-4ba4-b934-c3a78a1330f6", + }, + CreationTimestamp: metav1.NewTime(time.Unix(1637361794, 0)), + }, + Spec: v1alpha1.WorkflowSpec{}, + Status: v1alpha1.WorkflowStatus{ + State: "STATE_SUCCESS", + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := WorkflowProtoToCRD(tc.input) + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} + +func TestWorkflowYAMLToStatus(t *testing.T) { + cases := []struct { + name string + inputWf *workflow.Workflow + want *v1alpha1.WorkflowStatus + }{ + { + "Nil workflow", + nil, + nil, + }, + { + "Full crd", + &workflow.Workflow{ + Version: "1", + Name: "debian-provision", + ID: "0a90fac9-b509-4aa5-b294-5944128ece81", + GlobalTimeout: 600, + Tasks: []workflow.Task{ + { + Name: "do-or-do-not-there-is-no-try", + WorkerAddr: "00:00:53:00:53:F4", + Actions: []workflow.Action{ + { + Name: "stream-image-to-disk", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 300, + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + "/tmp/debug:/tmp/debug", + }, + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Pid: "host", + }, + }, + }, + }, + }, + &v1alpha1.WorkflowStatus{ + GlobalTimeout: 600, + Tasks: []v1alpha1.Task{ + { + Name: "do-or-do-not-there-is-no-try", + WorkerAddr: "00:00:53:00:53:F4", + Actions: []v1alpha1.Action{ + { + Name: "stream-image-to-disk", + Image: "quay.io/tinkerbell-actions/image2disk:v1.0.0", + Timeout: 300, + Volumes: []string{ + "/dev:/dev", + "/dev/console:/dev/console", + "/lib/firmware:/lib/firmware:ro", + "/tmp/debug:/tmp/debug", + }, + Pid: "host", + Environment: map[string]string{ + "COMPRESSED": "true", + "DEST_DISK": "/dev/nvme0n1", + "IMG_URL": "http://10.1.1.11:8080/debian-10-openstack-amd64.raw.gz", + }, + Status: "STATE_PENDING", + }, + }, + }, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := WorkflowYAMLToStatus(tc.inputWf) + if diff := cmp.Diff(got, tc.want, protocmp.Transform()); diff != "" { + t.Errorf("unexpected difference:\n%v", diff) + } + }) + } +} diff --git a/pkg/internal/tests/frozen_time.go b/pkg/internal/tests/frozen_time.go new file mode 100644 index 000000000..391bfa61b --- /dev/null +++ b/pkg/internal/tests/frozen_time.go @@ -0,0 +1,64 @@ +package tests + +import ( + "time" + + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// FrozenTime is an interface for testing out fake times with additional +// methods for protobuf and Kubernetes time formats. +type FrozenTime interface { + // Now never changes + Now() time.Time + Before(time.Duration) time.Time + After(time.Duration) time.Time + + // Before Now() by int64 seconds + BeforeSec(int64) time.Time + // After Now() by int64 seconds + AfterSec(int64) time.Time + + MetaV1Now() *metav1.Time + MetaV1Before(time.Duration) *metav1.Time + MetaV1After(time.Duration) *metav1.Time + MetaV1BeforeSec(int64) *metav1.Time + MetaV1AfterSec(int64) *metav1.Time + + PbNow() *timestamppb.Timestamp + PbBefore(time.Duration) *timestamppb.Timestamp + PbAfter(time.Duration) *timestamppb.Timestamp + PbBeforeSec(int64) *timestamppb.Timestamp + PbAfterSec(int64) *timestamppb.Timestamp +} + +func NewFrozenTimeUnix(unix int64) FrozenTime { + return &ft{t: time.Unix(unix, 0)} +} + +func NewFrozenTime(t time.Time) FrozenTime { + return &ft{t} +} + +type ft struct { + t time.Time +} + +func (f *ft) Now() time.Time { return f.t } +func (f *ft) Before(d time.Duration) time.Time { return f.Now().Add(d) } +func (f *ft) After(d time.Duration) time.Time { return f.Now().Add(-d) } +func (f *ft) BeforeSec(s int64) time.Time { return f.Now().Add(time.Duration(-s) * time.Second) } +func (f *ft) AfterSec(s int64) time.Time { return f.Now().Add(time.Duration(s) * time.Second) } + +func (f *ft) MetaV1Now() *metav1.Time { t := metav1.NewTime(f.Now()); return &t } +func (f *ft) MetaV1Before(d time.Duration) *metav1.Time { t := metav1.NewTime(f.Before(d)); return &t } +func (f *ft) MetaV1After(d time.Duration) *metav1.Time { t := metav1.NewTime(f.After(d)); return &t } +func (f *ft) MetaV1BeforeSec(s int64) *metav1.Time { t := metav1.NewTime(f.BeforeSec(s)); return &t } +func (f *ft) MetaV1AfterSec(s int64) *metav1.Time { t := metav1.NewTime(f.AfterSec(s)); return &t } + +func (f *ft) PbNow() *timestamppb.Timestamp { return timestamppb.New(f.Now()) } +func (f *ft) PbBefore(d time.Duration) *timestamppb.Timestamp { return timestamppb.New(f.Before(d)) } +func (f *ft) PbAfter(d time.Duration) *timestamppb.Timestamp { return timestamppb.New(f.After(d)) } +func (f *ft) PbBeforeSec(s int64) *timestamppb.Timestamp { return timestamppb.New(f.BeforeSec(s)) } +func (f *ft) PbAfterSec(s int64) *timestamppb.Timestamp { return timestamppb.New(f.AfterSec(s)) } diff --git a/rules.mk b/rules.mk index c70bf8e55..24e318d37 100644 --- a/rules.mk +++ b/rules.mk @@ -11,7 +11,7 @@ MAKEFLAGS += --no-builtin-rules SHELL := bash .SHELLFLAGS := -o pipefail -euc -binaries := cmd/tink-cli/tink-cli cmd/tink-server/tink-server cmd/tink-worker/tink-worker +binaries := cmd/tink-cli/tink-cli cmd/tink-controller/tink-controller cmd/tink-server/tink-server cmd/tink-worker/tink-worker version := $(shell git rev-parse --short HEAD) tag := $(shell git tag --points-at HEAD) ifneq (,$(tag)) @@ -22,6 +22,7 @@ export CGO_ENABLED := 0 .PHONY: server cli worker test $(binaries) cli: cmd/tink-cli/tink-cli +controller: cmd/tink-controller/tink-controller server: cmd/tink-server/tink-server worker : cmd/tink-worker/tink-worker @@ -37,9 +38,11 @@ crossbinaries := $(crossbinaries:=386) $(crossbinaries:=amd64) $(crossbinaries:= $(binaries) $(crossbinaries): $(FLAGS) go build $(LDFLAGS) -o $@ ./$(@D) -.PHONY: tink-cli-image tink-server-image tink-worker-image +.PHONY: tink-cli-image tink-controller-image tink-server-image tink-worker-image tink-cli-image: cmd/tink-cli/tink-cli-linux-amd64 docker build -t tink-cli cmd/tink-cli/ +tink-controller-image: cmd/tink-controller/tink-controller-linux-amd64 + docker build -t tink-controller cmd/tink-controller/ tink-server-image: cmd/tink-server/tink-server-linux-amd64 docker build -t tink-server cmd/tink-server/ tink-worker-image: cmd/tink-worker/tink-worker-linux-amd64 @@ -72,10 +75,10 @@ protomocks: bin/moq .PHONY: check-protomocks check-protomocks: @git diff --no-ext-diff --quiet --exit-code -- protos/*/mock.go || ( - echo "Mock files need to be regenerated!"; + echo "Mock files need to be regenerated!"; git diff --no-ext-diff --exit-code --stat -- protos/*/mock.go ) - + .PHONY: pbfiles pbfiles: buf.gen.yaml buf.lock $(shell git ls-files 'protos/*/*.proto') $(toolsBins) buf generate @@ -84,6 +87,6 @@ pbfiles: buf.gen.yaml buf.lock $(shell git ls-files 'protos/*/*.proto') $(toolsB .PHONY: check-pbfiles check-pbfiles: pbfiles @git diff --no-ext-diff --quiet --exit-code -- protos/*/*.pb.* || ( - echo "Protobuf files need to be regenerated!"; + echo "Protobuf files need to be regenerated!"; git diff --no-ext-diff --exit-code --stat -- protos/*/*.pb.* ) diff --git a/workflow/template_validator.go b/workflow/template_validator.go index 342a7261b..6eae3bb87 100644 --- a/workflow/template_validator.go +++ b/workflow/template_validator.go @@ -21,7 +21,7 @@ const ( errActionDuplicateName = "two actions in a task cannot have same name: %s" errActionInvalidImage = "invalid action image: %s" errTemplateParsing = "failed to parse template with ID %s" - errInvalidHardwareAddress = "failed to render template, invalid hardware address: %s" + errInvalidHardwareAddress = "failed to render template, invalid hardware address: %v" ) // Parse parses the template yaml content into a Workflow. @@ -60,36 +60,48 @@ func MustParseFromFile(path string) *Workflow { return MustParse(content) } -// RenderTemplate renders the workflow template wrt given hardware details. +// RenderTemplate renders the workflow template with regard to the given hardware details. func RenderTemplate(templateID, templateData string, devices []byte) (string, error) { - var hardware map[string]interface{} + var hardware map[string]string err := json.Unmarshal(devices, &hardware) if err != nil { err = errors.Wrapf(err, errTemplateParsing, templateID) return "", err } + _, buf, err := RenderTemplateHardware(templateID, templateData, hardware) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// RenderTemplateHardware renders the workflow template and returns the Workflow and the interpolated bytes. +func RenderTemplateHardware(templateID, templateData string, hardware map[string]string) (*Workflow, *bytes.Buffer, error) { t := template.New("workflow-template").Option("missingkey=error") - _, err = t.Parse(templateData) + _, err := t.Parse(templateData) if err != nil { err = errors.Wrapf(err, errTemplateParsing, templateID) - return "", err + return nil, nil, err } buf := new(bytes.Buffer) err = t.Execute(buf, hardware) if err != nil { err = errors.Wrapf(err, errTemplateParsing, templateID) - return "", err + return nil, nil, err } - wf := MustParse(buf.Bytes()) + wf, err := Parse(buf.Bytes()) + if err != nil { + return nil, nil, err + } for _, task := range wf.Tasks { if task.WorkerAddr == "" { - return "", fmt.Errorf(errInvalidHardwareAddress, string(devices)) + return nil, nil, fmt.Errorf(errInvalidHardwareAddress, hardware) } } - return buf.String(), nil + return wf, buf, nil } // validate validates a workflow template against certain requirements. diff --git a/workflow/template_validator_test.go b/workflow/template_validator_test.go index ee93221b8..9d4b52c07 100644 --- a/workflow/template_validator_test.go +++ b/workflow/template_validator_test.go @@ -301,6 +301,110 @@ tasks: timeout: 60 `, }, + { + name: "malformed template", + hwAddress: []byte("{\"device_1\":\"08:00:27:00:00:01\"}"), + templateID: "98788301-d0d9-4ee9-84df-b64e6e1ef1cc", + templateData: ` +version: "0.1" +name: hello_world_workflow +global_timeout: 600 +tasks: + - name: "hello world" + worker: "{{.device_1}" + actions: + - name: "hello_world" + image: hello-world + timeout: 60 +`, + expectedError: func(t *testing.T, err error) { + t.Helper() + if err == nil { + t.Error("expected error, got nil") + } + if !strings.Contains(err.Error(), `template: workflow-template:7: unexpected "}" in operand`) { + t.Errorf("\nexpected err: '%s'\ngot: '%s'", `failed to parse template with ID 98788301-d0d9-4ee9-84df-b64e6e1ef1cc: template: workflow-template:7: unexpected "}" in operand`, err) + } + }, + }, + { + name: "invalid yaml in template", + hwAddress: []byte("{\"device_1\":\"08:00:27:00:00:01\"}"), + templateID: "98788301-d0d9-4ee9-84df-b64e6e1ef1cc", + templateData: ` +version: "0.1" + name: hello_world_workflow +global_timeout: 600 +tasks: + - name: "hello world" + worker: "{{.device_1}}" + actions: + - name: "hello_world" + image: hello-world + timeout: 60 +`, + expectedError: func(t *testing.T, err error) { + t.Helper() + if err == nil { + t.Error("expected error, got nil") + } + if !strings.Contains(err.Error(), `parsing yaml data: yaml: line 2: did not find expected key`) { + t.Errorf("\nexpected err: '%s'\ngot: '%s'", `parsing yaml data: yaml: line 2: did not find expected key`, err) + } + }, + }, + { + name: "Empty worker address", + hwAddress: []byte("{\"device_1\":\"\"}"), + templateID: "98788301-d0d9-4ee9-84df-b64e6e1ef1cc", + templateData: ` +version: "0.1" +name: hello_world_workflow +global_timeout: 600 +tasks: + - name: "hello world" + worker: "{{.device_1}}" + actions: + - name: "hello_world" + image: hello-world + timeout: 60 +`, + expectedError: func(t *testing.T, err error) { + t.Helper() + if err == nil { + t.Error("expected error, got nil") + } + if !strings.Contains(err.Error(), `failed to render template, invalid hardware address: map[device_1:]`) { + t.Errorf("\nexpected err: '%s'\ngot: '%s'", `failed to render template, invalid hardware address: map[device_1:]`, err) + } + }, + }, + { + name: "Invalid hardware json", + hwAddress: []byte(`{"device_1":"abc"}}`), + templateID: "98788301-d0d9-4ee9-84df-b64e6e1ef1cc", + templateData: ` +version: "0.1" +name: hello_world_workflow +global_timeout: 600 +tasks: + - name: "hello world" + worker: "{{.device_1}}" + actions: + - name: "hello_world" + image: hello-world + timeout: 60 +`, + expectedError: func(t *testing.T, err error) { + t.Helper() + if err == nil { + t.Error("expected error, got nil") + } + if !strings.Contains(err.Error(), `failed to parse template with ID 98788301-d0d9-4ee9-84df-b64e6e1ef1cc: invalid character '}' after top-level value`) { + t.Errorf("\nexpected err: '%s'\ngot: '%s'", `failed to parse template with ID 98788301-d0d9-4ee9-84df-b64e6e1ef1cc: invalid character '}' after top-level value`, err) + } + }, + }, } for _, test := range tests {