From 4ebc9e53e9744aaae4030171ebf35f2067a94647 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 18 Sep 2024 22:27:20 -0600 Subject: [PATCH 01/24] WIP: add booting options to Workflow spec: Add spec field and functionality for setting the allowPXE field in hardware. Add spec field and functionality for creating a job.bmc.tinkerbell.org object to get the Hardware into a netboot state. Signed-off-by: Jacob Weinstock --- Tools.mk | 2 +- api/v1alpha1/workflow_types.go | 64 +- api/v1alpha1/zz_generated.deepcopy.go | 41 + buf.lock | 2 +- config/crd/bases/tinkerbell.org_hardware.yaml | 8 +- config/crd/bases/tinkerbell.org_osies.yaml | 2 +- .../crd/bases/tinkerbell.org_templates.yaml | 6 +- .../crd/bases/tinkerbell.org_workflows.yaml | 67 +- go.mod | 84 +- go.sum | 1228 ++--------------- internal/deprecated/controller/manager.go | 2 + internal/deprecated/workflow/reconciler.go | 198 +++ internal/server/kubernetes_api_workflow.go | 8 + 13 files changed, 512 insertions(+), 1200 deletions(-) diff --git a/Tools.mk b/Tools.mk index 36a58cdec..c35ebaf05 100644 --- a/Tools.mk +++ b/Tools.mk @@ -23,7 +23,7 @@ PROTOC_GEN_GO_GRPC := $(TOOLS_DIR)/protoc-gen-go-grpc PROTOC_GEN_GO_VER := v1.28 PROTOC_GEN_GO := $(TOOLS_DIR)/protoc-gen-go -CONTROLLER_GEN_VER := v0.15 +CONTROLLER_GEN_VER := v0.16.3 CONTROLLER_GEN := $(TOOLS_DIR)/controller-gen-$(CONTROLLER_GEN_VER) KUSTOMIZE_VER := v4.5 diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 97dc7ce02..2e0a3c80e 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -7,11 +7,12 @@ import ( type WorkflowState string const ( - WorkflowStatePending = WorkflowState("STATE_PENDING") - WorkflowStateRunning = WorkflowState("STATE_RUNNING") - WorkflowStateFailed = WorkflowState("STATE_FAILED") - WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") - WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") + WorkflowStatePending = WorkflowState("STATE_PENDING") + WorkflowStateRunning = WorkflowState("STATE_RUNNING") + WorkflowStateFailed = WorkflowState("STATE_FAILED") + WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") + WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") + WorkflowStatePreparing = WorkflowState("STATE_PREPARING") ) // WorkflowSpec defines the desired state of Workflow. @@ -24,6 +25,27 @@ type WorkflowSpec struct { // A mapping of template devices to hadware mac addresses HardwareMap map[string]string `json:"hardwareMap,omitempty"` + + // ToggleNetworkBoot uses the HardwareRef and changes the all network interfaces to boot from network + // before running the workflow and sets all network interfaces to not boot from the network after a successful workflow. + // ToggleNetworkBoot bool `json:"toggleNetworkBoot,omitempty"` + + // NetbootBeforeWorkflow uses the HardwareRef and the bmcRef in the hardware to boot the machine from the network before running the workflow. + // NetbootBeforeWorkflow bool `json:"netbootBeforeWorkflow,omitempty"` + + // BootOpts is a set of options to be used when netbooting the hardware. + BootOpts BootOpts `json:"bootOpts,omitempty"` +} + +type BootOpts struct { + // ToggleHardware indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. + // This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. + // A HardwareRef must be provided. + ToggleHardware bool `json:"toggleHardware,omitempty"` + // OneTimeNetboot indicates whether the controller should create a job.bmc.tinkerbell.org object for getting the associated hardware + // into a netbooting state. + // A HardwareRef that contains a spec.BmcRef must be provided. + OneTimeNetboot bool `json:"oneTimeNetboot,omitempty"` } // WorkflowStatus defines the observed state of Workflow. @@ -36,6 +58,38 @@ type WorkflowStatus struct { // Tasks are the tasks to be completed Tasks []Task `json:"tasks,omitempty"` + + // ToggleHardware indicates whether the controller has successfully toggled the network boot setting + // in the associated hardware. + ToggleHardware *Status `json:"toggleHardware,omitempty"` + + // OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. + OneTimeNetboot *Status `json:"oneTimeNetboot,omitempty"` +} + +// Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". +type Status struct { + // Status of the operation. + // One of: "Success" or "Failure". + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Status string `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"` + // A human-readable description of the status of this operation. + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"` + // A machine-readable description of why this operation is in the + // "Failure" status. If this value is empty there + // is no information available. A Reason clarifies an HTTP status + // code but does not override it. + // +optional + Reason metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason,casttype=StatusReason"` + // Extended data associated with the reason. Each reason may define its + // own extended details. This field is optional and the data returned + // is not guaranteed to conform to any schema except that defined by + // the reason type. + // +optional + // +listType=atomic + // Details *metav1.StatusDetails `json:"details,omitempty" protobuf:"bytes,5,opt,name=details"` } // Task represents a series of actions to be completed by a worker. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ad563c10b..edf34e2a7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -62,6 +62,21 @@ func (in *Action) DeepCopy() *Action { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BootOpts) DeepCopyInto(out *BootOpts) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootOpts. +func (in *BootOpts) DeepCopy() *BootOpts { + if in == nil { + return nil + } + out := new(BootOpts) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DHCP) DeepCopyInto(out *DHCP) { *out = *in @@ -701,6 +716,21 @@ func (in *OSIE) DeepCopy() *OSIE { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in @@ -898,6 +928,7 @@ func (in *WorkflowSpec) DeepCopyInto(out *WorkflowSpec) { (*out)[key] = val } } + out.BootOpts = in.BootOpts } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSpec. @@ -920,6 +951,16 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ToggleHardware != nil { + in, out := &in.ToggleHardware, &out.ToggleHardware + *out = new(Status) + **out = **in + } + if in.OneTimeNetboot != nil { + in, out := &in.OneTimeNetboot, &out.OneTimeNetboot + *out = new(Status) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus. diff --git a/buf.lock b/buf.lock index e761619a5..c0f64f319 100644 --- a/buf.lock +++ b/buf.lock @@ -4,4 +4,4 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: ee48893a270147348e3edc6c1a03de0e + commit: e7f8d366f5264595bcc4cd4139af9973 diff --git a/config/crd/bases/tinkerbell.org_hardware.yaml b/config/crd/bases/tinkerbell.org_hardware.yaml index cb90efcaf..fa3b35472 100644 --- a/config/crd/bases/tinkerbell.org_hardware.yaml +++ b/config/crd/bases/tinkerbell.org_hardware.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: hardware.tinkerbell.org spec: group: tinkerbell.org @@ -421,9 +421,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -530,16 +528,14 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic storageDevices: description: StorageDevices is a list of storage devices that will be available in the OSIE. items: - description: "StorageDevice describes a storage device path that will be present in the OSIE.\nStorageDevices must be valid Linux paths. They should not contain partitions.\n\n\nGood\n\n\n\t/dev/sda\n\t/dev/nvme0n1\n\n\nBad (contains partitions)\n\n\n\t/dev/sda1\n\t/dev/nvme0n1p1\n\n\nBad (invalid Linux path)\n\n\n\t\\dev\\sda" + description: "StorageDevice describes a storage device path that will be present in the OSIE.\nStorageDevices must be valid Linux paths. They should not contain partitions.\n\nGood\n\n\t/dev/sda\n\t/dev/nvme0n1\n\nBad (contains partitions)\n\n\t/dev/sda1\n\t/dev/nvme0n1p1\n\nBad (invalid Linux path)\n\n\t\\dev\\sda" pattern: ^(/[^/ ]*)+/?$ type: string type: array diff --git a/config/crd/bases/tinkerbell.org_osies.yaml b/config/crd/bases/tinkerbell.org_osies.yaml index b10d51a9f..e8270411f 100644 --- a/config/crd/bases/tinkerbell.org_osies.yaml +++ b/config/crd/bases/tinkerbell.org_osies.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: osies.tinkerbell.org spec: group: tinkerbell.org diff --git a/config/crd/bases/tinkerbell.org_templates.yaml b/config/crd/bases/tinkerbell.org_templates.yaml index a7570b066..8331b59b4 100644 --- a/config/crd/bases/tinkerbell.org_templates.yaml +++ b/config/crd/bases/tinkerbell.org_templates.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: templates.tinkerbell.org spec: group: tinkerbell.org @@ -134,7 +134,7 @@ spec: volumes: description: Volumes defines the volumes to mount into the container. items: - description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\n\nRead-only bind mount bound to /data\n\n\n\t/etc/data:/data:ro\n\n\nWritable volume name bound to /data\n\n\n\tshared_volume:/data\n\n\nSee https://docs.docker.com/storage/volumes/ for additional details." + description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\nRead-only bind mount bound to /data\n\n\t/etc/data:/data:ro\n\nWritable volume name bound to /data\n\n\tshared_volume:/data\n\nSee https://docs.docker.com/storage/volumes/ for additional details." type: string type: array required: @@ -155,7 +155,7 @@ spec: Volumes to be mounted on all actions. If an action specifies the same volume it will take precedence. items: - description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\n\nRead-only bind mount bound to /data\n\n\n\t/etc/data:/data:ro\n\n\nWritable volume name bound to /data\n\n\n\tshared_volume:/data\n\n\nSee https://docs.docker.com/storage/volumes/ for additional details." + description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\nRead-only bind mount bound to /data\n\n\t/etc/data:/data:ro\n\nWritable volume name bound to /data\n\n\tshared_volume:/data\n\nSee https://docs.docker.com/storage/volumes/ for additional details." type: string type: array type: object diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 82ed7a1dd..cde1ded64 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: workflows.tinkerbell.org spec: group: tinkerbell.org @@ -49,6 +49,22 @@ spec: spec: description: WorkflowSpec defines the desired state of Workflow. properties: + bootOpts: + description: BootOpts is a set of options to be used when netbooting the hardware. + properties: + oneTimeNetboot: + description: |- + OneTimeNetboot indicates whether the controller should create a job.bmc.tinkerbell.org object for getting the associated hardware + into a netbooting state. + A HardwareRef that contains a spec.BmcRef must be provided. + type: boolean + toggleHardware: + description: |- + ToggleHardware indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. + This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. + A HardwareRef must be provided. + type: boolean + type: object hardwareMap: additionalProperties: type: string @@ -68,6 +84,26 @@ spec: description: GlobalTimeout represents the max execution time format: int64 type: integer + oneTimeNetboot: + description: OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. + properties: + message: + description: A human-readable description of the status of this operation. + type: string + reason: + description: |- + A machine-readable description of why this operation is in the + "Failure" status. If this value is empty there + is no information available. A Reason clarifies an HTTP status + code but does not override it. + type: string + status: + description: |- + Status of the operation. + One of: "Success" or "Failure". + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + type: string + type: object state: description: State is the state of the workflow in Tinkerbell. type: string @@ -131,6 +167,28 @@ spec: - worker type: object type: array + toggleHardware: + description: |- + ToggleHardware indicates whether the controller has successfully toggled the network boot setting + in the associated hardware. + properties: + message: + description: A human-readable description of the status of this operation. + type: string + reason: + description: |- + A machine-readable description of why this operation is in the + "Failure" status. If this value is empty there + is no information available. A Reason clarifies an HTTP status + code but does not override it. + type: string + status: + description: |- + Status of the operation. + One of: "Success" or "Failure". + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + type: string + type: object type: object type: object served: true @@ -186,9 +244,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -199,7 +255,6 @@ spec: TemplateParams are a list of key-value pairs that are injected into templates at render time. TemplateParams are exposed to templates using a top level .Params key. - For example, TemplateParams = {"foo": "bar"}, the foo key can be accessed via .Params.foo. type: object templateRef: @@ -212,9 +267,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -291,7 +344,7 @@ spec: volumes: description: Volumes defines the volumes to mount into the container. items: - description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\n\nRead-only bind mount bound to /data\n\n\n\t/etc/data:/data:ro\n\n\nWritable volume name bound to /data\n\n\n\tshared_volume:/data\n\n\nSee https://docs.docker.com/storage/volumes/ for additional details." + description: "Volume is a specification for mounting a volume in an action. Volumes take the form\n{SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that\ndoes not exist it will be created for you. Examples:\n\nRead-only bind mount bound to /data\n\n\t/etc/data:/data:ro\n\nWritable volume name bound to /data\n\n\tshared_volume:/data\n\nSee https://docs.docker.com/storage/volumes/ for additional details." type: string type: array required: diff --git a/go.mod b/go.mod index bc7dae518..a688defc3 100644 --- a/go.mod +++ b/go.mod @@ -26,17 +26,18 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 + github.com/tinkerbell/rufio v0.3.3 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - google.golang.org/grpc v1.63.2 + google.golang.org/grpc v1.66.2 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.30.3 - k8s.io/apimachinery v0.30.3 - k8s.io/client-go v0.30.3 - knative.dev/pkg v0.0.0-20211119170723-a99300deff34 - sigs.k8s.io/controller-runtime v0.18.4 + k8s.io/api v0.31.1 + k8s.io/apimachinery v0.31.1 + k8s.io/client-go v0.31.1 + knative.dev/pkg v0.0.0-20240917091217-aaab500c26c4 + sigs.k8s.io/controller-runtime v0.19.0 sigs.k8s.io/yaml v1.4.0 ) @@ -46,21 +47,21 @@ require ( github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -68,10 +69,10 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -79,7 +80,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -102,36 +103,39 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.26.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.26.0 // indirect - go.opentelemetry.io/otel/sdk v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.26.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect + golang.org/x/tools v0.25.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.30.1 // indirect - k8s.io/klog/v2 v2.120.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + gotest.tools/v3 v3.5.1 // indirect + k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index dc76828ad..ffb98c542 100644 --- a/go.sum +++ b/go.sum @@ -1,244 +1,7 @@ -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.18.2/go.mod h1:AiIj7BWXyhO5gGVmYJ+S8tbkCx3yb0IMjua8Aw4naVM= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -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/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= @@ -247,85 +10,22 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -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/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= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -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/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= -github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -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-20211001041855-01bcc9b48dfe/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/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= @@ -334,60 +34,22 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -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/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/equinix-labs/otel-init-go v0.0.9 h1:hdh0Qifs1vzFnaN6UpJz0pO6A6ZejXjvkEFi8OGTfpE= github.com/equinix-labs/otel-init-go v0.0.9/go.mod h1:5h8apPuPWz/KaMvAb3d0HoPEisQrUnqPmkc2T5SSpX4= -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 v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -397,985 +59,279 @@ github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-logr/zerologr v1.2.3 h1:up5N9vcH9Xck3jJkXzgyOxozT14R47IyDODz8LM1KSs= github.com/go-logr/zerologr v1.2.3/go.mod h1:BxwGo7y5zgSHYR1BjbnHPyF/5ZjVKfKxAZANVu6E8Ho= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -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/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -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/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.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -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/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/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -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.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -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/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -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.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -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.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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/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/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -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 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -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= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -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/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -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/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= -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.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/tinkerbell/rufio v0.3.3 h1:d02r83hQnYv+4WzJwU+t1vr7qPmnsAmWp40Uef93/60= +github.com/tinkerbell/rufio v0.3.3/go.mod h1:yzCGjGbI1UzusuaeI26oG7XpBZElYqBXkk8jEMgWGwc= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= -go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= -go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= -go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= -go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= -go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= -go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -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 v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -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-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/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/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/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/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-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-20210823070655-63515b42dcdf/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -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= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -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.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -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/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -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-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -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-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-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.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.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -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= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a h1:KyUe15n7B1YCu+kMmPtlXxgkLQbp+Dw0tCRZf9Sd+CE= +google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a h1:EKiZZXueP9/T68B8Nl0GAx9cjbQnCId0yP3qPMgaaHs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.21.4/go.mod h1:fTVGP+M4D8+00FN2cMnJqk/eb/GH53bvmNs2SVTmpFk= -k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= -k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= -k8s.io/apiextensions-apiserver v0.21.4/go.mod h1:OoC8LhI9LnV+wKjZkXIBbLUwtnOGJiTRE33qctH5CIk= -k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= -k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= -k8s.io/apimachinery v0.21.4/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= -k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= -k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.21.4/go.mod h1:SErUuFBBPZUcD2nsUU8hItxoYheqyYr2o/pCINEPW8g= -k8s.io/client-go v0.21.4/go.mod h1:t0/eMKyUAq/DoQ7vW8NVVA00/nomlwC+eInsS8PxSew= -k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= -k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= -k8s.io/code-generator v0.21.4/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= -k8s.io/component-base v0.21.4/go.mod h1:ZKG0eHVX+tUDcaoIGpU3Vtk4TIjMddN9uhEWDmW6Nyg= -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/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.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -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= -pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 h1:1Wof1cGQgA5pqgo8MxKPtf+qN6Sh/0JzznmeGPm1HnE= +k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8/go.mod h1:Os6V6dZwLNii3vxFpxcNaTmH8LJJBkOTg1N0tOA0fvA= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +knative.dev/pkg v0.0.0-20240917091217-aaab500c26c4 h1:1yMPCa3CnWH8darWwC3YxBJC19ZvE/XNA4RtNnxKPDM= +knative.dev/pkg v0.0.0-20240917091217-aaab500c26c4/go.mod h1:ZK0e9aChRwXJCpT8cypwvn/bJYTo6ygmyjiaz0E32EY= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/deprecated/controller/manager.go b/internal/deprecated/controller/manager.go index bb5a72de6..4c5178f58 100644 --- a/internal/deprecated/controller/manager.go +++ b/internal/deprecated/controller/manager.go @@ -3,6 +3,7 @@ package controller import ( "fmt" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "github.com/tinkerbell/tink/internal/deprecated/workflow" "k8s.io/apimachinery/pkg/runtime" @@ -15,6 +16,7 @@ import ( var schemeBuilder = runtime.NewSchemeBuilder( clientgoscheme.AddToScheme, v1alpha1.AddToScheme, + rufio.AddToScheme, ) // DefaultScheme returns a scheme with all the types necessary for the tink controller. diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 005de573d..a266be146 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -6,9 +6,11 @@ import ( "time" "github.com/go-logr/logr" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -32,6 +34,7 @@ func NewReconciler(client ctrlclient.Client) *Reconciler { // +kubebuilder:rbac:groups=tinkerbell.org,resources=hardware;hardware/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=templates;templates/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=workflows;workflows/status,verbs=get;list;watch;update;patch;delete +// +kubebuilder:rbac:groups=bmc.tinkerbell.org,resources=job;job/status,verbs=get;delete;create;watch func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { logger := ctrl.LoggerFrom(ctx) @@ -58,6 +61,34 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco resp, err = r.processNewWorkflow(ctx, logger, wflow) case v1alpha1.WorkflowStateRunning: resp = r.processRunningWorkflow(ctx, wflow) + case v1alpha1.WorkflowStatePreparing: + logger.Info("debugging 1") + existingJob := &rufio.Job{} + jobName := fmt.Sprintf("tink-controller-%s-one-time-netboot", wflow.Spec.HardwareRef) + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: wflow.Namespace}, existingJob); err != nil { + return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) + } + logger.Info("debugging 2", "job conditions", existingJob.Status.Conditions) + if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { + return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + } + if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { + logger.Info("debugging 3") + wflow.Status.State = v1alpha1.WorkflowStatePending + } else { + return reconcile.Result{Requeue: true}, nil + } + case v1alpha1.WorkflowStateSuccess: + // handle updating hardware allowPXE to false + var hw v1alpha1.Hardware + err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: wflow.Spec.HardwareRef, Namespace: wflow.Namespace}, &hw) + if err != nil && !errors.IsNotFound(err) { + logger.Error(err, "error getting Hardware object for WorkflowStateSuccess processing") + return reconcile.Result{}, err + } + if err := r.handleHardwareAllowPXE(ctx, wflow, &hw); err != nil { + return resp, err + } default: return resp, nil } @@ -71,6 +102,42 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return resp, err } +func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware) error { + + // We need to set allowPXE to true before a workflow runs. + // We need to set allowPXE to false after a workflow completes successfully. + + // before workflow case + if stored.Status.ToggleHardware == nil || (stored.Status.ToggleHardware != nil && stored.Status.ToggleHardware.Status == "" && stored.Status.State == "" || stored.Status.State == v1alpha1.WorkflowStatePending) { + status := &v1alpha1.Status{Status: "success", Message: "allowPXE set to true"} + for _, iface := range hardware.Spec.Interfaces { + iface.Netboot.AllowPXE = ptr.Bool(true) + } + if err := r.client.Update(ctx, hardware); err != nil { + status.Status = "failed" + stored.Status.ToggleHardware = status + return err + } + stored.Status.ToggleHardware = status + } + + // after workflow case + if stored.Status.State == v1alpha1.WorkflowStateSuccess { + status := &v1alpha1.Status{Status: "success", Message: "allowPXE set to false"} + for _, iface := range hardware.Spec.Interfaces { + iface.Netboot.AllowPXE = ptr.Bool(false) + } + if err := r.client.Update(ctx, hardware); err != nil { + status.Status = "failed" + stored.Status.ToggleHardware = status + return err + } + stored.Status.ToggleHardware = status + } + + return nil +} + func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored *v1alpha1.Workflow) (reconcile.Result, error) { tpl := &v1alpha1.Template{} if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.TemplateRef, Namespace: stored.Namespace}, tpl); err != nil { @@ -120,6 +187,137 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // populate Task and Action data stored.Status = *YAMLToStatus(tinkWf) + // set hardware allowPXE if requested. + if stored.Spec.BootOpts.ToggleHardware { + // We need to set allowPXE to true before a workflow runs. + // We need to set allowPXE to false after a workflow completes successfully. + + if err := r.handleHardwareAllowPXE(ctx, stored, &hardware); err != nil { + return reconcile.Result{}, err + } + } + + // netboot the hardware if requested + if stored.Spec.BootOpts.OneTimeNetboot { + // check if the hardware has a bmcRef + if hardware.Spec.BMCRef == nil { + return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hardware.Name) + } + + // check if an existing job.bmc.tinkerbell.org object exists, if so delete it. + existingJob := &rufio.Job{} + jobName := fmt.Sprintf("tink-controller-%s-one-time-netboot", hardware.Name) + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hardware.Namespace}, existingJob); err == nil { + logger.Info("debugging in delete", "stored.status", stored.Status, "job conditions", existingJob.Status.Conditions) + if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionFalse) || len(existingJob.Status.Conditions) != 2 { + logger.Info("one time netboot job is still running", "job", jobName, "stored.status", stored.Status, "conditions", existingJob.Status.Conditions) + return reconcile.Result{Requeue: true}, nil + } + opts := []ctrlclient.DeleteOption{ + ctrlclient.GracePeriodSeconds(0), + ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), + } + logger.Info("deleting existing one time netboot job", "job", jobName, "conditions", existingJob.Status.Conditions) + if err := r.client.Delete(ctx, existingJob, opts...); err != nil { + return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + + return reconcile.Result{Requeue: true}, nil + } + + // create a job.bmc.tinkerbell.org object to netboot the hardware + name := fmt.Sprintf("tink-controller-%s-one-time-netboot", hardware.Name) + ns := hardware.Namespace + efiBoot := func() bool { + for _, iface := range hardware.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.UEFI { + return true + } + } + return false + }() + job := &rufio.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + Annotations: map[string]string{ + "tink-controller-auto-created": "true", + }, + Labels: map[string]string{ + "tink-controller-auto-created": "true", + }, + }, + Spec: rufio.JobSpec{ + MachineRef: rufio.MachineRef{ + Name: hardware.Spec.BMCRef.Name, + Namespace: ns, + }, + Tasks: []rufio.Action{ + { + PowerAction: rufio.PowerHardOff.Ptr(), + }, + { + OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ + Devices: []rufio.BootDevice{ + rufio.PXE, + }, + EFIBoot: efiBoot, + }, + }, + { + PowerAction: rufio.PowerOn.Ptr(), + }, + }, + }, + } + logger.Info("creating one time netboot job", "job", job.Name) + if err := r.client.Create(ctx, job); err != nil { + return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + stored.Status.OneTimeNetboot = &v1alpha1.Status{Status: "success", Message: "one time netboot job created"} + // block until the job completes. This is needed as there can be a race condition if the Hardware is already running + // a Tink Worker. + stored.Status.State = v1alpha1.WorkflowStatePreparing + return reconcile.Result{Requeue: true}, nil + /* + logger.Info("debugging 2") + waitJob := &rufio.Job{} + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: job.Name, Namespace: job.Namespace}, waitJob); err != nil { + return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) + } + if waitJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { + return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + } + if waitJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { + stored.Status.State = v1alpha1.WorkflowStatePending + return reconcile.Result{}, nil + } + */ + /* + timeout, cancel := context.WithTimeout(ctx, time.Duration(5*float64(time.Minute))) + defer cancel() + for { + select { + case <-timeout.Done(): + return reconcile.Result{}, fmt.Errorf("timeout waiting for one time netboot job to complete") + default: + time.Sleep(2 * time.Second) + waitJob := &rufio.Job{} + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: job.Name, Namespace: job.Namespace}, waitJob); err != nil { + continue + } + if waitJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { + goto DONE + } + if waitJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { + return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + } + } + } + DONE: + */ + } + stored.Status.State = v1alpha1.WorkflowStatePending return reconcile.Result{}, nil } diff --git a/internal/server/kubernetes_api_workflow.go b/internal/server/kubernetes_api_workflow.go index 5f7e219bc..e22ceb15f 100644 --- a/internal/server/kubernetes_api_workflow.go +++ b/internal/server/kubernetes_api_workflow.go @@ -67,6 +67,8 @@ func (s *KubernetesBackedServer) getWorkflowByName(ctx context.Context, workflow // The following APIs are used by the worker. func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextRequest, stream proto.WorkflowService_GetWorkflowContextsServer) error { + // if spec.Netboot is true, and allowPXE: false in the hardware then don't serve a workflow context + // if spec.ToggleHardwareNetworkBooting is true, and any associated bmc jobs dont exists or have not completed successfully then don't serve a workflow context if req.GetWorkerId() == "" { return status.Errorf(codes.InvalidArgument, errInvalidWorkflowID) } @@ -75,6 +77,12 @@ func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextR return err } for _, wf := range wflows { + if wf.Spec.BootOpts.ToggleHardware && wf.Status.ToggleHardware != nil && wf.Status.ToggleHardware.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { + continue + } + if wf.Spec.BootOpts.OneTimeNetboot && wf.Status.ToggleHardware != nil && wf.Status.OneTimeNetboot.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { + continue + } if err := stream.Send(getWorkflowContext(wf)); err != nil { return err } From b3b089ff757c6b1f43e284fdeb2b80856d9e052f Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 19 Sep 2024 11:55:23 -0600 Subject: [PATCH 02/24] Fix job.bmc creation and deletion: Use status' to make sure creation and deletion work properly. Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 16 +- api/v1alpha1/zz_generated.deepcopy.go | 31 ++- .../crd/bases/tinkerbell.org_workflows.yaml | 56 ++++-- internal/deprecated/workflow/reconciler.go | 186 ++++++++---------- internal/server/kubernetes_api_workflow.go | 2 +- 5 files changed, 163 insertions(+), 128 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 2e0a3c80e..7f1ac530a 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -13,6 +13,8 @@ const ( WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") WorkflowStatePreparing = WorkflowState("STATE_PREPARING") + StatusSuccess = "success" + StatusFailure = "failure" ) // WorkflowSpec defines the desired state of Workflow. @@ -64,7 +66,12 @@ type WorkflowStatus struct { ToggleHardware *Status `json:"toggleHardware,omitempty"` // OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. - OneTimeNetboot *Status `json:"oneTimeNetboot,omitempty"` + OneTimeNetboot OneTimeNetbootStatus `json:"oneTimeNetboot,omitempty"` +} + +type OneTimeNetbootStatus struct { + CreationStatus *Status `json:"creationStatus,omitempty"` + DeletionStatus *Status `json:"deletionStatus,omitempty"` } // Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". @@ -92,6 +99,13 @@ type Status struct { // Details *metav1.StatusDetails `json:"details,omitempty" protobuf:"bytes,5,opt,name=details"` } +func (s *Status) IsSuccess() bool { + if s == nil { + return false + } + return s.Status == StatusSuccess +} + // Task represents a series of actions to be completed by a worker. type Task struct { Name string `json:"name"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index edf34e2a7..e2e00303c 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -716,6 +716,31 @@ func (in *OSIE) DeepCopy() *OSIE { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OneTimeNetbootStatus) DeepCopyInto(out *OneTimeNetbootStatus) { + *out = *in + if in.CreationStatus != nil { + in, out := &in.CreationStatus, &out.CreationStatus + *out = new(Status) + **out = **in + } + if in.DeletionStatus != nil { + in, out := &in.DeletionStatus, &out.DeletionStatus + *out = new(Status) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OneTimeNetbootStatus. +func (in *OneTimeNetbootStatus) DeepCopy() *OneTimeNetbootStatus { + if in == nil { + return nil + } + out := new(OneTimeNetbootStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Status) DeepCopyInto(out *Status) { *out = *in @@ -956,11 +981,7 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { *out = new(Status) **out = **in } - if in.OneTimeNetboot != nil { - in, out := &in.OneTimeNetboot, &out.OneTimeNetboot - *out = new(Status) - **out = **in - } + in.OneTimeNetboot.DeepCopyInto(&out.OneTimeNetboot) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus. diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index cde1ded64..358ce398a 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -87,22 +87,46 @@ spec: oneTimeNetboot: description: OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. properties: - message: - description: A human-readable description of the status of this operation. - type: string - reason: - description: |- - A machine-readable description of why this operation is in the - "Failure" status. If this value is empty there - is no information available. A Reason clarifies an HTTP status - code but does not override it. - type: string - status: - description: |- - Status of the operation. - One of: "Success" or "Failure". - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: string + creationStatus: + description: Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". + properties: + message: + description: A human-readable description of the status of this operation. + type: string + reason: + description: |- + A machine-readable description of why this operation is in the + "Failure" status. If this value is empty there + is no information available. A Reason clarifies an HTTP status + code but does not override it. + type: string + status: + description: |- + Status of the operation. + One of: "Success" or "Failure". + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + type: string + type: object + deletionStatus: + description: Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". + properties: + message: + description: A human-readable description of the status of this operation. + type: string + reason: + description: |- + A machine-readable description of why this operation is in the + "Failure" status. If this value is empty there + is no information available. A Reason clarifies an HTTP status + code but does not override it. + type: string + status: + description: |- + Status of the operation. + One of: "Success" or "Failure". + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + type: string + type: object type: object state: description: State is the state of the workflow in Tinkerbell. diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index a266be146..06a7f615d 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -10,6 +10,7 @@ import ( "github.com/tinkerbell/tink/api/v1alpha1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" ctrl "sigs.k8s.io/controller-runtime" @@ -18,6 +19,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) +const ( + bmcJobName = "tink-controller-%s-one-time-netboot" +) + // Reconciler is a type for managing Workflows. type Reconciler struct { client ctrlclient.Client @@ -62,18 +67,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco case v1alpha1.WorkflowStateRunning: resp = r.processRunningWorkflow(ctx, wflow) case v1alpha1.WorkflowStatePreparing: - logger.Info("debugging 1") + if wflow.Status.OneTimeNetboot.CreationStatus == nil { + return reconcile.Result{Requeue: true}, nil + } + if !wflow.Status.OneTimeNetboot.CreationStatus.IsSuccess() { + return reconcile.Result{Requeue: true}, nil + } existingJob := &rufio.Job{} - jobName := fmt.Sprintf("tink-controller-%s-one-time-netboot", wflow.Spec.HardwareRef) + jobName := fmt.Sprintf(bmcJobName, wflow.Spec.HardwareRef) if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: wflow.Namespace}, existingJob); err != nil { return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) } - logger.Info("debugging 2", "job conditions", existingJob.Status.Conditions) if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { return reconcile.Result{}, fmt.Errorf("one time netboot job failed") } if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { - logger.Info("debugging 3") wflow.Status.State = v1alpha1.WorkflowStatePending } else { return reconcile.Result{Requeue: true}, nil @@ -109,12 +117,12 @@ func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha // before workflow case if stored.Status.ToggleHardware == nil || (stored.Status.ToggleHardware != nil && stored.Status.ToggleHardware.Status == "" && stored.Status.State == "" || stored.Status.State == v1alpha1.WorkflowStatePending) { - status := &v1alpha1.Status{Status: "success", Message: "allowPXE set to true"} + status := &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "allowPXE set to true"} for _, iface := range hardware.Spec.Interfaces { iface.Netboot.AllowPXE = ptr.Bool(true) } if err := r.client.Update(ctx, hardware); err != nil { - status.Status = "failed" + status.Status = v1alpha1.StatusFailure stored.Status.ToggleHardware = status return err } @@ -123,12 +131,12 @@ func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha // after workflow case if stored.Status.State == v1alpha1.WorkflowStateSuccess { - status := &v1alpha1.Status{Status: "success", Message: "allowPXE set to false"} + status := &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "allowPXE set to false"} for _, iface := range hardware.Spec.Interfaces { iface.Netboot.AllowPXE = ptr.Bool(false) } if err := r.client.Update(ctx, hardware); err != nil { - status.Status = "failed" + status.Status = v1alpha1.StatusFailure stored.Status.ToggleHardware = status return err } @@ -205,117 +213,85 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, } // check if an existing job.bmc.tinkerbell.org object exists, if so delete it. - existingJob := &rufio.Job{} - jobName := fmt.Sprintf("tink-controller-%s-one-time-netboot", hardware.Name) - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hardware.Namespace}, existingJob); err == nil { - logger.Info("debugging in delete", "stored.status", stored.Status, "job conditions", existingJob.Status.Conditions) - if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionFalse) || len(existingJob.Status.Conditions) != 2 { - logger.Info("one time netboot job is still running", "job", jobName, "stored.status", stored.Status, "conditions", existingJob.Status.Conditions) + if !stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() && !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() { + existingJob := &rufio.Job{} + jobName := fmt.Sprintf(bmcJobName, hardware.Name) + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hardware.Namespace}, existingJob); err == nil { + opts := []ctrlclient.DeleteOption{ + ctrlclient.GracePeriodSeconds(0), + ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), + } + if err := r.client.Delete(ctx, existingJob, opts...); err != nil { + return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "previous existing one time netboot job deleted"} + return reconcile.Result{Requeue: true}, nil + } else { + if apierrors.IsNotFound(err) { + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job found"} + } else { + return reconcile.Result{Requeue: true}, err + } } - opts := []ctrlclient.DeleteOption{ - ctrlclient.GracePeriodSeconds(0), - ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), - } - logger.Info("deleting existing one time netboot job", "job", jobName, "conditions", existingJob.Status.Conditions) - if err := r.client.Delete(ctx, existingJob, opts...); err != nil { - return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - - return reconcile.Result{Requeue: true}, nil } - // create a job.bmc.tinkerbell.org object to netboot the hardware - name := fmt.Sprintf("tink-controller-%s-one-time-netboot", hardware.Name) - ns := hardware.Namespace - efiBoot := func() bool { - for _, iface := range hardware.Spec.Interfaces { - if iface.DHCP != nil && iface.DHCP.UEFI { - return true + if !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() && stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() { + // create a job.bmc.tinkerbell.org object to netboot the hardware + name := fmt.Sprintf(bmcJobName, hardware.Name) + ns := hardware.Namespace + efiBoot := func() bool { + for _, iface := range hardware.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.UEFI { + return true + } } - } - return false - }() - job := &rufio.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: ns, - Annotations: map[string]string{ - "tink-controller-auto-created": "true", - }, - Labels: map[string]string{ - "tink-controller-auto-created": "true", - }, - }, - Spec: rufio.JobSpec{ - MachineRef: rufio.MachineRef{ - Name: hardware.Spec.BMCRef.Name, + return false + }() + job := &rufio.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, Namespace: ns, + Annotations: map[string]string{ + "tink-controller-auto-created": "true", + }, + Labels: map[string]string{ + "tink-controller-auto-created": "true", + }, }, - Tasks: []rufio.Action{ - { - PowerAction: rufio.PowerHardOff.Ptr(), + Spec: rufio.JobSpec{ + MachineRef: rufio.MachineRef{ + Name: hardware.Spec.BMCRef.Name, + Namespace: ns, }, - { - OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ - Devices: []rufio.BootDevice{ - rufio.PXE, + Tasks: []rufio.Action{ + { + PowerAction: rufio.PowerHardOff.Ptr(), + }, + { + OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ + Devices: []rufio.BootDevice{ + rufio.PXE, + }, + EFIBoot: efiBoot, }, - EFIBoot: efiBoot, }, - }, - { - PowerAction: rufio.PowerOn.Ptr(), + { + PowerAction: rufio.PowerOn.Ptr(), + }, }, }, - }, - } - logger.Info("creating one time netboot job", "job", job.Name) - if err := r.client.Create(ctx, job); err != nil { - return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - stored.Status.OneTimeNetboot = &v1alpha1.Status{Status: "success", Message: "one time netboot job created"} - // block until the job completes. This is needed as there can be a race condition if the Hardware is already running - // a Tink Worker. - stored.Status.State = v1alpha1.WorkflowStatePreparing - return reconcile.Result{Requeue: true}, nil - /* - logger.Info("debugging 2") - waitJob := &rufio.Job{} - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: job.Name, Namespace: job.Namespace}, waitJob); err != nil { - return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) } - if waitJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { - return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + if err := r.client.Create(ctx, job); err != nil { + return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) } - if waitJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { - stored.Status.State = v1alpha1.WorkflowStatePending - return reconcile.Result{}, nil - } - */ - /* - timeout, cancel := context.WithTimeout(ctx, time.Duration(5*float64(time.Minute))) - defer cancel() - for { - select { - case <-timeout.Done(): - return reconcile.Result{}, fmt.Errorf("timeout waiting for one time netboot job to complete") - default: - time.Sleep(2 * time.Second) - waitJob := &rufio.Job{} - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: job.Name, Namespace: job.Namespace}, waitJob); err != nil { - continue - } - if waitJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { - goto DONE - } - if waitJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { - return reconcile.Result{}, fmt.Errorf("one time netboot job failed") - } - } - } - DONE: - */ + stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "one time netboot job created"} + // block until the job completes. This is needed as there can be a race condition if the Hardware is already running + // a Tink Worker. + stored.Status.State = v1alpha1.WorkflowStatePreparing + return reconcile.Result{Requeue: true}, nil + } + return reconcile.Result{Requeue: true}, nil } stored.Status.State = v1alpha1.WorkflowStatePending diff --git a/internal/server/kubernetes_api_workflow.go b/internal/server/kubernetes_api_workflow.go index e22ceb15f..f81538591 100644 --- a/internal/server/kubernetes_api_workflow.go +++ b/internal/server/kubernetes_api_workflow.go @@ -80,7 +80,7 @@ func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextR if wf.Spec.BootOpts.ToggleHardware && wf.Status.ToggleHardware != nil && wf.Status.ToggleHardware.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { continue } - if wf.Spec.BootOpts.OneTimeNetboot && wf.Status.ToggleHardware != nil && wf.Status.OneTimeNetboot.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { + if wf.Spec.BootOpts.OneTimeNetboot && wf.Status.State == v1alpha1.WorkflowStatePreparing { continue } if err := stream.Send(getWorkflowContext(wf)); err != nil { From ca2f7019c8488111911e50d4cc55c891381ade46 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 19 Sep 2024 12:53:51 -0600 Subject: [PATCH 03/24] Fix linting issues Signed-off-by: Jacob Weinstock --- .golangci.yml | 4 ++++ Tools.mk | 2 +- api/v1alpha1/workflow_methods.go | 2 +- api/v1alpha1/workflow_types.go | 2 +- cmd/tink-controller-v1alpha2/main.go | 6 +++--- cmd/tink-controller/main.go | 6 +++--- cmd/tink-server/main.go | 6 +++--- cmd/tink-worker/cmd/root.go | 4 ++-- cmd/tink-worker/worker/log_capturer_test.go | 2 +- cmd/virtual-worker/cmd/root.go | 4 ++-- cmd/virtual-worker/worker/container_manager.go | 2 +- internal/agent/agent_test.go | 6 +++--- internal/agent/transport/file_test.go | 2 +- internal/agent/transport/grpc_test.go | 4 ++-- internal/cli/agent.go | 4 ++-- internal/client/client.go | 2 +- internal/deprecated/workflow/reconciler.go | 14 +++++--------- internal/workflow/internal/reconcile_test.go | 2 +- 18 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 51bf67939..3bda4241f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -80,6 +80,10 @@ linters-settings: - name: var-naming - name: unconditional-recursion - name: waitgroup-by-value + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag + - name: struct-tag + arguments: + - "json,inline" staticcheck: go: "1.18" unused: diff --git a/Tools.mk b/Tools.mk index c35ebaf05..24b7eed3d 100644 --- a/Tools.mk +++ b/Tools.mk @@ -32,7 +32,7 @@ KUSTOMIZE := $(TOOLS_DIR)/kustomize-$(KUSTOMIZE_VER) SETUP_ENVTEST_VER := v0.0.0-20220304125252-9ee63fc65a97 SETUP_ENVTEST := $(TOOLS_DIR)/setup-envtest-$(SETUP_ENVTEST_VER) -GOLANGCI_LINT_VER := v1.52 +GOLANGCI_LINT_VER := v1.61 GOLANGCI_LINT := $(TOOLS_DIR)/golangci-lint-$(GOLANGCI_LINT_VER) YAMLFMT_VER := v0.6 diff --git a/api/v1alpha1/workflow_methods.go b/api/v1alpha1/workflow_methods.go index 978f406d4..7e1e78493 100644 --- a/api/v1alpha1/workflow_methods.go +++ b/api/v1alpha1/workflow_methods.go @@ -60,7 +60,7 @@ func (w *Workflow) getTaskActionInfo() taskInfo { INNER: for ai, action := range task.Actions { // Find the first non-successful action - switch action.Status { + switch action.Status { //nolint:exhaustive // WorkflowStatePreparing is only used in Workflows not Actions. case WorkflowStateSuccess: actionIndex++ continue diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 7f1ac530a..a3e2919b5 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -89,7 +89,7 @@ type Status struct { // is no information available. A Reason clarifies an HTTP status // code but does not override it. // +optional - Reason metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason,casttype=StatusReason"` + Reason metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"` // Extended data associated with the reason. Each reason may define its // own extended details. This field is optional and the data returned // is not guaranteed to conform to any schema except that defined by diff --git a/cmd/tink-controller-v1alpha2/main.go b/cmd/tink-controller-v1alpha2/main.go index 50b0c9238..590207ee4 100644 --- a/cmd/tink-controller-v1alpha2/main.go +++ b/cmd/tink-controller-v1alpha2/main.go @@ -73,14 +73,14 @@ func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "tink-controller", - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, _ []string) error { viper, err := createViper(logger) if err != nil { return fmt.Errorf("config init: %w", err) } return applyViper(viper, cmd) }, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { logger.Info("Starting controller version " + version) ccfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( @@ -172,7 +172,7 @@ func applyViper(v *viper.Viper, cmd *cobra.Command) error { for _, err := range errors { errs = append(errs, err.Error()) } - return fmt.Errorf(strings.Join(errs, ", ")) + return fmt.Errorf("%s", strings.Join(errs, ", ")) } return nil diff --git a/cmd/tink-controller/main.go b/cmd/tink-controller/main.go index 10726a13e..d1686b601 100644 --- a/cmd/tink-controller/main.go +++ b/cmd/tink-controller/main.go @@ -60,14 +60,14 @@ func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "tink-controller", - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, _ []string) error { viper, err := createViper(logger) if err != nil { return fmt.Errorf("config init: %w", err) } return applyViper(viper, cmd) }, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { logger.Info("Starting controller version " + version) ccfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( @@ -146,7 +146,7 @@ func applyViper(v *viper.Viper, cmd *cobra.Command) error { for _, err := range errors { errs = append(errs, err.Error()) } - return fmt.Errorf(strings.Join(errs, ", ")) + return fmt.Errorf("%s", strings.Join(errs, ", ")) } return nil diff --git a/cmd/tink-server/main.go b/cmd/tink-server/main.go index a9cae0bdc..78051a09b 100644 --- a/cmd/tink-server/main.go +++ b/cmd/tink-server/main.go @@ -78,14 +78,14 @@ func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "tink-server", - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, _ []string) error { viper, err := createViper(logger) if err != nil { return err } return applyViper(viper, cmd) }, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { // I am not sure if it is right for this to be here, // but as last step I want to keep compatibility with // what we have for a little bit and I thinik that's @@ -201,7 +201,7 @@ func applyViper(v *viper.Viper, cmd *cobra.Command) error { for _, err := range errors { errs = append(errs, err.Error()) } - return fmt.Errorf(strings.Join(errs, ", ")) + return fmt.Errorf("%s", strings.Join(errs, ", ")) } return nil diff --git a/cmd/tink-worker/cmd/root.go b/cmd/tink-worker/cmd/root.go index 6bdce966a..d4155ef2d 100644 --- a/cmd/tink-worker/cmd/root.go +++ b/cmd/tink-worker/cmd/root.go @@ -39,10 +39,10 @@ func NewRootCommand(version string) *cobra.Command { Use: "tink-worker", Short: "Tink Worker", Version: version, - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, _ []string) error { return initViper(logger, cmd) }, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { retryInterval := viper.GetDuration("retry-interval") retries := viper.GetInt("max-retry") workerID := viper.GetString("id") diff --git a/cmd/tink-worker/worker/log_capturer_test.go b/cmd/tink-worker/worker/log_capturer_test.go index dad44c5b7..9b257beeb 100644 --- a/cmd/tink-worker/worker/log_capturer_test.go +++ b/cmd/tink-worker/worker/log_capturer_test.go @@ -94,7 +94,7 @@ func TestLogCapturerContextLogger(t *testing.T) { } for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { + t.Run(tc.name, func(_ *testing.T) { logger := zapr.NewLogger(zap.Must(zap.NewDevelopment())) ctx := context.Background() if tc.logger != nil { diff --git a/cmd/virtual-worker/cmd/root.go b/cmd/virtual-worker/cmd/root.go index fa9b0e93c..46f04c4c2 100644 --- a/cmd/virtual-worker/cmd/root.go +++ b/cmd/virtual-worker/cmd/root.go @@ -34,10 +34,10 @@ func NewRootCommand(version string) *cobra.Command { rootCmd := &cobra.Command{ Use: "virtual-worker", Short: "Virtual Tink Worker", - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, _ []string) error { return createViper(logger, cmd) }, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { retryInterval := viper.GetDuration("retry-interval") retries := viper.GetInt("max-retry") workerID := viper.GetString("id") diff --git a/cmd/virtual-worker/worker/container_manager.go b/cmd/virtual-worker/worker/container_manager.go index 4a9b8fa10..c4ff26629 100644 --- a/cmd/virtual-worker/worker/container_manager.go +++ b/cmd/virtual-worker/worker/container_manager.go @@ -30,7 +30,7 @@ type fakeManager struct { } func (m *fakeManager) sleep() { - jitter := time.Duration(m.r.Int31n(int32(m.sleepJitter.Milliseconds()))) * time.Millisecond + jitter := time.Duration(m.r.Int63n(m.sleepJitter.Milliseconds())) * time.Millisecond time.Sleep(jitter + m.sleepMinimum) } diff --git a/internal/agent/agent_test.go b/internal/agent/agent_test.go index 83ddd6dfd..6b5568013 100644 --- a/internal/agent/agent_test.go +++ b/internal/agent/agent_test.go @@ -105,7 +105,7 @@ func TestAgent_ConcurrentWorkflows(t *testing.T) { // Started is used to indicate the runtime has received the workflow. started := make(chan struct{}) rntime := agent.ContainerRuntimeMock{ - RunFunc: func(ctx context.Context, action workflow.Action) error { + RunFunc: func(ctx context.Context, _ workflow.Action) error { started <- struct{}{} <-ctx.Done() return nil @@ -412,7 +412,7 @@ message`, trnport := transport.Noop() rntime := agent.ContainerRuntimeMock{ - RunFunc: func(ctx context.Context, action workflow.Action) error { + RunFunc: func(_ context.Context, action workflow.Action) error { if res, ok := tc.Errors[action.ID]; ok { return failure.NewReason(res.Message, res.Reason) } @@ -424,7 +424,7 @@ message`, // to check for the last expected action. lastEventReceived := make(chan struct{}) recorder := event.RecorderMock{ - RecordEventFunc: func(contextMoqParam context.Context, event event.Event) error { + RecordEventFunc: func(_ context.Context, event event.Event) error { if cmp.Equal(event, tc.Events[len(tc.Events)-1]) { lastEventReceived <- struct{}{} } diff --git a/internal/agent/transport/file_test.go b/internal/agent/transport/file_test.go index d6e2e426f..ca2b29e85 100644 --- a/internal/agent/transport/file_test.go +++ b/internal/agent/transport/file_test.go @@ -46,7 +46,7 @@ func TestFile(t *testing.T) { defer cancel() handler := &transport.WorkflowHandlerMock{ - HandleWorkflowFunc: func(contextMoqParam context.Context, workflow workflow.Workflow, recorder event.Recorder) { + HandleWorkflowFunc: func(_ context.Context, workflow workflow.Workflow, _ event.Recorder) { if !cmp.Equal(expect, workflow) { t.Fatalf("Workflow diff:\n%v", cmp.Diff(expect, workflow)) } diff --git a/internal/agent/transport/grpc_test.go b/internal/agent/transport/grpc_test.go index 80660a6cb..fb158399c 100644 --- a/internal/agent/transport/grpc_test.go +++ b/internal/agent/transport/grpc_test.go @@ -46,7 +46,7 @@ func TestGRPC(t *testing.T) { ContextFunc: context.Background, } client := &workflowproto.WorkflowServiceClientMock{ - GetWorkflowsFunc: func(ctx context.Context, in *workflowproto.GetWorkflowsRequest, opts ...grpc.CallOption) (workflowproto.WorkflowService_GetWorkflowsClient, error) { + GetWorkflowsFunc: func(_ context.Context, _ *workflowproto.GetWorkflowsRequest, _ ...grpc.CallOption) (workflowproto.WorkflowService_GetWorkflowsClient, error) { return stream, nil }, } @@ -54,7 +54,7 @@ func TestGRPC(t *testing.T) { var wg sync.WaitGroup wg.Add(1) handler := &transport.WorkflowHandlerMock{ - HandleWorkflowFunc: func(contextMoqParam context.Context, workflow workflow.Workflow, recorder event.Recorder) { + HandleWorkflowFunc: func(_ context.Context, _ workflow.Workflow, _ event.Recorder) { defer wg.Done() close(responses) }, diff --git a/internal/cli/agent.go b/internal/cli/agent.go index e01f2eb07..d1529dfff 100644 --- a/internal/cli/agent.go +++ b/internal/cli/agent.go @@ -23,7 +23,7 @@ func NewAgent() *cobra.Command { // TODO(chrisdoherty4) Handle signals cmd := cobra.Command{ Use: "tink-agent", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { zl, err := zap.NewProduction() if err != nil { return fmt.Errorf("init logger: %w", err) @@ -35,7 +35,7 @@ func NewAgent() *cobra.Command { return fmt.Errorf("create runtime: %w", err) } - conn, err := grpc.DialContext(cmd.Context(), opts.TinkServerAddr) + conn, err := grpc.NewClient(opts.TinkServerAddr) if err != nil { return fmt.Errorf("dial tink server: %w", err) } diff --git a/internal/client/client.go b/internal/client/client.go index ee6ee83c8..c143525e8 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -18,7 +18,7 @@ func NewClientConn(authority string, tlsEnabled bool, tlsInsecure bool) (*grpc.C creds = grpc.WithTransportCredentials(insecure.NewCredentials()) } - conn, err := grpc.Dial(authority, creds, grpc.WithStatsHandler(otelgrpc.NewClientHandler())) + conn, err := grpc.NewClient(authority, creds, grpc.WithStatsHandler(otelgrpc.NewClientHandler())) if err != nil { return nil, errors.Wrap(err, "dial tinkerbell server") } diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 06a7f615d..e38d093da 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -10,7 +10,6 @@ import ( "github.com/tinkerbell/tink/api/v1alpha1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" ctrl "sigs.k8s.io/controller-runtime" @@ -111,7 +110,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware) error { - // We need to set allowPXE to true before a workflow runs. // We need to set allowPXE to false after a workflow completes successfully. @@ -206,7 +204,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, } // netboot the hardware if requested - if stored.Spec.BootOpts.OneTimeNetboot { + if stored.Spec.BootOpts.OneTimeNetboot { //nolint:nestif // Will work on this complexity. // check if the hardware has a bmcRef if hardware.Spec.BMCRef == nil { return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hardware.Name) @@ -227,12 +225,10 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "previous existing one time netboot job deleted"} return reconcile.Result{Requeue: true}, nil + } else if errors.IsNotFound(err) { + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job found"} } else { - if apierrors.IsNotFound(err) { - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job found"} - } else { - return reconcile.Result{Requeue: true}, err - } + return reconcile.Result{Requeue: true}, err } } @@ -329,7 +325,7 @@ func toTemplateHardwareData(hardware v1alpha1.Hardware) templateHardwareData { return contract } -func (r *Reconciler) processRunningWorkflow(_ context.Context, stored *v1alpha1.Workflow) reconcile.Result { +func (r *Reconciler) processRunningWorkflow(_ context.Context, stored *v1alpha1.Workflow) reconcile.Result { //nolint:unparam // This is the way controller runtime works. // Check for global timeout expiration if r.nowFunc().After(stored.GetStartTime().Add(time.Duration(stored.Status.GlobalTimeout) * time.Second)) { stored.Status.State = v1alpha1.WorkflowStateTimeout diff --git a/internal/workflow/internal/reconcile_test.go b/internal/workflow/internal/reconcile_test.go index 6cccf8456..5becb75ad 100644 --- a/internal/workflow/internal/reconcile_test.go +++ b/internal/workflow/internal/reconcile_test.go @@ -10,7 +10,7 @@ import ( "github.com/rs/zerolog" tinkv1 "github.com/tinkerbell/tink/api/v1alpha2" "github.com/tinkerbell/tink/internal/ptr" - . "github.com/tinkerbell/tink/internal/workflow/internal" + . "github.com/tinkerbell/tink/internal/workflow/internal" //nolint:revive // Dot imports should not be used. Problem for another time though. corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" From 945c1ea9479a81774674d18ebb7e343415ab6b9b Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 19 Sep 2024 13:03:32 -0600 Subject: [PATCH 04/24] Clean up used code Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 20 ------------------ .../crd/bases/tinkerbell.org_workflows.yaml | 21 ------------------- 2 files changed, 41 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index a3e2919b5..22141960e 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -28,13 +28,6 @@ type WorkflowSpec struct { // A mapping of template devices to hadware mac addresses HardwareMap map[string]string `json:"hardwareMap,omitempty"` - // ToggleNetworkBoot uses the HardwareRef and changes the all network interfaces to boot from network - // before running the workflow and sets all network interfaces to not boot from the network after a successful workflow. - // ToggleNetworkBoot bool `json:"toggleNetworkBoot,omitempty"` - - // NetbootBeforeWorkflow uses the HardwareRef and the bmcRef in the hardware to boot the machine from the network before running the workflow. - // NetbootBeforeWorkflow bool `json:"netbootBeforeWorkflow,omitempty"` - // BootOpts is a set of options to be used when netbooting the hardware. BootOpts BootOpts `json:"bootOpts,omitempty"` } @@ -84,19 +77,6 @@ type Status struct { // A human-readable description of the status of this operation. // +optional Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"` - // A machine-readable description of why this operation is in the - // "Failure" status. If this value is empty there - // is no information available. A Reason clarifies an HTTP status - // code but does not override it. - // +optional - Reason metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"` - // Extended data associated with the reason. Each reason may define its - // own extended details. This field is optional and the data returned - // is not guaranteed to conform to any schema except that defined by - // the reason type. - // +optional - // +listType=atomic - // Details *metav1.StatusDetails `json:"details,omitempty" protobuf:"bytes,5,opt,name=details"` } func (s *Status) IsSuccess() bool { diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 358ce398a..9c370e1f5 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -93,13 +93,6 @@ spec: message: description: A human-readable description of the status of this operation. type: string - reason: - description: |- - A machine-readable description of why this operation is in the - "Failure" status. If this value is empty there - is no information available. A Reason clarifies an HTTP status - code but does not override it. - type: string status: description: |- Status of the operation. @@ -113,13 +106,6 @@ spec: message: description: A human-readable description of the status of this operation. type: string - reason: - description: |- - A machine-readable description of why this operation is in the - "Failure" status. If this value is empty there - is no information available. A Reason clarifies an HTTP status - code but does not override it. - type: string status: description: |- Status of the operation. @@ -199,13 +185,6 @@ spec: message: description: A human-readable description of the status of this operation. type: string - reason: - description: |- - A machine-readable description of why this operation is in the - "Failure" status. If this value is empty there - is no information available. A Reason clarifies an HTTP status - code but does not override it. - type: string status: description: |- Status of the operation. From a70acec9f836a7f028ac5ec49d3853c6a1b093c6 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 19 Sep 2024 20:35:29 -0600 Subject: [PATCH 05/24] Refactor for testing: Add tests for handleOneTimeNetboot and handleHardwareAllowPXE. Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/reconciler.go | 199 ++++++------- .../deprecated/workflow/reconciler_test.go | 267 ++++++++++++++++++ 2 files changed, 367 insertions(+), 99 deletions(-) diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index e38d093da..978874d19 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -35,6 +35,13 @@ func NewReconciler(client ctrlclient.Client) *Reconciler { } } +func (r *Reconciler) SetupWithManager(mgr manager.Manager) error { + return ctrl. + NewControllerManagedBy(mgr). + For(&v1alpha1.Workflow{}). + Complete(r) +} + // +kubebuilder:rbac:groups=tinkerbell.org,resources=hardware;hardware/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=templates;templates/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=workflows;workflows/status,verbs=get;list;watch;update;patch;delete @@ -93,7 +100,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco logger.Error(err, "error getting Hardware object for WorkflowStateSuccess processing") return reconcile.Result{}, err } - if err := r.handleHardwareAllowPXE(ctx, wflow, &hw); err != nil { + if err := handleHardwareAllowPXE(ctx, r.client, wflow, &hw); err != nil { return resp, err } default: @@ -109,7 +116,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return resp, err } -func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware) error { +func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware) error { // We need to set allowPXE to true before a workflow runs. // We need to set allowPXE to false after a workflow completes successfully. @@ -119,8 +126,9 @@ func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha for _, iface := range hardware.Spec.Interfaces { iface.Netboot.AllowPXE = ptr.Bool(true) } - if err := r.client.Update(ctx, hardware); err != nil { + if err := client.Update(ctx, hardware); err != nil { status.Status = v1alpha1.StatusFailure + status.Message = fmt.Sprintf("error setting allowPXE: %v", err) stored.Status.ToggleHardware = status return err } @@ -133,8 +141,9 @@ func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha for _, iface := range hardware.Spec.Interfaces { iface.Netboot.AllowPXE = ptr.Bool(false) } - if err := r.client.Update(ctx, hardware); err != nil { + if err := client.Update(ctx, hardware); err != nil { status.Status = v1alpha1.StatusFailure + status.Message = fmt.Sprintf("error setting allowPXE: %v", err) stored.Status.ToggleHardware = status return err } @@ -144,6 +153,89 @@ func (r *Reconciler) handleHardwareAllowPXE(ctx context.Context, stored *v1alpha return nil } +func handleOneTimeNetboot(ctx context.Context, client ctrlclient.Client, hw *v1alpha1.Hardware, stored *v1alpha1.Workflow) (reconcile.Result, error) { + if hw.Spec.BMCRef == nil { + return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hw.Name) + } + + if !stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() && !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() { + existingJob := &rufio.Job{} + jobName := fmt.Sprintf(bmcJobName, hw.Name) + if err := client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hw.Namespace}, existingJob); err == nil { + opts := []ctrlclient.DeleteOption{ + ctrlclient.GracePeriodSeconds(0), + ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), + } + if err := client.Delete(ctx, existingJob, opts...); err != nil { + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error deleting existing one time netboot job: %v", err)} + return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "existing one time netboot job deleted"} + + return reconcile.Result{Requeue: true}, nil + } else if errors.IsNotFound(err) { + stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job to be deleted"} + } else { + return reconcile.Result{Requeue: true}, err + } + } + + if !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() && stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() { + name := fmt.Sprintf(bmcJobName, hw.Name) + ns := hw.Namespace + efiBoot := func() bool { + for _, iface := range hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.UEFI { + return true + } + } + return false + }() + job := &rufio.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + Annotations: map[string]string{ + "tink-controller-auto-created": "true", + }, + Labels: map[string]string{ + "tink-controller-auto-created": "true", + }, + }, + Spec: rufio.JobSpec{ + MachineRef: rufio.MachineRef{ + Name: hw.Spec.BMCRef.Name, + Namespace: ns, + }, + Tasks: []rufio.Action{ + { + PowerAction: rufio.PowerHardOff.Ptr(), + }, + { + OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ + Devices: []rufio.BootDevice{ + rufio.PXE, + }, + EFIBoot: efiBoot, + }, + }, + { + PowerAction: rufio.PowerOn.Ptr(), + }, + }, + }, + } + if err := client.Create(ctx, job); err != nil { + stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error creating one time netboot job: %v", err)} + return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "one time netboot job created"} + stored.Status.State = v1alpha1.WorkflowStatePreparing + return reconcile.Result{Requeue: true}, nil + } + return reconcile.Result{Requeue: true}, nil +} + func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored *v1alpha1.Workflow) (reconcile.Result, error) { tpl := &v1alpha1.Template{} if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.TemplateRef, Namespace: stored.Namespace}, tpl); err != nil { @@ -195,99 +287,15 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // set hardware allowPXE if requested. if stored.Spec.BootOpts.ToggleHardware { - // We need to set allowPXE to true before a workflow runs. - // We need to set allowPXE to false after a workflow completes successfully. - - if err := r.handleHardwareAllowPXE(ctx, stored, &hardware); err != nil { + if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware); err != nil { + stored.Status.ToggleHardware = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} return reconcile.Result{}, err } } // netboot the hardware if requested - if stored.Spec.BootOpts.OneTimeNetboot { //nolint:nestif // Will work on this complexity. - // check if the hardware has a bmcRef - if hardware.Spec.BMCRef == nil { - return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hardware.Name) - } - - // check if an existing job.bmc.tinkerbell.org object exists, if so delete it. - if !stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() && !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() { - existingJob := &rufio.Job{} - jobName := fmt.Sprintf(bmcJobName, hardware.Name) - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hardware.Namespace}, existingJob); err == nil { - opts := []ctrlclient.DeleteOption{ - ctrlclient.GracePeriodSeconds(0), - ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), - } - if err := r.client.Delete(ctx, existingJob, opts...); err != nil { - return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "previous existing one time netboot job deleted"} - - return reconcile.Result{Requeue: true}, nil - } else if errors.IsNotFound(err) { - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job found"} - } else { - return reconcile.Result{Requeue: true}, err - } - } - - if !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() && stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() { - // create a job.bmc.tinkerbell.org object to netboot the hardware - name := fmt.Sprintf(bmcJobName, hardware.Name) - ns := hardware.Namespace - efiBoot := func() bool { - for _, iface := range hardware.Spec.Interfaces { - if iface.DHCP != nil && iface.DHCP.UEFI { - return true - } - } - return false - }() - job := &rufio.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: ns, - Annotations: map[string]string{ - "tink-controller-auto-created": "true", - }, - Labels: map[string]string{ - "tink-controller-auto-created": "true", - }, - }, - Spec: rufio.JobSpec{ - MachineRef: rufio.MachineRef{ - Name: hardware.Spec.BMCRef.Name, - Namespace: ns, - }, - Tasks: []rufio.Action{ - { - PowerAction: rufio.PowerHardOff.Ptr(), - }, - { - OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ - Devices: []rufio.BootDevice{ - rufio.PXE, - }, - EFIBoot: efiBoot, - }, - }, - { - PowerAction: rufio.PowerOn.Ptr(), - }, - }, - }, - } - if err := r.client.Create(ctx, job); err != nil { - return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "one time netboot job created"} - // block until the job completes. This is needed as there can be a race condition if the Hardware is already running - // a Tink Worker. - stored.Status.State = v1alpha1.WorkflowStatePreparing - return reconcile.Result{Requeue: true}, nil - } - return reconcile.Result{Requeue: true}, nil + if stored.Spec.BootOpts.OneTimeNetboot { + return handleOneTimeNetboot(ctx, r.client, &hardware, stored) } stored.Status.State = v1alpha1.WorkflowStatePending @@ -349,10 +357,3 @@ func (r *Reconciler) processRunningWorkflow(_ context.Context, stored *v1alpha1. return reconcile.Result{} } - -func (r *Reconciler) SetupWithManager(mgr manager.Manager) error { - return ctrl. - NewControllerManagedBy(mgr). - For(&v1alpha1.Workflow{}). - Complete(r) -} diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index 0b9834bc2..8bea8bf45 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -3,13 +3,16 @@ package workflow import ( "context" "errors" + "fmt" "strings" "testing" "github.com/google/go-cmp/cmp" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "github.com/tinkerbell/tink/internal/ptr" "github.com/tinkerbell/tink/internal/testtime" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -84,6 +87,270 @@ tasks: VENDOR_DATA: {{ .Hardware.VendorData }} METADATA: {{ .Hardware.Metadata.State }}` +func TestHandleHardwareAllowPXE(t *testing.T) { + tests := map[string]struct { + OriginalHardware *v1alpha1.Hardware + WantHardware *v1alpha1.Hardware + OriginalWorkflow *v1alpha1.Workflow + WantWorkflow *v1alpha1.Workflow + WantError error + }{ + "before workflow": { + OriginalHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + ResourceVersion: "1000", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + DHCP: &v1alpha1.DHCP{ + MAC: "3c:ec:ef:4c:4f:54", + }, + Netboot: &v1alpha1.Netboot{ + AllowPXE: ptr.Bool(false), + }, + }, + }, + }, + }, + WantHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + ResourceVersion: "1001", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + DHCP: &v1alpha1.DHCP{ + MAC: "3c:ec:ef:4c:4f:54", + }, + Netboot: &v1alpha1.Netboot{ + AllowPXE: ptr.Bool(true), + }, + }, + }, + }, + }, + OriginalWorkflow: &v1alpha1.Workflow{}, + WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ + ToggleHardware: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "allowPXE set to true", + }, + }}, + }, + "after workflow": { + OriginalHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + ResourceVersion: "1000", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + DHCP: &v1alpha1.DHCP{ + MAC: "3c:ec:ef:4c:4f:54", + }, + Netboot: &v1alpha1.Netboot{ + AllowPXE: ptr.Bool(true), + }, + }, + }, + }, + }, + WantHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + ResourceVersion: "1002", + }, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{ + { + DHCP: &v1alpha1.DHCP{ + MAC: "3c:ec:ef:4c:4f:54", + }, + Netboot: &v1alpha1.Netboot{ + AllowPXE: ptr.Bool(false), + }, + }, + }, + }, + }, + OriginalWorkflow: &v1alpha1.Workflow{ + Status: v1alpha1.WorkflowStatus{ + State: v1alpha1.WorkflowStateSuccess, + }, + }, + WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ + State: v1alpha1.WorkflowStateSuccess, + ToggleHardware: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "allowPXE set to false", + }, + }}, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + fakeClient := GetFakeClientBuilder().WithRuntimeObjects(tt.OriginalHardware).Build() + err := handleHardwareAllowPXE(context.Background(), fakeClient, tt.OriginalWorkflow, tt.OriginalHardware) + + if diff := cmp.Diff(tt.WantError, err, cmp.Comparer(func(a, b error) bool { + return a.Error() == b.Error() + })); diff != "" { + t.Fatalf("unexpected error diff: %s", diff) + } + + if diff := cmp.Diff(tt.WantHardware, tt.OriginalHardware); diff != "" { + t.Fatalf("unexpected hardware diff: %s", diff) + } + if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow); diff != "" { + t.Fatalf("unexpected workflow diff: %s", diff) + } + }) + } +} + +func TestHandleOneTimeNetboot(t *testing.T) { + tests := map[string]struct { + OriginalHardware *v1alpha1.Hardware + OriginalWorkflow *v1alpha1.Workflow + OriginalJob *rufio.Job + WantWorkflow *v1alpha1.Workflow + WantResult reconcile.Result + WantError error + }{ + "no bmc reference": { + OriginalHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + }, + }, + WantResult: reconcile.Result{}, + WantError: fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", "machine1"), + }, + "delete existing bmc job": { + OriginalHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + BMCRef: &v1.TypedLocalObjectReference{ + Name: "bmc1", + Kind: "machine.bmc.tinkerbell.org", + }, + }, + }, + OriginalWorkflow: &v1alpha1.Workflow{ + Status: v1alpha1.WorkflowStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + DeletionStatus: &v1alpha1.Status{}, + CreationStatus: &v1alpha1.Status{}, + }, + }, + }, + OriginalJob: &rufio.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf(bmcJobName, "machine1"), + Namespace: "default", + }, + Spec: rufio.JobSpec{}, + Status: rufio.JobStatus{}, + }, + WantWorkflow: &v1alpha1.Workflow{ + Status: v1alpha1.WorkflowStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + DeletionStatus: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "existing one time netboot job deleted", + }, + CreationStatus: &v1alpha1.Status{}, + }, + }, + }, + WantResult: reconcile.Result{Requeue: true}, + }, + "create bmc job": { + OriginalHardware: &v1alpha1.Hardware{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine2", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + BMCRef: &v1.TypedLocalObjectReference{ + Name: "bmc2", + Kind: "machine.bmc.tinkerbell.org", + }, + }, + }, + OriginalWorkflow: &v1alpha1.Workflow{ + Status: v1alpha1.WorkflowStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + DeletionStatus: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "no existing one time netboot job to be deleted", + }, + CreationStatus: &v1alpha1.Status{}, + }, + }, + }, + WantWorkflow: &v1alpha1.Workflow{ + Status: v1alpha1.WorkflowStatus{ + State: v1alpha1.WorkflowStatePreparing, + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + DeletionStatus: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "no existing one time netboot job to be deleted", + }, + CreationStatus: &v1alpha1.Status{ + Status: v1alpha1.StatusSuccess, + Message: "one time netboot job created", + }, + }, + }, + }, + WantResult: reconcile.Result{Requeue: true}, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + client := GetFakeClientBuilder().Build() + if tt.OriginalHardware.Spec.BMCRef != nil { + runtimescheme := runtime.NewScheme() + rufio.AddToScheme(runtimescheme) + v1alpha1.AddToScheme(runtimescheme) + clientBulider := GetFakeClientBuilder().WithScheme(runtimescheme) + if tt.OriginalJob != nil { + clientBulider.WithRuntimeObjects(tt.OriginalJob) + } + client = clientBulider.Build() + } + r, err := handleOneTimeNetboot(context.Background(), client, tt.OriginalHardware, tt.OriginalWorkflow) + + if diff := cmp.Diff(tt.WantError, err, cmp.Comparer(func(a, b error) bool { + return a.Error() == b.Error() + })); diff != "" { + t.Fatalf("unexpected error diff: %s", diff) + } + + if diff := cmp.Diff(tt.WantResult, r); diff != "" { + t.Fatalf("unexpected result diff: %s", diff) + } + if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow); diff != "" { + t.Fatalf("unexpected workflow diff: %s", diff) + } + }) + } +} + func TestReconcile(t *testing.T) { cases := []struct { name string From d1b21d86c9b85ad1bccc59aaa20ebc1bd89668f6 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 19 Sep 2024 22:16:08 -0600 Subject: [PATCH 06/24] Change toggle field name: Hopefully improved the understandability of the field some. Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 8 ++++---- api/v1alpha1/zz_generated.deepcopy.go | 4 ++-- config/crd/bases/tinkerbell.org_workflows.yaml | 8 ++++---- internal/deprecated/workflow/reconciler.go | 14 +++++++------- internal/deprecated/workflow/reconciler_test.go | 4 ++-- internal/server/kubernetes_api_workflow.go | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 22141960e..50c408bca 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -33,10 +33,10 @@ type WorkflowSpec struct { } type BootOpts struct { - // ToggleHardware indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. + // ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. // This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. // A HardwareRef must be provided. - ToggleHardware bool `json:"toggleHardware,omitempty"` + ToggleAllowNetboot bool `json:"toggleAllowNetboot,omitempty"` // OneTimeNetboot indicates whether the controller should create a job.bmc.tinkerbell.org object for getting the associated hardware // into a netbooting state. // A HardwareRef that contains a spec.BmcRef must be provided. @@ -54,9 +54,9 @@ type WorkflowStatus struct { // Tasks are the tasks to be completed Tasks []Task `json:"tasks,omitempty"` - // ToggleHardware indicates whether the controller has successfully toggled the network boot setting + // ToggleAllowNetboot indicates whether the controller has successfully toggled the network boot setting // in the associated hardware. - ToggleHardware *Status `json:"toggleHardware,omitempty"` + ToggleAllowNetboot *Status `json:"toggleAllowNetboot,omitempty"` // OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. OneTimeNetboot OneTimeNetbootStatus `json:"oneTimeNetboot,omitempty"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index e2e00303c..6c23fd25b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -976,8 +976,8 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.ToggleHardware != nil { - in, out := &in.ToggleHardware, &out.ToggleHardware + if in.ToggleAllowNetboot != nil { + in, out := &in.ToggleAllowNetboot, &out.ToggleAllowNetboot *out = new(Status) **out = **in } diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 9c370e1f5..5f13d3a96 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -58,9 +58,9 @@ spec: into a netbooting state. A HardwareRef that contains a spec.BmcRef must be provided. type: boolean - toggleHardware: + toggleAllowNetboot: description: |- - ToggleHardware indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. + ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. A HardwareRef must be provided. type: boolean @@ -177,9 +177,9 @@ spec: - worker type: object type: array - toggleHardware: + toggleAllowNetboot: description: |- - ToggleHardware indicates whether the controller has successfully toggled the network boot setting + ToggleAllowNetboot indicates whether the controller has successfully toggled the network boot setting in the associated hardware. properties: message: diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 978874d19..2a8d9d791 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -121,7 +121,7 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store // We need to set allowPXE to false after a workflow completes successfully. // before workflow case - if stored.Status.ToggleHardware == nil || (stored.Status.ToggleHardware != nil && stored.Status.ToggleHardware.Status == "" && stored.Status.State == "" || stored.Status.State == v1alpha1.WorkflowStatePending) { + if stored.Status.ToggleAllowNetboot == nil || (stored.Status.ToggleAllowNetboot != nil && stored.Status.ToggleAllowNetboot.Status == "" && stored.Status.State == "" || stored.Status.State == v1alpha1.WorkflowStatePending) { status := &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "allowPXE set to true"} for _, iface := range hardware.Spec.Interfaces { iface.Netboot.AllowPXE = ptr.Bool(true) @@ -129,10 +129,10 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store if err := client.Update(ctx, hardware); err != nil { status.Status = v1alpha1.StatusFailure status.Message = fmt.Sprintf("error setting allowPXE: %v", err) - stored.Status.ToggleHardware = status + stored.Status.ToggleAllowNetboot = status return err } - stored.Status.ToggleHardware = status + stored.Status.ToggleAllowNetboot = status } // after workflow case @@ -144,10 +144,10 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store if err := client.Update(ctx, hardware); err != nil { status.Status = v1alpha1.StatusFailure status.Message = fmt.Sprintf("error setting allowPXE: %v", err) - stored.Status.ToggleHardware = status + stored.Status.ToggleAllowNetboot = status return err } - stored.Status.ToggleHardware = status + stored.Status.ToggleAllowNetboot = status } return nil @@ -286,9 +286,9 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored.Status = *YAMLToStatus(tinkWf) // set hardware allowPXE if requested. - if stored.Spec.BootOpts.ToggleHardware { + if stored.Spec.BootOpts.ToggleAllowNetboot { if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware); err != nil { - stored.Status.ToggleHardware = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} + stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} return reconcile.Result{}, err } } diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index 8bea8bf45..dbe57f057 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -136,7 +136,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { }, OriginalWorkflow: &v1alpha1.Workflow{}, WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ - ToggleHardware: &v1alpha1.Status{ + ToggleAllowNetboot: &v1alpha1.Status{ Status: v1alpha1.StatusSuccess, Message: "allowPXE set to true", }, @@ -188,7 +188,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { }, WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ State: v1alpha1.WorkflowStateSuccess, - ToggleHardware: &v1alpha1.Status{ + ToggleAllowNetboot: &v1alpha1.Status{ Status: v1alpha1.StatusSuccess, Message: "allowPXE set to false", }, diff --git a/internal/server/kubernetes_api_workflow.go b/internal/server/kubernetes_api_workflow.go index f81538591..a2bf511a7 100644 --- a/internal/server/kubernetes_api_workflow.go +++ b/internal/server/kubernetes_api_workflow.go @@ -77,7 +77,7 @@ func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextR return err } for _, wf := range wflows { - if wf.Spec.BootOpts.ToggleHardware && wf.Status.ToggleHardware != nil && wf.Status.ToggleHardware.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { + if wf.Spec.BootOpts.ToggleAllowNetboot && wf.Status.ToggleAllowNetboot != nil && wf.Status.ToggleAllowNetboot.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { continue } if wf.Spec.BootOpts.OneTimeNetboot && wf.Status.State == v1alpha1.WorkflowStatePreparing { From 86387cca627a51dcd5c6152f2ce9be7b195dc7f3 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 09:46:26 -0600 Subject: [PATCH 07/24] Fix controller-gen operations: Update rbac. Signed-off-by: Jacob Weinstock --- Makefile | 10 +++++----- config/manager-rbac/role.yaml | 20 ++++++++------------ config/server-rbac/role.yaml | 7 ------- internal/deprecated/workflow/reconciler.go | 3 ++- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index acd228890..680331162 100644 --- a/Makefile +++ b/Makefile @@ -120,12 +120,12 @@ generate-crds: $(CONTROLLER_GEN) $(YAMLFMT) $(YAMLFMT) ./config/crd/bases/* ./config/webhook/* .PHONY: generate-rbac -generate-rbac: $(CONTROLLER_GEN) $(YAMLFMT) +generate-rbac: generate-controller-rbac generate-server-rbac $(CONTROLLER_GEN) $(YAMLFMT) .PHONY: generate-controller-rbac -generate-manager-rbac: +generate-controller-rbac: $(CONTROLLER_GEN) \ - paths=./internal/workflow/... \ + paths=./internal/deprecated/workflow/... \ output:rbac:dir=./config/manager-rbac/ \ rbac:roleName=manager-role $(YAMLFMT) ./config/rbac/* @@ -151,14 +151,14 @@ out/release/default/kustomization.yaml: config/default/kustomization.yaml mkdir -p out/ cp -a config/ out/release/ -out/release/tink.yaml: generate-manifests out/release/default/kustomization.yaml $(KUSTOMIZE) +out/release/tink.yaml: generate-manifests out/release/default/kustomization.yaml $(KUSTOMIZE) $(YAMLFMT) ( cd out/release/default && \ $(KUSTOMIZE) edit set image server=$(TINK_SERVER_IMAGE):$(TINK_CONTROLLER_TAG) controller=$(TINK_CONTROLLER_IMAGE):$(TINK_CONTROLLER_TAG) && \ $(KUSTOMIZE) edit set namespace $(NAMESPACE) \ ) $(KUSTOMIZE) build out/release/default -o $@ - prettier --write $@ + $(YAMLFMT) $@ .PHONY: release-manifests release-manifests: ## Builds the manifests to publish with a release. diff --git a/config/manager-rbac/role.yaml b/config/manager-rbac/role.yaml index fb55a1945..3f46bb22e 100644 --- a/config/manager-rbac/role.yaml +++ b/config/manager-rbac/role.yaml @@ -5,19 +5,21 @@ metadata: name: manager-role rules: - apiGroups: - - tinkerbell.org + - bmc.tinkerbell.org resources: - - hardware - - hardware/status + - job + - job/status verbs: + - create + - delete - get - list - - patch - - update - watch - apiGroups: - tinkerbell.org resources: + - hardware + - hardware/status - templates - templates/status verbs: @@ -26,19 +28,13 @@ rules: - patch - update - watch -- apiGroups: - - tinkerbell.org - resources: - - workflows - - workflows/finalizers - verbs: - - update - apiGroups: - tinkerbell.org resources: - workflows - workflows/status verbs: + - delete - get - list - patch diff --git a/config/server-rbac/role.yaml b/config/server-rbac/role.yaml index 1a228bd4c..8e65cfe3b 100644 --- a/config/server-rbac/role.yaml +++ b/config/server-rbac/role.yaml @@ -8,13 +8,6 @@ rules: resources: - hardware - hardware/status - verbs: - - get - - list - - watch - - apiGroups: - - tinkerbell.org - resources: - templates - templates/status verbs: diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 2a8d9d791..ce00b45b7 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -45,8 +45,9 @@ func (r *Reconciler) SetupWithManager(mgr manager.Manager) error { // +kubebuilder:rbac:groups=tinkerbell.org,resources=hardware;hardware/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=templates;templates/status,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=tinkerbell.org,resources=workflows;workflows/status,verbs=get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=bmc.tinkerbell.org,resources=job;job/status,verbs=get;delete;create;watch +// +kubebuilder:rbac:groups=bmc.tinkerbell.org,resources=job;job/status,verbs=get;list;watch;delete;create +// Reconcile handles Workflow objects. This includes Template rendering, optional Hardware allowPXE toggling, and optional Hardware one-time netbooting. func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { logger := ctrl.LoggerFrom(ctx) logger.Info("Reconciling") From 9f725d64ea1f2a306c2d2686283b3189e08fbbf3 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 09:55:19 -0600 Subject: [PATCH 08/24] Update dependencies: Upgrades and removed unused dep. Signed-off-by: Jacob Weinstock --- go.mod | 37 +++++++++++++----------------- go.sum | 71 ++++++++++++++++++++++++++++++---------------------------- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/go.mod b/go.mod index a688defc3..890797abe 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/avast/retry-go v3.0.0+incompatible github.com/distribution/reference v0.6.0 - github.com/docker/docker v27.2.0+incompatible + github.com/docker/docker v27.2.1+incompatible github.com/equinix-labs/otel-init-go v0.0.9 github.com/go-logr/logr v1.4.2 github.com/go-logr/zapr v1.3.0 @@ -20,14 +20,14 @@ require ( github.com/onsi/gomega v1.34.2 github.com/opencontainers/image-spec v1.1.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.3 + github.com/prometheus/client_golang v1.20.4 github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/tinkerbell/rufio v0.3.3 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 google.golang.org/grpc v1.66.2 @@ -45,13 +45,13 @@ require ( dario.cat/mergo v1.0.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.4.14 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect @@ -69,7 +69,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -85,7 +85,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect @@ -105,28 +105,26 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect + go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect - golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.25.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -139,8 +137,3 @@ require ( sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) - -// When updating buf we receive ambiguous import errors stemming from the cloud.google.com/go -// package. This is a known issue with buf and is fixed in the latest version of buf. -// This fix was found in https://github.com/aws-observability/aws-otel-collector/issues/926#issuecomment-1263065587 -replace cloud.google.com/go => cloud.google.com/go v0.107.0 diff --git a/go.sum b/go.sum index ffb98c542..43633186d 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+ github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -28,10 +28,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= -github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= @@ -88,8 +88,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= @@ -106,6 +106,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -130,8 +131,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -151,13 +152,14 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= -github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= @@ -176,6 +178,7 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -191,9 +194,11 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -208,24 +213,24 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -243,8 +248,6 @@ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDT golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -256,10 +259,10 @@ golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -286,10 +289,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a h1:KyUe15n7B1YCu+kMmPtlXxgkLQbp+Dw0tCRZf9Sd+CE= -google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a h1:EKiZZXueP9/T68B8Nl0GAx9cjbQnCId0yP3qPMgaaHs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= From 86d057b94720cb7b450f3a2de1fdea23a9bd0883 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 09:58:18 -0600 Subject: [PATCH 09/24] Bump all Alpine images to 3.20.3: Signed-off-by: Jacob Weinstock --- cmd/tink-agent/Dockerfile | 2 +- cmd/tink-controller-v1alpha2/Dockerfile | 2 +- cmd/tink-controller/Dockerfile | 2 +- cmd/tink-server/Dockerfile | 2 +- cmd/tink-worker/Dockerfile | 2 +- cmd/virtual-worker/Dockerfile | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/tink-agent/Dockerfile b/cmd/tink-agent/Dockerfile index f8db129f5..def174da5 100644 --- a/cmd/tink-agent/Dockerfile +++ b/cmd/tink-agent/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH diff --git a/cmd/tink-controller-v1alpha2/Dockerfile b/cmd/tink-controller-v1alpha2/Dockerfile index 6a4b4cf6b..ad4d4a32a 100644 --- a/cmd/tink-controller-v1alpha2/Dockerfile +++ b/cmd/tink-controller-v1alpha2/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH diff --git a/cmd/tink-controller/Dockerfile b/cmd/tink-controller/Dockerfile index 4e9cd9ad6..97436cbb6 100644 --- a/cmd/tink-controller/Dockerfile +++ b/cmd/tink-controller/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH diff --git a/cmd/tink-server/Dockerfile b/cmd/tink-server/Dockerfile index a3ecba517..2d2bb2370 100644 --- a/cmd/tink-server/Dockerfile +++ b/cmd/tink-server/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH diff --git a/cmd/tink-worker/Dockerfile b/cmd/tink-worker/Dockerfile index dfc5c99d4..cd90e0525 100644 --- a/cmd/tink-worker/Dockerfile +++ b/cmd/tink-worker/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH diff --git a/cmd/virtual-worker/Dockerfile b/cmd/virtual-worker/Dockerfile index 36d0085ef..d9e102f2f 100644 --- a/cmd/virtual-worker/Dockerfile +++ b/cmd/virtual-worker/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15 +FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH From 6bea9cc3778032c80ec680271485db15cff9fc46 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 10:03:33 -0600 Subject: [PATCH 10/24] Fix linting warnings: Pin apk packages in all Dockerfiles. Signed-off-by: Jacob Weinstock --- .golangci.yml | 6 +----- cmd/tink-agent/Dockerfile | 2 +- cmd/tink-controller-v1alpha2/Dockerfile | 2 +- cmd/tink-controller/Dockerfile | 2 +- cmd/tink-server/Dockerfile | 2 +- cmd/tink-worker/Dockerfile | 2 +- cmd/virtual-worker/Dockerfile | 2 +- 7 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 3bda4241f..6702f825d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -84,10 +84,6 @@ linters-settings: - name: struct-tag arguments: - "json,inline" - staticcheck: - go: "1.18" - unused: - go: "1.18" output: sort-results: true linters: @@ -103,7 +99,7 @@ linters: - errname - errorlint - exhaustive - - exportloopref + - copyloopvar - forcetypeassert - gocognit - goconst diff --git a/cmd/tink-agent/Dockerfile b/cmd/tink-agent/Dockerfile index def174da5..a1c43e8eb 100644 --- a/cmd/tink-agent/Dockerfile +++ b/cmd/tink-agent/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/tink-agent-${TARGETOS}-${TARGETARCH} /usr/bin/tink-agent diff --git a/cmd/tink-controller-v1alpha2/Dockerfile b/cmd/tink-controller-v1alpha2/Dockerfile index ad4d4a32a..7b7f0a742 100644 --- a/cmd/tink-controller-v1alpha2/Dockerfile +++ b/cmd/tink-controller-v1alpha2/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/tink-controller-v1alpha2-${TARGETOS}-${TARGETARCH} /usr/bin/tink-controller diff --git a/cmd/tink-controller/Dockerfile b/cmd/tink-controller/Dockerfile index 97436cbb6..8b725a6bb 100644 --- a/cmd/tink-controller/Dockerfile +++ b/cmd/tink-controller/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/tink-controller-${TARGETOS}-${TARGETARCH} /usr/bin/tink-controller diff --git a/cmd/tink-server/Dockerfile b/cmd/tink-server/Dockerfile index 2d2bb2370..2a48a552f 100644 --- a/cmd/tink-server/Dockerfile +++ b/cmd/tink-server/Dockerfile @@ -5,7 +5,7 @@ ARG TARGETARCH EXPOSE 42113 42114 -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/tink-server-${TARGETOS}-${TARGETARCH} /usr/bin/tink-server diff --git a/cmd/tink-worker/Dockerfile b/cmd/tink-worker/Dockerfile index cd90e0525..c1ae155ee 100644 --- a/cmd/tink-worker/Dockerfile +++ b/cmd/tink-worker/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/tink-worker-${TARGETOS}-${TARGETARCH} /usr/bin/tink-worker diff --git a/cmd/virtual-worker/Dockerfile b/cmd/virtual-worker/Dockerfile index d9e102f2f..ca914357c 100644 --- a/cmd/virtual-worker/Dockerfile +++ b/cmd/virtual-worker/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.20.3 ARG TARGETOS ARG TARGETARCH -RUN apk add --no-cache --update --upgrade ca-certificates +RUN apk add --no-cache --update --upgrade ca-certificates=20240705-r0 COPY bin/virtual-worker-${TARGETOS}-${TARGETARCH} /usr/bin/virtual-worker From b55317e853bded62534372872f8b2a71f7ae7e77 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 15:56:12 -0600 Subject: [PATCH 11/24] Simplify allowPXE handling: Push the boolean info to the caller so that handleHardwareAllowPXE can be simpler. Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/reconciler.go | 65 ++++++++----------- .../deprecated/workflow/reconciler_test.go | 6 +- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index ce00b45b7..62137a40e 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -94,15 +94,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{Requeue: true}, nil } case v1alpha1.WorkflowStateSuccess: - // handle updating hardware allowPXE to false - var hw v1alpha1.Hardware - err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: wflow.Spec.HardwareRef, Namespace: wflow.Namespace}, &hw) - if err != nil && !errors.IsNotFound(err) { - logger.Error(err, "error getting Hardware object for WorkflowStateSuccess processing") - return reconcile.Result{}, err - } - if err := handleHardwareAllowPXE(ctx, r.client, wflow, &hw); err != nil { - return resp, err + if wflow.Spec.BootOpts.ToggleAllowNetboot { + // handle updating hardware allowPXE to false + if err := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); err != nil { + return reconcile.Result{}, err + } } default: return resp, nil @@ -117,40 +113,32 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return resp, err } -func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware) error { - // We need to set allowPXE to true before a workflow runs. - // We need to set allowPXE to false after a workflow completes successfully. +// handleHardwareAllowPXE sets the allowPXE field on the hardware interfaces to true before a workflow runs and false after a workflow completes successfully. +// If hardware is nil then it will be retrieved using the client. +func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware, allowPXE bool) error { + if stored == nil { + return fmt.Errorf("cannot handle hardware allowPXE without a workflow") + } - // before workflow case - if stored.Status.ToggleAllowNetboot == nil || (stored.Status.ToggleAllowNetboot != nil && stored.Status.ToggleAllowNetboot.Status == "" && stored.Status.State == "" || stored.Status.State == v1alpha1.WorkflowStatePending) { - status := &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "allowPXE set to true"} - for _, iface := range hardware.Spec.Interfaces { - iface.Netboot.AllowPXE = ptr.Bool(true) - } - if err := client.Update(ctx, hardware); err != nil { - status.Status = v1alpha1.StatusFailure - status.Message = fmt.Sprintf("error setting allowPXE: %v", err) - stored.Status.ToggleAllowNetboot = status - return err + if hardware == nil { + hardware = &v1alpha1.Hardware{} + if err := client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, hardware); err != nil { + stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error getting hardware: %v", err)} + return fmt.Errorf("hardware not found: name=%v; namespace=%v, error: %w", stored.Spec.HardwareRef, stored.Namespace, err) } - stored.Status.ToggleAllowNetboot = status } - // after workflow case - if stored.Status.State == v1alpha1.WorkflowStateSuccess { - status := &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "allowPXE set to false"} - for _, iface := range hardware.Spec.Interfaces { - iface.Netboot.AllowPXE = ptr.Bool(false) - } - if err := client.Update(ctx, hardware); err != nil { - status.Status = v1alpha1.StatusFailure - status.Message = fmt.Sprintf("error setting allowPXE: %v", err) - stored.Status.ToggleAllowNetboot = status - return err - } - stored.Status.ToggleAllowNetboot = status + for _, iface := range hardware.Spec.Interfaces { + iface.Netboot.AllowPXE = ptr.Bool(allowPXE) } + if err := client.Update(ctx, hardware); err != nil { + stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} + return err + } + + stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: fmt.Sprintf("allowPXE set to %v", allowPXE)} + return nil } @@ -288,8 +276,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // set hardware allowPXE if requested. if stored.Spec.BootOpts.ToggleAllowNetboot { - if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware); err != nil { - stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} + if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { return reconcile.Result{}, err } } diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index dbe57f057..573662171 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -94,6 +94,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { OriginalWorkflow *v1alpha1.Workflow WantWorkflow *v1alpha1.Workflow WantError error + AllowPXE bool }{ "before workflow": { OriginalHardware: &v1alpha1.Hardware{ @@ -141,6 +142,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { Message: "allowPXE set to true", }, }}, + AllowPXE: true, }, "after workflow": { OriginalHardware: &v1alpha1.Hardware{ @@ -166,7 +168,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "machine1", Namespace: "default", - ResourceVersion: "1002", + ResourceVersion: "1001", }, Spec: v1alpha1.HardwareSpec{ Interfaces: []v1alpha1.Interface{ @@ -199,7 +201,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { fakeClient := GetFakeClientBuilder().WithRuntimeObjects(tt.OriginalHardware).Build() - err := handleHardwareAllowPXE(context.Background(), fakeClient, tt.OriginalWorkflow, tt.OriginalHardware) + err := handleHardwareAllowPXE(context.Background(), fakeClient, tt.OriginalWorkflow, tt.OriginalHardware, tt.AllowPXE) if diff := cmp.Diff(tt.WantError, err, cmp.Comparer(func(a, b error) bool { return a.Error() == b.Error() From e199e5085965c8d8eb5e3275c4ef975276850ffb Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 20 Sep 2024 22:16:35 -0600 Subject: [PATCH 12/24] Use status conditions instead of status fields: This allows for adding/modifying conditions without changing the Workflow spec. Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 106 ++++++++++- api/v1alpha1/zz_generated.deepcopy.go | 38 +++- .../crd/bases/tinkerbell.org_workflows.yaml | 104 +++++----- internal/deprecated/workflow/reconciler.go | 180 +++++++++++++----- internal/server/kubernetes_api_workflow.go | 11 +- 5 files changed, 332 insertions(+), 107 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 50c408bca..333821f4d 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -54,19 +54,115 @@ type WorkflowStatus struct { // Tasks are the tasks to be completed Tasks []Task `json:"tasks,omitempty"` - // ToggleAllowNetboot indicates whether the controller has successfully toggled the network boot setting - // in the associated hardware. - ToggleAllowNetboot *Status `json:"toggleAllowNetboot,omitempty"` + // The latest available observations of an object's current state. When a Job + // fails, one of the conditions will have type "Failed" and status true. When + // a Job is suspended, one of the conditions will have type "Suspended" and + // status true; when the Job is resumed, the status of this condition will + // become false. When a Job is completed, one of the conditions will have + // type "Complete" and status true. + // + // A job is considered finished when it is in a terminal condition, either + // "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions. + // Additionally, it cannot be in the "Complete" and "FailureTarget" conditions. + // The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled. + // + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=atomic + Conditions []WorkflowCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` + + // Represents time when the job controller started processing a job. When a + // Job is created in the suspended state, this field is not set until the + // first time it is resumed. This field is reset every time a Job is resumed + // from suspension. It is represented in RFC3339 form and is in UTC. + // + // Once set, the field can only be removed when the job is suspended. + // The field cannot be modified while the job is unsuspended or finished. + // + // +optional + TimeStarted *metav1.Time `json:"timeStarted,omitempty" protobuf:"bytes,2,opt,name=startTime"` + + // Represents time when the job was completed. It is not guaranteed to + // be set in happens-before order across separate operations. + // It is represented in RFC3339 form and is in UTC. + // The completion time is set when the job finishes successfully, and only then. + // The value cannot be updated or removed. The value indicates the same or + // later point in time as the startTime field. + // +optional + TimeCompleted *metav1.Time `json:"timeCompleted,omitempty" protobuf:"bytes,3,opt,name=completionTime"` +} - // OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. - OneTimeNetboot OneTimeNetbootStatus `json:"oneTimeNetboot,omitempty"` +// JobCondition describes current state of a job. +type WorkflowCondition struct { + // Type of job condition, Complete or Failed. + Type WorkflowConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=JobConditionType"` + // Status of the condition, one of True, False, Unknown. + Status metav1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"` + // (brief) reason for the condition's last transition. + // +optional + Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"` + // Human readable message indicating details about last transition. + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"` + // Time when the condition was created. + // +optional + Time *metav1.Time `json:"Time,omitempty" protobuf:"bytes,7,opt,name=lastTransitionTime"` } +type WorkflowConditionType string + +const ( + NetbootJobFailed WorkflowConditionType = "Netboot Job Failed" + NetbootJobComplete WorkflowConditionType = "Netboot Job Complete" + NetbootJobRunning WorkflowConditionType = "Netboot Job Running" + + NetbootJobSetupFailed WorkflowConditionType = "Netboot Job Setup Failed" + NetbootJobSetupComplete WorkflowConditionType = "Netboot Job Setup Complete" + NetbootJobSetupRunning WorkflowConditionType = "Netboot Job Setup Running" + + ToggleAllowNetbootFailed WorkflowConditionType = "Toggle Allow Netboot Failed" + ToggleAllowNetbootComplete WorkflowConditionType = "Toggle Allow Netboot Complete" + ToggleAllowNetbootRunning WorkflowConditionType = "Toggle Allow Netboot Running" +) + type OneTimeNetbootStatus struct { CreationStatus *Status `json:"creationStatus,omitempty"` DeletionStatus *Status `json:"deletionStatus,omitempty"` } +// HasCondition checks if the cType condition is present with status cStatus on a bmj. +func (w WorkflowStatus) HasCondition(cType WorkflowConditionType, cStatus metav1.ConditionStatus) bool { + for _, c := range w.Conditions { + if c.Type == cType { + return c.Status == cStatus + } + } + + return false +} + +// SetCondition updates an existing condition, if it exists, or appends a new one. +// If ignoreFound is true, it will update the condition if it already exists. +func (w *WorkflowStatus) SetCondition(wc WorkflowCondition, ignoreFound bool) { + index := -1 + for i, c := range w.Conditions { + if c.Type == wc.Type { + index = i + break + } + } + if index != -1 { + if !ignoreFound { + w.Conditions[index] = wc + } + return + } + + w.Conditions = append(w.Conditions, wc) +} + // Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". type Status struct { // Status of the operation. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6c23fd25b..ddfd4a26e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -911,6 +911,25 @@ func (in *Workflow) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkflowCondition) DeepCopyInto(out *WorkflowCondition) { + *out = *in + if in.Time != nil { + in, out := &in.Time, &out.Time + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowCondition. +func (in *WorkflowCondition) DeepCopy() *WorkflowCondition { + if in == nil { + return nil + } + out := new(WorkflowCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkflowList) DeepCopyInto(out *WorkflowList) { *out = *in @@ -976,12 +995,21 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.ToggleAllowNetboot != nil { - in, out := &in.ToggleAllowNetboot, &out.ToggleAllowNetboot - *out = new(Status) - **out = **in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]WorkflowCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TimeStarted != nil { + in, out := &in.TimeStarted, &out.TimeStarted + *out = (*in).DeepCopy() + } + if in.TimeCompleted != nil { + in, out := &in.TimeCompleted, &out.TimeCompleted + *out = (*in).DeepCopy() } - in.OneTimeNetboot.DeepCopyInto(&out.OneTimeNetboot) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus. diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 5f13d3a96..a051709da 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -80,40 +80,50 @@ spec: status: description: WorkflowStatus defines the observed state of Workflow. properties: + conditions: + description: |- + The latest available observations of an object's current state. When a Job + fails, one of the conditions will have type "Failed" and status true. When + a Job is suspended, one of the conditions will have type "Suspended" and + status true; when the Job is resumed, the status of this condition will + become false. When a Job is completed, one of the conditions will have + type "Complete" and status true. + + A job is considered finished when it is in a terminal condition, either + "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions. + Additionally, it cannot be in the "Complete" and "FailureTarget" conditions. + The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled. + + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + items: + description: JobCondition describes current state of a job. + properties: + Time: + description: Time when the condition was created. + format: date-time + type: string + message: + description: Human readable message indicating details about last transition. + type: string + reason: + description: (brief) reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of job condition, Complete or Failed. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic globalTimeout: description: GlobalTimeout represents the max execution time format: int64 type: integer - oneTimeNetboot: - description: OneTimeNetboot indicates whether the controller has successfully netbooted the associated hardware. - properties: - creationStatus: - description: Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". - properties: - message: - description: A human-readable description of the status of this operation. - type: string - status: - description: |- - Status of the operation. - One of: "Success" or "Failure". - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: string - type: object - deletionStatus: - description: Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". - properties: - message: - description: A human-readable description of the status of this operation. - type: string - status: - description: |- - Status of the operation. - One of: "Success" or "Failure". - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: string - type: object - type: object state: description: State is the state of the workflow in Tinkerbell. type: string @@ -177,21 +187,27 @@ spec: - worker type: object type: array - toggleAllowNetboot: + timeCompleted: description: |- - ToggleAllowNetboot indicates whether the controller has successfully toggled the network boot setting - in the associated hardware. - properties: - message: - description: A human-readable description of the status of this operation. - type: string - status: - description: |- - Status of the operation. - One of: "Success" or "Failure". - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: string - type: object + Represents time when the job was completed. It is not guaranteed to + be set in happens-before order across separate operations. + It is represented in RFC3339 form and is in UTC. + The completion time is set when the job finishes successfully, and only then. + The value cannot be updated or removed. The value indicates the same or + later point in time as the startTime field. + format: date-time + type: string + timeStarted: + description: |- + Represents time when the job controller started processing a job. When a + Job is created in the suspended state, this field is not set until the + first time it is resumed. This field is reset every time a Job is resumed + from suspension. It is represented in RFC3339 form and is in UTC. + + Once set, the field can only be removed when the job is suspended. + The field cannot be modified while the job is unsuspended or finished. + format: date-time + type: string type: object type: object served: true diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 62137a40e..e0666dc6a 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -71,35 +71,70 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco switch wflow.Status.State { case "": resp, err = r.processNewWorkflow(ctx, logger, wflow) + if wflow.Status.TimeStarted == nil { + wflow.Status.TimeStarted = &metav1.Time{Time: metav1.Now().UTC()} + } case v1alpha1.WorkflowStateRunning: resp = r.processRunningWorkflow(ctx, wflow) case v1alpha1.WorkflowStatePreparing: - if wflow.Status.OneTimeNetboot.CreationStatus == nil { - return reconcile.Result{Requeue: true}, nil - } - if !wflow.Status.OneTimeNetboot.CreationStatus.IsSuccess() { - return reconcile.Result{Requeue: true}, nil - } - existingJob := &rufio.Job{} - jobName := fmt.Sprintf(bmcJobName, wflow.Spec.HardwareRef) - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: wflow.Namespace}, existingJob); err != nil { - return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) - } - if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { - return reconcile.Result{}, fmt.Errorf("one time netboot job failed") - } - if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { - wflow.Status.State = v1alpha1.WorkflowStatePending - } else { - return reconcile.Result{Requeue: true}, nil + if isNetbootJobSetupFinished(wflow.Status.Conditions) { + println("81") + existingJob := &rufio.Job{} + jobName := fmt.Sprintf(bmcJobName, wflow.Spec.HardwareRef) + if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: wflow.Namespace}, existingJob); err != nil { + return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) + } + if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { + println("88") + wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: "one time netboot job failed", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) + return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + } + if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { + println("94") + wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobComplete, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "one time netboot job completed", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) + wflow.Status.State = v1alpha1.WorkflowStatePending + } else { + println("99") + wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobRunning, + Status: metav1.ConditionTrue, + Reason: "Running", + Message: "netboot job running", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, true) + resp.Requeue = true + } } case v1alpha1.WorkflowStateSuccess: - if wflow.Spec.BootOpts.ToggleAllowNetboot { + if wflow.Spec.BootOpts.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootComplete, metav1.ConditionTrue) { // handle updating hardware allowPXE to false + wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootComplete, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "setting allowPXE to false", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) if err := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); err != nil { + println("102") return reconcile.Result{}, err } } + if wflow.Status.TimeCompleted == nil { + wflow.Status.TimeCompleted = &metav1.Time{Time: metav1.Now().UTC()} + } default: return resp, nil } @@ -123,7 +158,13 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store if hardware == nil { hardware = &v1alpha1.Hardware{} if err := client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, hardware); err != nil { - stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error getting hardware: %v", err)} + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error getting hardware: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) return fmt.Errorf("hardware not found: name=%v; namespace=%v, error: %w", stored.Spec.HardwareRef, stored.Namespace, err) } } @@ -133,43 +174,64 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store } if err := client.Update(ctx, hardware); err != nil { - stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error setting allowPXE: %v", err)} + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error setting allowPXE: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) return err } - stored.Status.ToggleAllowNetboot = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: fmt.Sprintf("allowPXE set to %v", allowPXE)} - return nil } +func isNetbootJobSetupFinished(cs []v1alpha1.WorkflowCondition) bool { + for _, c := range cs { + if c.Type == v1alpha1.NetbootJobSetupComplete && c.Status == metav1.ConditionTrue { + return true + } + } + return false +} + func handleOneTimeNetboot(ctx context.Context, client ctrlclient.Client, hw *v1alpha1.Hardware, stored *v1alpha1.Workflow) (reconcile.Result, error) { if hw.Spec.BMCRef == nil { return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hw.Name) } - if !stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() && !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() { - existingJob := &rufio.Job{} - jobName := fmt.Sprintf(bmcJobName, hw.Name) - if err := client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: hw.Namespace}, existingJob); err == nil { - opts := []ctrlclient.DeleteOption{ - ctrlclient.GracePeriodSeconds(0), - ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), - } - if err := client.Delete(ctx, existingJob, opts...); err != nil { - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error deleting existing one time netboot job: %v", err)} - return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "existing one time netboot job deleted"} - - return reconcile.Result{Requeue: true}, nil - } else if errors.IsNotFound(err) { - stored.Status.OneTimeNetboot.DeletionStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "no existing one time netboot job to be deleted"} - } else { - return reconcile.Result{Requeue: true}, err + if !isNetbootJobSetupFinished(stored.Status.Conditions) || stored.Status.State == v1alpha1.WorkflowStatePreparing { + println("170") + existingJob := &rufio.Job{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf(bmcJobName, hw.Name), Namespace: hw.Namespace}} + opts := []ctrlclient.DeleteOption{ + ctrlclient.GracePeriodSeconds(0), + ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), + } + err := client.Delete(ctx, existingJob, opts...) + if err == nil { + println("189") + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupComplete, + Status: metav1.ConditionTrue, + Reason: "Deleted", + Message: "existing job deleted", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) + return reconcile.Result{}, nil + } + if !errors.IsNotFound(err) { + println("185") + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error deleting existing job: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) + return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) } - } - if !stored.Status.OneTimeNetboot.CreationStatus.IsSuccess() && stored.Status.OneTimeNetboot.DeletionStatus.IsSuccess() { name := fmt.Sprintf(bmcJobName, hw.Name) ns := hw.Namespace efiBoot := func() bool { @@ -215,14 +277,29 @@ func handleOneTimeNetboot(ctx context.Context, client ctrlclient.Client, hw *v1a }, } if err := client.Create(ctx, job); err != nil { - stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusFailure, Message: fmt.Sprintf("error creating one time netboot job: %v", err)} + println("248") + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error creating job: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) } - stored.Status.OneTimeNetboot.CreationStatus = &v1alpha1.Status{Status: v1alpha1.StatusSuccess, Message: "one time netboot job created"} + println("252") + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupComplete, + Status: metav1.ConditionTrue, + Reason: "Created", + Message: "job created", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) stored.Status.State = v1alpha1.WorkflowStatePreparing - return reconcile.Result{Requeue: true}, nil } - return reconcile.Result{Requeue: true}, nil + + println("338") + return reconcile.Result{}, nil } func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored *v1alpha1.Workflow) (reconcile.Result, error) { @@ -276,6 +353,13 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // set hardware allowPXE if requested. if stored.Spec.BootOpts.ToggleAllowNetboot { + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootRunning, + Status: metav1.ConditionTrue, + Reason: "Started", + Message: "setting allowPXE to true", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { return reconcile.Result{}, err } diff --git a/internal/server/kubernetes_api_workflow.go b/internal/server/kubernetes_api_workflow.go index a2bf511a7..bbd205be4 100644 --- a/internal/server/kubernetes_api_workflow.go +++ b/internal/server/kubernetes_api_workflow.go @@ -77,11 +77,12 @@ func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextR return err } for _, wf := range wflows { - if wf.Spec.BootOpts.ToggleAllowNetboot && wf.Status.ToggleAllowNetboot != nil && wf.Status.ToggleAllowNetboot.Status == "" && wf.Status.State == v1alpha1.WorkflowStatePreparing { - continue - } - if wf.Spec.BootOpts.OneTimeNetboot && wf.Status.State == v1alpha1.WorkflowStatePreparing { - continue + // Don't serve Actions when in a v1alpha1.WorkflowStatePreparing state. + // This is to prevent the worker from starting Actions before Workflow boot options are performed. + if wf.Spec.BootOpts.ToggleAllowNetboot || wf.Spec.BootOpts.OneTimeNetboot { + if wf.Status.State == v1alpha1.WorkflowStatePreparing { + continue + } } if err := stream.Send(getWorkflowContext(wf)); err != nil { return err From 00a5966f4d630023139e48437c557049697fc191 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 23 Sep 2024 11:01:04 -0600 Subject: [PATCH 13/24] Fix tests: Moving to using Conditions required the tests be updated. Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 17 ++-- internal/deprecated/workflow/reconciler.go | 45 ++++----- .../deprecated/workflow/reconciler_test.go | 97 ++++++++----------- 3 files changed, 74 insertions(+), 85 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 333821f4d..c5fd20dee 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -114,17 +114,16 @@ type WorkflowCondition struct { type WorkflowConditionType string const ( - NetbootJobFailed WorkflowConditionType = "Netboot Job Failed" - NetbootJobComplete WorkflowConditionType = "Netboot Job Complete" - NetbootJobRunning WorkflowConditionType = "Netboot Job Running" + NetbootJobFailed WorkflowConditionType = "NetbootJobFailed" + NetbootJobComplete WorkflowConditionType = "NetbootJobComplete" + NetbootJobRunning WorkflowConditionType = "NetbootJobRunning" - NetbootJobSetupFailed WorkflowConditionType = "Netboot Job Setup Failed" - NetbootJobSetupComplete WorkflowConditionType = "Netboot Job Setup Complete" - NetbootJobSetupRunning WorkflowConditionType = "Netboot Job Setup Running" + NetbootJobSetupFailed WorkflowConditionType = "NetbootJobSetupFailed" + NetbootJobSetupComplete WorkflowConditionType = "NetbootJobSetupComplete" + NetbootJobSetupRunning WorkflowConditionType = "NetbootJobSetupRunning" - ToggleAllowNetbootFailed WorkflowConditionType = "Toggle Allow Netboot Failed" - ToggleAllowNetbootComplete WorkflowConditionType = "Toggle Allow Netboot Complete" - ToggleAllowNetbootRunning WorkflowConditionType = "Toggle Allow Netboot Running" + ToggleAllowNetbootTrue WorkflowConditionType = "AllowNetbootTrue" + ToggleAllowNetbootFalse WorkflowConditionType = "AllowNetbootFalse" ) type OneTimeNetbootStatus struct { diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index e0666dc6a..1c5c470e0 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -118,10 +118,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } } case v1alpha1.WorkflowStateSuccess: - if wflow.Spec.BootOpts.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootComplete, metav1.ConditionTrue) { + if wflow.Spec.BootOpts.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootFalse, metav1.ConditionTrue) { // handle updating hardware allowPXE to false wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootComplete, + Type: v1alpha1.ToggleAllowNetbootFalse, Status: metav1.ConditionTrue, Reason: "Complete", Message: "setting allowPXE to false", @@ -129,6 +129,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco }, false) if err := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); err != nil { println("102") + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootFalse, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error setting Allow PXE: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) return reconcile.Result{}, err } } @@ -151,22 +158,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco // handleHardwareAllowPXE sets the allowPXE field on the hardware interfaces to true before a workflow runs and false after a workflow completes successfully. // If hardware is nil then it will be retrieved using the client. func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware, allowPXE bool) error { - if stored == nil { - return fmt.Errorf("cannot handle hardware allowPXE without a workflow") - } - - if hardware == nil { + if hardware == nil && stored != nil { hardware = &v1alpha1.Hardware{} if err := client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, hardware); err != nil { - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootFailed, - Status: metav1.ConditionTrue, - Reason: "Error", - Message: fmt.Sprintf("error getting hardware: %v", err), - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) return fmt.Errorf("hardware not found: name=%v; namespace=%v, error: %w", stored.Spec.HardwareRef, stored.Namespace, err) } + } else if stored == nil { + return fmt.Errorf("workflow and hardware cannot both be nil") } for _, iface := range hardware.Spec.Interfaces { @@ -174,13 +172,6 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store } if err := client.Update(ctx, hardware); err != nil { - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootFailed, - Status: metav1.ConditionTrue, - Reason: "Error", - Message: fmt.Sprintf("error setting allowPXE: %v", err), - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) return err } @@ -252,6 +243,9 @@ func handleOneTimeNetboot(ctx context.Context, client ctrlclient.Client, hw *v1a Labels: map[string]string{ "tink-controller-auto-created": "true", }, + OwnerReferences: []metav1.OwnerReference{ + {Name: "tink-controller"}, + }, }, Spec: rufio.JobSpec{ MachineRef: rufio.MachineRef{ @@ -354,13 +348,20 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // set hardware allowPXE if requested. if stored.Spec.BootOpts.ToggleAllowNetboot { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootRunning, + Type: v1alpha1.ToggleAllowNetbootTrue, Status: metav1.ConditionTrue, Reason: "Started", Message: "setting allowPXE to true", Time: &metav1.Time{Time: metav1.Now().UTC()}, }, false) if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootTrue, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("error setting allowPXE to true: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }, false) return reconcile.Result{}, err } } diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index 573662171..c9d720499 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "github.com/tinkerbell/tink/internal/ptr" @@ -91,8 +92,6 @@ func TestHandleHardwareAllowPXE(t *testing.T) { tests := map[string]struct { OriginalHardware *v1alpha1.Hardware WantHardware *v1alpha1.Hardware - OriginalWorkflow *v1alpha1.Workflow - WantWorkflow *v1alpha1.Workflow WantError error AllowPXE bool }{ @@ -135,13 +134,6 @@ func TestHandleHardwareAllowPXE(t *testing.T) { }, }, }, - OriginalWorkflow: &v1alpha1.Workflow{}, - WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ - ToggleAllowNetboot: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "allowPXE set to true", - }, - }}, AllowPXE: true, }, "after workflow": { @@ -183,38 +175,37 @@ func TestHandleHardwareAllowPXE(t *testing.T) { }, }, }, - OriginalWorkflow: &v1alpha1.Workflow{ - Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStateSuccess, - }, - }, - WantWorkflow: &v1alpha1.Workflow{Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStateSuccess, - ToggleAllowNetboot: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "allowPXE set to false", - }, - }}, }, } for name, tt := range tests { t.Run(name, func(t *testing.T) { fakeClient := GetFakeClientBuilder().WithRuntimeObjects(tt.OriginalHardware).Build() - err := handleHardwareAllowPXE(context.Background(), fakeClient, tt.OriginalWorkflow, tt.OriginalHardware, tt.AllowPXE) + wf := &v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + } + err := handleHardwareAllowPXE(context.Background(), fakeClient, wf, nil, tt.AllowPXE) + got := &v1alpha1.Hardware{} + if err := fakeClient.Get(context.Background(), client.ObjectKeyFromObject(tt.OriginalHardware), got); err != nil { + t.Fatalf("failed to get hardware after update: %v", err) + } if diff := cmp.Diff(tt.WantError, err, cmp.Comparer(func(a, b error) bool { return a.Error() == b.Error() })); diff != "" { + t.Errorf("error type: %T", err) t.Fatalf("unexpected error diff: %s", diff) } - if diff := cmp.Diff(tt.WantHardware, tt.OriginalHardware); diff != "" { + if diff := cmp.Diff(tt.WantHardware, got); diff != "" { t.Fatalf("unexpected hardware diff: %s", diff) } - if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow); diff != "" { - t.Fatalf("unexpected workflow diff: %s", diff) - } }) } } @@ -252,10 +243,7 @@ func TestHandleOneTimeNetboot(t *testing.T) { }, OriginalWorkflow: &v1alpha1.Workflow{ Status: v1alpha1.WorkflowStatus{ - OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ - DeletionStatus: &v1alpha1.Status{}, - CreationStatus: &v1alpha1.Status{}, - }, + State: v1alpha1.WorkflowStatePreparing, }, }, OriginalJob: &rufio.Job{ @@ -268,16 +256,18 @@ func TestHandleOneTimeNetboot(t *testing.T) { }, WantWorkflow: &v1alpha1.Workflow{ Status: v1alpha1.WorkflowStatus{ - OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ - DeletionStatus: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "existing one time netboot job deleted", + State: v1alpha1.WorkflowStatePreparing, + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.NetbootJobSetupComplete, + Status: metav1.ConditionTrue, + Reason: "Deleted", + Message: "existing job deleted", }, - CreationStatus: &v1alpha1.Status{}, }, }, }, - WantResult: reconcile.Result{Requeue: true}, + WantResult: reconcile.Result{}, }, "create bmc job": { OriginalHardware: &v1alpha1.Hardware{ @@ -290,35 +280,34 @@ func TestHandleOneTimeNetboot(t *testing.T) { Name: "bmc2", Kind: "machine.bmc.tinkerbell.org", }, + Interfaces: []v1alpha1.Interface{ + { + DHCP: &v1alpha1.DHCP{ + UEFI: true, + }, + }, + }, }, }, OriginalWorkflow: &v1alpha1.Workflow{ Status: v1alpha1.WorkflowStatus{ - OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ - DeletionStatus: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "no existing one time netboot job to be deleted", - }, - CreationStatus: &v1alpha1.Status{}, - }, + State: v1alpha1.WorkflowStatePreparing, }, }, WantWorkflow: &v1alpha1.Workflow{ Status: v1alpha1.WorkflowStatus{ State: v1alpha1.WorkflowStatePreparing, - OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ - DeletionStatus: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "no existing one time netboot job to be deleted", - }, - CreationStatus: &v1alpha1.Status{ - Status: v1alpha1.StatusSuccess, - Message: "one time netboot job created", + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.NetbootJobSetupComplete, + Status: metav1.ConditionTrue, + Reason: "Created", + Message: "job created", }, }, }, }, - WantResult: reconcile.Result{Requeue: true}, + WantResult: reconcile.Result{}, }, } @@ -346,7 +335,7 @@ func TestHandleOneTimeNetboot(t *testing.T) { if diff := cmp.Diff(tt.WantResult, r); diff != "" { t.Fatalf("unexpected result diff: %s", diff) } - if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow); diff != "" { + if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow, cmpopts.IgnoreFields(v1alpha1.WorkflowCondition{}, "Time")); diff != "" { t.Fatalf("unexpected workflow diff: %s", diff) } }) @@ -1136,7 +1125,7 @@ tasks: return } - if diff := cmp.Diff(tc.wantWflow, wflow); diff != "" { + if diff := cmp.Diff(tc.wantWflow, wflow, cmpopts.IgnoreFields(v1alpha1.WorkflowStatus{}, "TimeStarted")); diff != "" { t.Errorf("unexpected difference:\n%v", diff) } }) From 85ae82c650139d90dfb306e1d2a814add3484076 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 23 Sep 2024 11:06:47 -0600 Subject: [PATCH 14/24] Update struct tags, regenerate manifests: Signed-off-by: Jacob Weinstock --- .golangci.yml | 1 + api/v1alpha1/workflow_types.go | 4 ++-- config/crd/bases/tinkerbell.org_workflows.yaml | 8 ++++---- internal/deprecated/workflow/reconciler.go | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 6702f825d..e1cab745f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -84,6 +84,7 @@ linters-settings: - name: struct-tag arguments: - "json,inline" + - "protobuf,casttype" output: sort-results: true linters: diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index c5fd20dee..b181f9886 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -97,7 +97,7 @@ type WorkflowStatus struct { // JobCondition describes current state of a job. type WorkflowCondition struct { // Type of job condition, Complete or Failed. - Type WorkflowConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=JobConditionType"` + Type WorkflowConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=WorkflowConditionType"` // Status of the condition, one of True, False, Unknown. Status metav1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"` // (brief) reason for the condition's last transition. @@ -108,7 +108,7 @@ type WorkflowCondition struct { Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"` // Time when the condition was created. // +optional - Time *metav1.Time `json:"Time,omitempty" protobuf:"bytes,7,opt,name=lastTransitionTime"` + Time *metav1.Time `json:"time,omitempty" protobuf:"bytes,7,opt,name=time"` } type WorkflowConditionType string diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index a051709da..c791ab3cd 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -98,10 +98,6 @@ spec: items: description: JobCondition describes current state of a job. properties: - Time: - description: Time when the condition was created. - format: date-time - type: string message: description: Human readable message indicating details about last transition. type: string @@ -111,6 +107,10 @@ spec: status: description: Status of the condition, one of True, False, Unknown. type: string + time: + description: Time when the condition was created. + format: date-time + type: string type: description: Type of job condition, Complete or Failed. type: string diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 1c5c470e0..dc2e799a1 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -172,7 +172,7 @@ func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, store } if err := client.Update(ctx, hardware); err != nil { - return err + return fmt.Errorf("error updating allow pxe: %w", err) } return nil From dee9e77a8d1798e207c67d6df50fc074ac670f05 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 24 Sep 2024 18:10:44 -0600 Subject: [PATCH 15/24] Refactor: - Allows update existing conditions. - Remove using conditions to check state, add top level status fields for state. - Add TemplateRendering status field, printcolumn, and implementation - Add currentAction status field, printcolumn, and implementation - Move boot options code to their own file Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_test.go | 42 +++ api/v1alpha1/workflow_types.go | 206 ++++++------ api/v1alpha1/zz_generated.deepcopy.go | 49 +-- cmd/tink-controller/main.go | 2 + .../crd/bases/tinkerbell.org_workflows.yaml | 50 +-- internal/deprecated/workflow/reconciler.go | 292 ++++++------------ .../deprecated/workflow/reconciler_test.go | 5 +- 7 files changed, 296 insertions(+), 350 deletions(-) diff --git a/api/v1alpha1/workflow_test.go b/api/v1alpha1/workflow_test.go index 349d58983..62f68f817 100644 --- a/api/v1alpha1/workflow_test.go +++ b/api/v1alpha1/workflow_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "github.com/tinkerbell/tink/internal/testtime" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -408,3 +409,44 @@ func TestWorkflowMethods(t *testing.T) { }) } } + +func TestSetCondition(t *testing.T) { + tests := map[string]struct { + ExistingConditions []WorkflowCondition + WantConditions []WorkflowCondition + Condition WorkflowCondition + }{ + "update existing condition": { + ExistingConditions: []WorkflowCondition{ + {Type: ToggleAllowNetbootTrue, Status: metav1.ConditionTrue}, + {Type: ToggleAllowNetbootFalse, Status: metav1.ConditionTrue}, + }, + WantConditions: []WorkflowCondition{ + {Type: ToggleAllowNetbootTrue, Status: metav1.ConditionFalse}, + {Type: ToggleAllowNetbootFalse, Status: metav1.ConditionTrue}, + }, + Condition: WorkflowCondition{Type: ToggleAllowNetbootTrue, Status: metav1.ConditionFalse}, + }, + "append new condition": { + ExistingConditions: []WorkflowCondition{ + {Type: ToggleAllowNetbootTrue, Status: metav1.ConditionTrue}, + }, + WantConditions: []WorkflowCondition{ + {Type: ToggleAllowNetbootTrue, Status: metav1.ConditionTrue}, + {Type: ToggleAllowNetbootFalse, Status: metav1.ConditionFalse}, + }, + Condition: WorkflowCondition{Type: ToggleAllowNetbootFalse, Status: metav1.ConditionFalse}, + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + w := &WorkflowStatus{ + Conditions: tt.ExistingConditions, + } + w.SetCondition(tt.Condition) + if !cmp.Equal(tt.WantConditions, w.Conditions) { + t.Errorf("SetCondition() mismatch (-want +got):\n%s", cmp.Diff(tt.WantConditions, w.Conditions)) + } + }) + } +} diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index b181f9886..49bdd3e82 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -2,9 +2,17 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ) -type WorkflowState string +func init() { + SchemeBuilder.Register(&Workflow{}, &WorkflowList{}) +} + +type ( + WorkflowState string + WorkflowConditionType string +) const ( WorkflowStatePending = WorkflowState("STATE_PENDING") @@ -13,16 +21,51 @@ const ( WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") WorkflowStatePreparing = WorkflowState("STATE_PREPARING") - StatusSuccess = "success" - StatusFailure = "failure" + + NetbootJobFailed WorkflowConditionType = "NetbootJobFailed" + NetbootJobComplete WorkflowConditionType = "NetbootJobComplete" + NetbootJobRunning WorkflowConditionType = "NetbootJobRunning" + NetbootJobSetupFailed WorkflowConditionType = "NetbootJobSetupFailed" + NetbootJobSetupComplete WorkflowConditionType = "NetbootJobSetupComplete" + ToggleAllowNetbootTrue WorkflowConditionType = "AllowNetbootTrue" + ToggleAllowNetbootFalse WorkflowConditionType = "AllowNetbootFalse" + TemplateRenderedSuccess WorkflowConditionType = "TemplateRenderedSuccess" ) +// +kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=workflows,scope=Namespaced,categories=tinkerbell,shortName=wf,singular=workflow +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:JSONPath=".spec.templateRef",name=Template,type=string +// +kubebuilder:printcolumn:JSONPath=".status.state",name=State,type=string +// +kubebuilder:printcolumn:JSONPath=".status.currentAction",name=Current-Action,type=string +// +kubebuilder:printcolumn:JSONPath=".status.templateRending",name=Template-Rendering,type=string + +// Workflow is the Schema for the Workflows API. +type Workflow struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec WorkflowSpec `json:"spec,omitempty"` + Status WorkflowStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// WorkflowList contains a list of Workflows. +type WorkflowList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Workflow `json:"items"` +} + // WorkflowSpec defines the desired state of Workflow. type WorkflowSpec struct { // Name of the Template associated with this workflow. TemplateRef string `json:"templateRef,omitempty"` // Name of the Hardware associated with this workflow. + // +optional HardwareRef string `json:"hardwareRef,omitempty"` // A mapping of template devices to hadware mac addresses @@ -36,10 +79,12 @@ type BootOpts struct { // ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. // This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. // A HardwareRef must be provided. + // +optional ToggleAllowNetboot bool `json:"toggleAllowNetboot,omitempty"` // OneTimeNetboot indicates whether the controller should create a job.bmc.tinkerbell.org object for getting the associated hardware // into a netbooting state. // A HardwareRef that contains a spec.BmcRef must be provided. + // +optional OneTimeNetboot bool `json:"oneTimeNetboot,omitempty"` } @@ -48,6 +93,23 @@ type WorkflowStatus struct { // State is the state of the workflow in Tinkerbell. State WorkflowState `json:"state,omitempty"` + // CurrentAction is the action that is currently in the running state. + CurrentAction string `json:"currentAction,omitempty"` + + // JobUID is the UID of the BMCJob associated with this workflow. + // This is used to identify the unique job.bmc.tinkerbell.org object, as + // all objects are created with the same name. + // JobUID types.UID `json:"jobUid,omitempty"` + + // JobComplete bool `json:"jobComplete,omitempty"` + // ExistingJobDeleted bool `json:"existingJobDeleted,omitempty"` + + Job JobStatus `json:"jobStatus,omitempty"` + + // TemplateRendering indicates whether the template was rendered successfully. + // Possible values are "successful" or "failed". + TemplateRendering string `json:"templateRending,omitempty"` + // GlobalTimeout represents the max execution time GlobalTimeout int64 `json:"globalTimeout,omitempty"` @@ -72,26 +134,22 @@ type WorkflowStatus struct { // +patchStrategy=merge // +listType=atomic Conditions []WorkflowCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` +} - // Represents time when the job controller started processing a job. When a - // Job is created in the suspended state, this field is not set until the - // first time it is resumed. This field is reset every time a Job is resumed - // from suspension. It is represented in RFC3339 form and is in UTC. - // - // Once set, the field can only be removed when the job is suspended. - // The field cannot be modified while the job is unsuspended or finished. - // - // +optional - TimeStarted *metav1.Time `json:"timeStarted,omitempty" protobuf:"bytes,2,opt,name=startTime"` - - // Represents time when the job was completed. It is not guaranteed to - // be set in happens-before order across separate operations. - // It is represented in RFC3339 form and is in UTC. - // The completion time is set when the job finishes successfully, and only then. - // The value cannot be updated or removed. The value indicates the same or - // later point in time as the startTime field. - // +optional - TimeCompleted *metav1.Time `json:"timeCompleted,omitempty" protobuf:"bytes,3,opt,name=completionTime"` +type JobStatus struct { + // UID is the UID of the BMCJob associated with this workflow. + // This is used to identify the unique job.bmc.tinkerbell.org object, as + // all objects are created with the same name. + UID types.UID `json:"uid,omitempty"` + + // Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. + Complete bool `json:"complete,omitempty"` + + // ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. + // The name of each job.bmc.tinkerbell.org object is the same, so only one can exist at a time. + // Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per hardware. + // This makes clean up easier and we dont just orphan jobs every time. + ExistingJobDeleted bool `json:"existingJobDeleted,omitempty"` } // JobCondition describes current state of a job. @@ -111,57 +169,6 @@ type WorkflowCondition struct { Time *metav1.Time `json:"time,omitempty" protobuf:"bytes,7,opt,name=time"` } -type WorkflowConditionType string - -const ( - NetbootJobFailed WorkflowConditionType = "NetbootJobFailed" - NetbootJobComplete WorkflowConditionType = "NetbootJobComplete" - NetbootJobRunning WorkflowConditionType = "NetbootJobRunning" - - NetbootJobSetupFailed WorkflowConditionType = "NetbootJobSetupFailed" - NetbootJobSetupComplete WorkflowConditionType = "NetbootJobSetupComplete" - NetbootJobSetupRunning WorkflowConditionType = "NetbootJobSetupRunning" - - ToggleAllowNetbootTrue WorkflowConditionType = "AllowNetbootTrue" - ToggleAllowNetbootFalse WorkflowConditionType = "AllowNetbootFalse" -) - -type OneTimeNetbootStatus struct { - CreationStatus *Status `json:"creationStatus,omitempty"` - DeletionStatus *Status `json:"deletionStatus,omitempty"` -} - -// HasCondition checks if the cType condition is present with status cStatus on a bmj. -func (w WorkflowStatus) HasCondition(cType WorkflowConditionType, cStatus metav1.ConditionStatus) bool { - for _, c := range w.Conditions { - if c.Type == cType { - return c.Status == cStatus - } - } - - return false -} - -// SetCondition updates an existing condition, if it exists, or appends a new one. -// If ignoreFound is true, it will update the condition if it already exists. -func (w *WorkflowStatus) SetCondition(wc WorkflowCondition, ignoreFound bool) { - index := -1 - for i, c := range w.Conditions { - if c.Type == wc.Type { - index = i - break - } - } - if index != -1 { - if !ignoreFound { - w.Conditions[index] = wc - } - return - } - - w.Conditions = append(w.Conditions, wc) -} - // Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". type Status struct { // Status of the operation. @@ -174,13 +181,6 @@ type Status struct { Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"` } -func (s *Status) IsSuccess() bool { - if s == nil { - return false - } - return s.Status == StatusSuccess -} - // Task represents a series of actions to be completed by a worker. type Task struct { Name string `json:"name"` @@ -205,31 +205,31 @@ type Action struct { Message string `json:"message,omitempty"` } -// +kubebuilder:subresource:status -// +kubebuilder:object:root=true -// +kubebuilder:resource:path=workflows,scope=Namespaced,categories=tinkerbell,shortName=wf,singular=workflow -// +kubebuilder:storageversion -// +kubebuilder:printcolumn:JSONPath=".spec.templateRef",name=Template,type=string -// +kubebuilder:printcolumn:JSONPath=".status.state",name=State,type=string - -// Workflow is the Schema for the Workflows API. -type Workflow struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` +// HasCondition checks if the cType condition is present with status cStatus on a bmj. +func (w *WorkflowStatus) HasCondition(wct WorkflowConditionType, cs metav1.ConditionStatus) bool { + for _, c := range w.Conditions { + if c.Type == wct { + return c.Status == cs + } + } - Spec WorkflowSpec `json:"spec,omitempty"` - Status WorkflowStatus `json:"status,omitempty"` + return false } -// +kubebuilder:object:root=true - -// WorkflowList contains a list of Workflows. -type WorkflowList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Workflow `json:"items"` -} +// SetCondition updates conditions. If the condition already exists, it updates it. +// If the condition doesn't exist then it appends the new one (wc). +func (w *WorkflowStatus) SetCondition(wc WorkflowCondition) { + index := -1 + for i, c := range w.Conditions { + if c.Type == wc.Type { + index = i + break + } + } + if index != -1 { + w.Conditions[index] = wc + return + } -func init() { - SchemeBuilder.Register(&Workflow{}, &WorkflowList{}) + w.Conditions = append(w.Conditions, wc) } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ddfd4a26e..506fa62cb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -340,6 +340,21 @@ func (in *Interface) DeepCopy() *Interface { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobStatus) DeepCopyInto(out *JobStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobStatus. +func (in *JobStatus) DeepCopy() *JobStatus { + if in == nil { + return nil + } + out := new(JobStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetadataCustom) DeepCopyInto(out *MetadataCustom) { *out = *in @@ -716,31 +731,6 @@ func (in *OSIE) DeepCopy() *OSIE { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OneTimeNetbootStatus) DeepCopyInto(out *OneTimeNetbootStatus) { - *out = *in - if in.CreationStatus != nil { - in, out := &in.CreationStatus, &out.CreationStatus - *out = new(Status) - **out = **in - } - if in.DeletionStatus != nil { - in, out := &in.DeletionStatus, &out.DeletionStatus - *out = new(Status) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OneTimeNetbootStatus. -func (in *OneTimeNetbootStatus) DeepCopy() *OneTimeNetbootStatus { - if in == nil { - return nil - } - out := new(OneTimeNetbootStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Status) DeepCopyInto(out *Status) { *out = *in @@ -988,6 +978,7 @@ func (in *WorkflowSpec) DeepCopy() *WorkflowSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { *out = *in + out.Job = in.Job if in.Tasks != nil { in, out := &in.Tasks, &out.Tasks *out = make([]Task, len(*in)) @@ -1002,14 +993,6 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.TimeStarted != nil { - in, out := &in.TimeStarted, &out.TimeStarted - *out = (*in).DeepCopy() - } - if in.TimeCompleted != nil { - in, out := &in.TimeCompleted, &out.TimeCompleted - *out = (*in).DeepCopy() - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus. diff --git a/cmd/tink-controller/main.go b/cmd/tink-controller/main.go index d1686b601..354990bdf 100644 --- a/cmd/tink-controller/main.go +++ b/cmd/tink-controller/main.go @@ -95,6 +95,8 @@ func NewRootCommand() *cobra.Command { HealthProbeBindAddress: config.ProbeAddr, } + ctrl.SetLogger(logger) + mgr, err := controller.NewManager(cfg, options) if err != nil { return fmt.Errorf("controller manager: %w", err) diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index c791ab3cd..46a8b72d7 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -24,6 +24,12 @@ spec: - jsonPath: .status.state name: State type: string + - jsonPath: .status.currentAction + name: Current-Action + type: string + - jsonPath: .status.templateRending + name: Template-Rendering + type: string name: v1alpha1 schema: openAPIV3Schema: @@ -120,10 +126,32 @@ spec: type: object type: array x-kubernetes-list-type: atomic + currentAction: + description: CurrentAction is the action that is currently in the running state. + type: string globalTimeout: description: GlobalTimeout represents the max execution time format: int64 type: integer + jobStatus: + properties: + complete: + description: Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. + type: boolean + existingJobDeleted: + description: |- + ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. + The name of each job.bmc.tinkerbell.org object is the same, so only one can exist at a time. + Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per hardware. + This makes clean up easier and we dont just orphan jobs every time. + type: boolean + uid: + description: |- + UID is the UID of the BMCJob associated with this workflow. + This is used to identify the unique job.bmc.tinkerbell.org object, as + all objects are created with the same name. + type: string + type: object state: description: State is the state of the workflow in Tinkerbell. type: string @@ -187,26 +215,10 @@ spec: - worker type: object type: array - timeCompleted: + templateRending: description: |- - Represents time when the job was completed. It is not guaranteed to - be set in happens-before order across separate operations. - It is represented in RFC3339 form and is in UTC. - The completion time is set when the job finishes successfully, and only then. - The value cannot be updated or removed. The value indicates the same or - later point in time as the startTime field. - format: date-time - type: string - timeStarted: - description: |- - Represents time when the job controller started processing a job. When a - Job is created in the suspended state, this field is not set until the - first time it is resumed. This field is reset every time a Job is resumed - from suspension. It is represented in RFC3339 form and is in UTC. - - Once set, the field can only be removed when the job is suspended. - The field cannot be modified while the job is unsuspended or finished. - format: date-time + TemplateRendering indicates whether the template was rendered successfully. + Possible values are "successful" or "failed". type: string type: object type: object diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index dc2e799a1..7685b4754 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -6,7 +6,6 @@ import ( "time" "github.com/go-logr/logr" - rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" @@ -18,10 +17,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -const ( - bmcJobName = "tink-controller-%s-one-time-netboot" -) - // Reconciler is a type for managing Workflows. type Reconciler struct { client ctrlclient.Client @@ -71,51 +66,48 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco switch wflow.Status.State { case "": resp, err = r.processNewWorkflow(ctx, logger, wflow) - if wflow.Status.TimeStarted == nil { - wflow.Status.TimeStarted = &metav1.Time{Time: metav1.Now().UTC()} - } case v1alpha1.WorkflowStateRunning: resp = r.processRunningWorkflow(ctx, wflow) + // set the current action in the status + ca := runningAction(wflow) + if ca != "" && wflow.Status.CurrentAction != ca { + wflow.Status.CurrentAction = ca + } case v1alpha1.WorkflowStatePreparing: - if isNetbootJobSetupFinished(wflow.Status.Conditions) { - println("81") - existingJob := &rufio.Job{} - jobName := fmt.Sprintf(bmcJobName, wflow.Spec.HardwareRef) - if err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: jobName, Namespace: wflow.Namespace}, existingJob); err != nil { - return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) + // make sure any existing job is deleted + if !wflow.Status.Job.ExistingJobDeleted { + rc, err := handleExistingJob(ctx, r.client, wflow) + // Patch any changes, regardless of errors + if !equality.Semantic.DeepEqual(wflow, stored) { + if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { + err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) + } } - if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { - println("88") - wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobFailed, - Status: metav1.ConditionTrue, - Reason: "Error", - Message: "one time netboot job failed", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + return rc, err + } + + // create a new job + if wflow.Status.Job.UID == "" && wflow.Status.Job.ExistingJobDeleted { + rc, err := handleJobCreation(ctx, r.client, wflow) + // Patch any changes, regardless of errors + if !equality.Semantic.DeepEqual(wflow, stored) { + if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { + err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) + } } - if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { - println("94") - wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobComplete, - Status: metav1.ConditionTrue, - Reason: "Complete", - Message: "one time netboot job completed", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - wflow.Status.State = v1alpha1.WorkflowStatePending - } else { - println("99") - wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobRunning, - Status: metav1.ConditionTrue, - Reason: "Running", - Message: "netboot job running", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, true) - resp.Requeue = true + return rc, err + } + + // check if the job is complete + if !wflow.Status.Job.Complete && wflow.Status.Job.UID != "" && wflow.Status.Job.ExistingJobDeleted { + rc, err := handleJobComplete(ctx, r.client, wflow) + // Patch any changes, regardless of errors + if !equality.Semantic.DeepEqual(wflow, stored) { + if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { + err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) + } } + return rc, err } case v1alpha1.WorkflowStateSuccess: if wflow.Spec.BootOpts.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootFalse, metav1.ConditionTrue) { @@ -126,22 +118,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco Reason: "Complete", Message: "setting allowPXE to false", Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - if err := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); err != nil { - println("102") + }) + if gerr := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); gerr != nil { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootFalse, Status: metav1.ConditionTrue, Reason: "Error", - Message: fmt.Sprintf("error setting Allow PXE: %v", err), + Message: fmt.Sprintf("error setting Allow PXE: %v", gerr), Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - return reconcile.Result{}, err + }) + err = gerr } } - if wflow.Status.TimeCompleted == nil { - wflow.Status.TimeCompleted = &metav1.Time{Time: metav1.Now().UTC()} - } default: return resp, nil } @@ -155,145 +143,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return resp, err } -// handleHardwareAllowPXE sets the allowPXE field on the hardware interfaces to true before a workflow runs and false after a workflow completes successfully. -// If hardware is nil then it will be retrieved using the client. -func handleHardwareAllowPXE(ctx context.Context, client ctrlclient.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware, allowPXE bool) error { - if hardware == nil && stored != nil { - hardware = &v1alpha1.Hardware{} - if err := client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, hardware); err != nil { - return fmt.Errorf("hardware not found: name=%v; namespace=%v, error: %w", stored.Spec.HardwareRef, stored.Namespace, err) - } - } else if stored == nil { - return fmt.Errorf("workflow and hardware cannot both be nil") - } - - for _, iface := range hardware.Spec.Interfaces { - iface.Netboot.AllowPXE = ptr.Bool(allowPXE) - } - - if err := client.Update(ctx, hardware); err != nil { - return fmt.Errorf("error updating allow pxe: %w", err) - } - - return nil -} - -func isNetbootJobSetupFinished(cs []v1alpha1.WorkflowCondition) bool { - for _, c := range cs { - if c.Type == v1alpha1.NetbootJobSetupComplete && c.Status == metav1.ConditionTrue { - return true - } - } - return false -} - -func handleOneTimeNetboot(ctx context.Context, client ctrlclient.Client, hw *v1alpha1.Hardware, stored *v1alpha1.Workflow) (reconcile.Result, error) { - if hw.Spec.BMCRef == nil { - return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hw.Name) - } - - if !isNetbootJobSetupFinished(stored.Status.Conditions) || stored.Status.State == v1alpha1.WorkflowStatePreparing { - println("170") - existingJob := &rufio.Job{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf(bmcJobName, hw.Name), Namespace: hw.Namespace}} - opts := []ctrlclient.DeleteOption{ - ctrlclient.GracePeriodSeconds(0), - ctrlclient.PropagationPolicy(metav1.DeletePropagationForeground), - } - err := client.Delete(ctx, existingJob, opts...) - if err == nil { - println("189") - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobSetupComplete, - Status: metav1.ConditionTrue, - Reason: "Deleted", - Message: "existing job deleted", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - return reconcile.Result{}, nil - } - if !errors.IsNotFound(err) { - println("185") - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobSetupFailed, - Status: metav1.ConditionTrue, - Reason: "Error", - Message: fmt.Sprintf("error deleting existing job: %v", err), - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - return reconcile.Result{}, fmt.Errorf("error deleting existing job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - - name := fmt.Sprintf(bmcJobName, hw.Name) - ns := hw.Namespace - efiBoot := func() bool { - for _, iface := range hw.Spec.Interfaces { - if iface.DHCP != nil && iface.DHCP.UEFI { - return true - } +func runningAction(wf *v1alpha1.Workflow) string { + for _, task := range wf.Status.Tasks { + for _, action := range task.Actions { + if action.Status == v1alpha1.WorkflowStateRunning { + return action.Name } - return false - }() - job := &rufio.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: ns, - Annotations: map[string]string{ - "tink-controller-auto-created": "true", - }, - Labels: map[string]string{ - "tink-controller-auto-created": "true", - }, - OwnerReferences: []metav1.OwnerReference{ - {Name: "tink-controller"}, - }, - }, - Spec: rufio.JobSpec{ - MachineRef: rufio.MachineRef{ - Name: hw.Spec.BMCRef.Name, - Namespace: ns, - }, - Tasks: []rufio.Action{ - { - PowerAction: rufio.PowerHardOff.Ptr(), - }, - { - OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ - Devices: []rufio.BootDevice{ - rufio.PXE, - }, - EFIBoot: efiBoot, - }, - }, - { - PowerAction: rufio.PowerOn.Ptr(), - }, - }, - }, } - if err := client.Create(ctx, job); err != nil { - println("248") - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobSetupFailed, - Status: metav1.ConditionTrue, - Reason: "Error", - Message: fmt.Sprintf("error creating job: %v", err), - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) - } - println("252") - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.NetbootJobSetupComplete, - Status: metav1.ConditionTrue, - Reason: "Created", - Message: "job created", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) - stored.Status.State = v1alpha1.WorkflowStatePreparing } - println("338") - return reconcile.Result{}, nil + return "" } func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored *v1alpha1.Workflow) (reconcile.Result, error) { @@ -302,12 +161,28 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, if errors.IsNotFound(err) { // Throw an error to raise awareness and take advantage of immediate requeue. logger.Error(err, "error getting Template object in processNewWorkflow function") + stored.Status.TemplateRendering = "failed" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: "template not found", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) return reconcile.Result{}, fmt.Errorf( "no template found: name=%v; namespace=%v", stored.Spec.TemplateRef, stored.Namespace, ) } + stored.Status.TemplateRendering = "failed" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: err.Error(), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) return reconcile.Result{}, err } @@ -320,11 +195,27 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, &hardware) if err != nil && !errors.IsNotFound(err) { logger.Error(err, "error getting Hardware object in processNewWorkflow function") + stored.Status.TemplateRendering = "failed" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("error getting hardware: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) return reconcile.Result{}, err } if stored.Spec.HardwareRef != "" && errors.IsNotFound(err) { logger.Error(err, "hardware not found in processNewWorkflow function") + stored.Status.TemplateRendering = "failed" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("hardware not found: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) return reconcile.Result{}, fmt.Errorf( "hardware not found: name=%v; namespace=%v", stored.Spec.HardwareRef, @@ -339,21 +230,37 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, tinkWf, err := renderTemplateHardware(stored.Name, ptr.StringValue(tpl.Spec.Data), data) if err != nil { + stored.Status.TemplateRendering = "failed" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("error rendering template: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) return reconcile.Result{}, err } // populate Task and Action data stored.Status = *YAMLToStatus(tinkWf) + stored.Status.TemplateRendering = "successful" + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.TemplateRenderedSuccess, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "template rendered successfully", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) // set hardware allowPXE if requested. if stored.Spec.BootOpts.ToggleAllowNetboot { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootTrue, Status: metav1.ConditionTrue, - Reason: "Started", + Reason: "Complete", Message: "setting allowPXE to true", Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) + }) if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootTrue, @@ -361,14 +268,15 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, Reason: "Error", Message: fmt.Sprintf("error setting allowPXE to true: %v", err), Time: &metav1.Time{Time: metav1.Now().UTC()}, - }, false) + }) return reconcile.Result{}, err } } // netboot the hardware if requested if stored.Spec.BootOpts.OneTimeNetboot { - return handleOneTimeNetboot(ctx, r.client, &hardware, stored) + stored.Status.State = v1alpha1.WorkflowStatePreparing + return reconcile.Result{Requeue: true}, err } stored.Status.State = v1alpha1.WorkflowStatePending diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index c9d720499..1e57ccd70 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -3,17 +3,14 @@ package workflow import ( "context" "errors" - "fmt" "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" "github.com/tinkerbell/tink/internal/ptr" "github.com/tinkerbell/tink/internal/testtime" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -210,6 +207,7 @@ func TestHandleHardwareAllowPXE(t *testing.T) { } } +/* func TestHandleOneTimeNetboot(t *testing.T) { tests := map[string]struct { OriginalHardware *v1alpha1.Hardware @@ -341,6 +339,7 @@ func TestHandleOneTimeNetboot(t *testing.T) { }) } } +*/ func TestReconcile(t *testing.T) { cases := []struct { From 3217c7473d287bafefd61907867d8633be94918d Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 24 Sep 2024 18:16:44 -0600 Subject: [PATCH 16/24] Fix linting issues Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/reconciler.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 7685b4754..aa0a40866 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -17,6 +17,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) +const ( + failed = "failed" +) + // Reconciler is a type for managing Workflows. type Reconciler struct { client ctrlclient.Client @@ -161,7 +165,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, if errors.IsNotFound(err) { // Throw an error to raise awareness and take advantage of immediate requeue. logger.Error(err, "error getting Template object in processNewWorkflow function") - stored.Status.TemplateRendering = "failed" + stored.Status.TemplateRendering = failed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -175,7 +179,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored.Namespace, ) } - stored.Status.TemplateRendering = "failed" + stored.Status.TemplateRendering = failed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -195,7 +199,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, &hardware) if err != nil && !errors.IsNotFound(err) { logger.Error(err, "error getting Hardware object in processNewWorkflow function") - stored.Status.TemplateRendering = "failed" + stored.Status.TemplateRendering = failed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -208,7 +212,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, if stored.Spec.HardwareRef != "" && errors.IsNotFound(err) { logger.Error(err, "hardware not found in processNewWorkflow function") - stored.Status.TemplateRendering = "failed" + stored.Status.TemplateRendering = failed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -230,7 +234,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, tinkWf, err := renderTemplateHardware(stored.Name, ptr.StringValue(tpl.Spec.Data), data) if err != nil { - stored.Status.TemplateRendering = "failed" + stored.Status.TemplateRendering = failed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, From 4cf6cf2421bfaa2a03427b3cfd4b1aa3d463aeb7 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 24 Sep 2024 18:29:09 -0600 Subject: [PATCH 17/24] Fix tests Signed-off-by: Jacob Weinstock --- .../deprecated/workflow/reconciler_test.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index 1e57ccd70..782c6b304 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -458,8 +458,12 @@ func TestReconcile(t *testing.T) { }, }, Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePending, - GlobalTimeout: 1800, + State: v1alpha1.WorkflowStatePending, + GlobalTimeout: 1800, + TemplateRendering: "successful", + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionTrue, Reason: "Complete", Message: "template rendered successfully"}, + }, Tasks: []v1alpha1.Task{ { Name: "os-installation", @@ -1035,8 +1039,12 @@ tasks: }, }, Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePending, - GlobalTimeout: 1800, + State: v1alpha1.WorkflowStatePending, + GlobalTimeout: 1800, + TemplateRendering: "successful", + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionTrue, Reason: "Complete", Message: "template rendered successfully"}, + }, Tasks: []v1alpha1.Task{ { Name: "os-installation", @@ -1124,7 +1132,7 @@ tasks: return } - if diff := cmp.Diff(tc.wantWflow, wflow, cmpopts.IgnoreFields(v1alpha1.WorkflowStatus{}, "TimeStarted")); diff != "" { + if diff := cmp.Diff(tc.wantWflow, wflow, cmpopts.IgnoreFields(v1alpha1.WorkflowCondition{}, "Time")); diff != "" { t.Errorf("unexpected difference:\n%v", diff) } }) From 43a9eab9493aa70521388e9527901a8f25a5019a Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 24 Sep 2024 18:34:18 -0600 Subject: [PATCH 18/24] Add missing file for boot options Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/bootops.go | 200 ++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 internal/deprecated/workflow/bootops.go diff --git a/internal/deprecated/workflow/bootops.go b/internal/deprecated/workflow/bootops.go new file mode 100644 index 000000000..34bd242af --- /dev/null +++ b/internal/deprecated/workflow/bootops.go @@ -0,0 +1,200 @@ +package workflow + +import ( + "context" + "fmt" + "time" + + rufio "github.com/tinkerbell/rufio/api/v1alpha1" + "github.com/tinkerbell/tink/api/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + bmcJobName = "tink-controller-%s-one-time-netboot" +) + +// handleExistingJob ensures that an existing job.bmc.tinkerbell.org is removed. +func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { + if wf.Status.Job.ExistingJobDeleted { + return reconcile.Result{}, nil + } + name := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) + namespace := wf.Namespace + if err := cc.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, &rufio.Job{}); (err != nil && !errors.IsNotFound(err)) || err == nil { + existingJob := &rufio.Job{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}} + opts := []client.DeleteOption{ + client.GracePeriodSeconds(0), + client.PropagationPolicy(metav1.DeletePropagationForeground), + } + if err := cc.Delete(ctx, existingJob, opts...); err != nil { + return reconcile.Result{}, fmt.Errorf("error deleting job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + return reconcile.Result{Requeue: true}, nil + } + wf.Status.Job.ExistingJobDeleted = true + + return reconcile.Result{Requeue: true}, nil +} + +func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { + if wf.Status.Job.UID == "" && wf.Status.Job.ExistingJobDeleted { + // assumption is that at this point, if the job exists its because we created it already. + // requeue until the jobuid shows up. + existingJob := &rufio.Job{} + if err := cc.Get(ctx, client.ObjectKey{Name: fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef), Namespace: wf.Namespace}, existingJob); err == nil { + wf.Status.Job.UID = existingJob.GetUID() + return reconcile.Result{Requeue: true}, nil + } + hw := &v1alpha1.Hardware{ObjectMeta: metav1.ObjectMeta{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}} + if gerr := cc.Get(ctx, client.ObjectKey{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}, hw); gerr != nil { + return reconcile.Result{}, fmt.Errorf("error getting hardware %s: %w", wf.Spec.HardwareRef, gerr) + } + if hw.Spec.BMCRef == nil { + return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hw.Name) + } + if err := createNetbootJob(ctx, cc, hw, wf.Namespace); err != nil { + wf.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: fmt.Sprintf("error creating job: %v", err), + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + wf.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobSetupComplete, + Status: metav1.ConditionTrue, + Reason: "Created", + Message: "job created", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + + return reconcile.Result{Requeue: true}, nil + } + + return reconcile.Result{}, nil +} + +func handleJobComplete(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { + if !wf.Status.Job.Complete && wf.Status.Job.UID != "" && wf.Status.Job.ExistingJobDeleted { + existingJob := &rufio.Job{} + jobName := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) + if gerr := cc.Get(ctx, client.ObjectKey{Name: jobName, Namespace: wf.Namespace}, existingJob); gerr != nil { + return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", gerr) + } + if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { + wf.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobFailed, + Status: metav1.ConditionTrue, + Reason: "Error", + Message: "one time netboot job failed", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + return reconcile.Result{}, fmt.Errorf("one time netboot job failed") + } + if existingJob.HasCondition(rufio.JobCompleted, rufio.ConditionTrue) { + wf.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobComplete, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "one time netboot job completed", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + wf.Status.State = v1alpha1.WorkflowStatePending + wf.Status.Job.Complete = true + return reconcile.Result{Requeue: true}, nil + } + if !wf.Status.HasCondition(v1alpha1.NetbootJobRunning, metav1.ConditionTrue) { + wf.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.NetbootJobRunning, + Status: metav1.ConditionTrue, + Reason: "Running", + Message: "one time netboot job running", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + } + return reconcile.Result{RequeueAfter: 5 * time.Second}, nil + } + + return reconcile.Result{}, nil +} + +func createNetbootJob(ctx context.Context, cc client.Client, hw *v1alpha1.Hardware, ns string) error { + name := fmt.Sprintf(bmcJobName, hw.Name) + efiBoot := func() bool { + for _, iface := range hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.UEFI { + return true + } + } + return false + }() + job := &rufio.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + Annotations: map[string]string{ + "tink-controller-auto-created": "true", + }, + Labels: map[string]string{ + "tink-controller-auto-created": "true", + }, + }, + Spec: rufio.JobSpec{ + MachineRef: rufio.MachineRef{ + Name: hw.Spec.BMCRef.Name, + Namespace: ns, + }, + Tasks: []rufio.Action{ + { + PowerAction: rufio.PowerHardOff.Ptr(), + }, + { + OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ + Devices: []rufio.BootDevice{ + rufio.PXE, + }, + EFIBoot: efiBoot, + }, + }, + { + PowerAction: rufio.PowerOn.Ptr(), + }, + }, + }, + } + if err := cc.Create(ctx, job); err != nil { + return fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) + } + + return nil +} + +// handleHardwareAllowPXE sets the allowPXE field on the hardware interfaces to true before a workflow runs and false after a workflow completes successfully. +// If hardware is nil then it will be retrieved using the client. +func handleHardwareAllowPXE(ctx context.Context, cc client.Client, stored *v1alpha1.Workflow, hardware *v1alpha1.Hardware, allowPXE bool) error { + if hardware == nil && stored != nil { + hardware = &v1alpha1.Hardware{} + if err := cc.Get(ctx, client.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, hardware); err != nil { + return fmt.Errorf("hardware not found: name=%v; namespace=%v, error: %w", stored.Spec.HardwareRef, stored.Namespace, err) + } + } else if stored == nil { + return fmt.Errorf("workflow and hardware cannot both be nil") + } + + for _, iface := range hardware.Spec.Interfaces { + iface.Netboot.AllowPXE = ptr.Bool(allowPXE) + } + + if err := cc.Update(ctx, hardware); err != nil { + return fmt.Errorf("error updating allow pxe: %w", err) + } + + return nil +} From 12aedc8a00abb61b77cb29a9d99f1ae27f9b307f Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 25 Sep 2024 09:39:08 -0600 Subject: [PATCH 19/24] Add test for handleExistingJob Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/bootops.go | 2 +- internal/deprecated/workflow/bootops_test.go | 145 +++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 internal/deprecated/workflow/bootops_test.go diff --git a/internal/deprecated/workflow/bootops.go b/internal/deprecated/workflow/bootops.go index 34bd242af..793911a1e 100644 --- a/internal/deprecated/workflow/bootops.go +++ b/internal/deprecated/workflow/bootops.go @@ -32,7 +32,7 @@ func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workf client.PropagationPolicy(metav1.DeletePropagationForeground), } if err := cc.Delete(ctx, existingJob, opts...); err != nil { - return reconcile.Result{}, fmt.Errorf("error deleting job.bmc.tinkerbell.org object for netbooting machine: %w", err) + return reconcile.Result{}, fmt.Errorf("error deleting job.bmc.tinkerbell.org object: %w", err) } return reconcile.Result{Requeue: true}, nil } diff --git a/internal/deprecated/workflow/bootops_test.go b/internal/deprecated/workflow/bootops_test.go new file mode 100644 index 000000000..397e59d5c --- /dev/null +++ b/internal/deprecated/workflow/bootops_test.go @@ -0,0 +1,145 @@ +package workflow + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" + "github.com/tinkerbell/tink/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +func TestHandleExistingJob(t *testing.T) { + tests := map[string]struct { + workflow *v1alpha1.Workflow + wantWorkflow *v1alpha1.Workflow + wantResult reconcile.Result + job *rufio.Job + }{ + "existing job deleted": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: false, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: false, + }, + }, + }, + wantResult: reconcile.Result{Requeue: true}, + job: &rufio.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: "tink-controller-machine1-one-time-netboot", + Namespace: "default", + }, + }, + }, + "no existing job": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{}, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: true, + }, + }, + }, + wantResult: reconcile.Result{Requeue: true}, + }, + "existing job already deleted": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: true, + }, + }, + }, + wantResult: reconcile.Result{}, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + //cc := GetFakeClientBuilder().Build() + runtimescheme := runtime.NewScheme() + rufio.AddToScheme(runtimescheme) + v1alpha1.AddToScheme(runtimescheme) + clientBulider := GetFakeClientBuilder().WithScheme(runtimescheme) + if tc.job != nil { + clientBulider.WithRuntimeObjects(tc.job) + } + cc := clientBulider.Build() + + r, err := handleExistingJob(context.Background(), cc, tc.workflow) + if err != nil { + t.Fatalf("handleExistingJob() err = %v, want nil", err) + } + if diff := cmp.Diff(tc.wantResult, r); diff != "" { + t.Errorf("handleExistingJob() mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(tc.wantWorkflow, tc.workflow); diff != "" { + t.Errorf("handleExistingJob() mismatch (-want +got):\n%s", diff) + } + }) + } +} From d718bde98cbd58487156358ec70b1b8798e036f4 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 25 Sep 2024 10:34:04 -0600 Subject: [PATCH 20/24] Add tests for handleJobComplete Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/bootops.go | 8 +- internal/deprecated/workflow/bootops_test.go | 341 ++++++++++++++++++- 2 files changed, 343 insertions(+), 6 deletions(-) diff --git a/internal/deprecated/workflow/bootops.go b/internal/deprecated/workflow/bootops.go index 793911a1e..0a62a0855 100644 --- a/internal/deprecated/workflow/bootops.go +++ b/internal/deprecated/workflow/bootops.go @@ -43,8 +43,6 @@ func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workf func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { if wf.Status.Job.UID == "" && wf.Status.Job.ExistingJobDeleted { - // assumption is that at this point, if the job exists its because we created it already. - // requeue until the jobuid shows up. existingJob := &rufio.Job{} if err := cc.Get(ctx, client.ObjectKey{Name: fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef), Namespace: wf.Namespace}, existingJob); err == nil { wf.Status.Job.UID = existingJob.GetUID() @@ -65,7 +63,7 @@ func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workf Message: fmt.Sprintf("error creating job: %v", err), Time: &metav1.Time{Time: metav1.Now().UTC()}, }) - return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object for netbooting machine: %w", err) + return reconcile.Result{}, fmt.Errorf("error creating job.bmc.tinkerbell.org object: %w", err) } wf.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.NetbootJobSetupComplete, @@ -85,8 +83,8 @@ func handleJobComplete(ctx context.Context, cc client.Client, wf *v1alpha1.Workf if !wf.Status.Job.Complete && wf.Status.Job.UID != "" && wf.Status.Job.ExistingJobDeleted { existingJob := &rufio.Job{} jobName := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) - if gerr := cc.Get(ctx, client.ObjectKey{Name: jobName, Namespace: wf.Namespace}, existingJob); gerr != nil { - return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", gerr) + if err := cc.Get(ctx, client.ObjectKey{Name: jobName, Namespace: wf.Namespace}, existingJob); err != nil { + return reconcile.Result{}, fmt.Errorf("error getting one time netboot job: %w", err) } if existingJob.HasCondition(rufio.JobFailed, rufio.ConditionTrue) { wf.Status.SetCondition(v1alpha1.WorkflowCondition{ diff --git a/internal/deprecated/workflow/bootops_test.go b/internal/deprecated/workflow/bootops_test.go index 397e59d5c..00e639565 100644 --- a/internal/deprecated/workflow/bootops_test.go +++ b/internal/deprecated/workflow/bootops_test.go @@ -3,12 +3,18 @@ package workflow import ( "context" "testing" + "time" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -120,7 +126,6 @@ func TestHandleExistingJob(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - //cc := GetFakeClientBuilder().Build() runtimescheme := runtime.NewScheme() rufio.AddToScheme(runtimescheme) v1alpha1.AddToScheme(runtimescheme) @@ -143,3 +148,337 @@ func TestHandleExistingJob(t *testing.T) { }) } } + +func TestHandleJobCreation(t *testing.T) { + uid := uuid.NewUUID() + tests := map[string]struct { + workflow *v1alpha1.Workflow + wantWorkflow *v1alpha1.Workflow + wantResult reconcile.Result + job *rufio.Job + }{ + "creation already done": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + UID: uid, + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + UID: uid, + ExistingJobDeleted: true, + }, + }, + }, + wantResult: reconcile.Result{}, + }, + "create new job": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{ + HardwareRef: "machine1", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + ExistingJobDeleted: true, + }, + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.NetbootJobSetupComplete, Status: v1.ConditionTrue, Reason: "Created", Message: "job created"}, + }, + }, + }, + wantResult: reconcile.Result{Requeue: true}, + job: &rufio.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: "tink-controller-machine1-one-time-netboot", + Namespace: "default", + ResourceVersion: "1", + Labels: map[string]string{ + "tink-controller-auto-created": "true", + }, + Annotations: map[string]string{ + "tink-controller-auto-created": "true", + }, + }, + Spec: rufio.JobSpec{ + MachineRef: rufio.MachineRef{ + Name: "machine1", + Namespace: "default", + }, + Tasks: []rufio.Action{ + {PowerAction: ptr.To(rufio.PowerHardOff)}, + {OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{Devices: []rufio.BootDevice{rufio.PXE}}}, + {PowerAction: ptr.To(rufio.PowerOn)}, + }, + }, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + runtimescheme := runtime.NewScheme() + rufio.AddToScheme(runtimescheme) + v1alpha1.AddToScheme(runtimescheme) + clientBulider := GetFakeClientBuilder().WithScheme(runtimescheme) + clientBulider.WithRuntimeObjects(&v1alpha1.Hardware{ + ObjectMeta: v1.ObjectMeta{ + Name: "machine1", + Namespace: "default", + }, + Spec: v1alpha1.HardwareSpec{ + BMCRef: &corev1.TypedLocalObjectReference{Name: "machine1"}, + }, + }) + cc := clientBulider.Build() + + r, err := handleJobCreation(context.Background(), cc, tc.workflow) + if err != nil { + t.Fatalf("handleJobCreation() err = %v, want nil", err) + } + if diff := cmp.Diff(tc.wantResult, r); diff != "" { + t.Errorf("handleJobCreation() mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(tc.wantWorkflow, tc.workflow, cmpopts.IgnoreFields(v1alpha1.WorkflowCondition{}, "Time")); diff != "" { + t.Errorf("handleJobCreation() mismatch (-want +got):\n%s", diff) + } + // check if the job is created + if tc.job != nil { + job := &rufio.Job{} + if err := cc.Get(context.Background(), client.ObjectKey{Name: tc.job.Name, Namespace: tc.job.Namespace}, job); err != nil { + t.Fatalf("handleJobCreation() job not created: %v", err) + } + if diff := cmp.Diff(tc.job, job); diff != "" { + t.Errorf("handleJobCreation() mismatch (-want +got):\n%s", diff) + } + } + }) + } +} + +func TestHandleJobComplete(t *testing.T) { + uid := uuid.NewUUID() + tests := map[string]struct { + workflow *v1alpha1.Workflow + wantWorkflow *v1alpha1.Workflow + wantResult reconcile.Result + job *rufio.Job + shouldError bool + }{ + "status for existing job complete": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: true, + }, + }, + }, + wantResult: reconcile.Result{}, + }, + "existing job not complete": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.NetbootJobRunning, Status: v1.ConditionTrue, Reason: "Running", Message: "one time netboot job running"}, + }, + }, + }, + wantResult: reconcile.Result{RequeueAfter: 5 * time.Second}, + job: &rufio.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: "tink-controller-machine1-one-time-netboot", + Namespace: "default", + }, + Status: rufio.JobStatus{ + Conditions: []rufio.JobCondition{ + {Type: rufio.JobRunning, Status: rufio.ConditionTrue}, + }, + }, + }, + }, + "existing job failed": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.NetbootJobFailed, Status: v1.ConditionTrue, Reason: "Error", Message: "one time netboot job failed"}, + }, + }, + }, + wantResult: reconcile.Result{}, + job: &rufio.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: "tink-controller-machine1-one-time-netboot", + Namespace: "default", + }, + Status: rufio.JobStatus{ + Conditions: []rufio.JobCondition{ + {Type: rufio.JobFailed, Status: rufio.ConditionTrue}, + }, + }, + }, + shouldError: true, + }, + "existing job completed": { + workflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + Job: v1alpha1.JobStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, + }, + }, + wantWorkflow: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "workflow1", + Namespace: "default", + }, + Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, + Status: v1alpha1.WorkflowStatus{ + State: v1alpha1.WorkflowStatePending, + Job: v1alpha1.JobStatus{ + Complete: true, + UID: uid, + ExistingJobDeleted: true, + }, + Conditions: []v1alpha1.WorkflowCondition{ + {Type: v1alpha1.NetbootJobComplete, Status: v1.ConditionTrue, Reason: "Complete", Message: "one time netboot job completed"}, + }, + }, + }, + wantResult: reconcile.Result{Requeue: true}, + job: &rufio.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: "tink-controller-machine1-one-time-netboot", + Namespace: "default", + }, + Status: rufio.JobStatus{ + Conditions: []rufio.JobCondition{ + {Type: rufio.JobCompleted, Status: rufio.ConditionTrue}, + }, + }, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + runtimescheme := runtime.NewScheme() + rufio.AddToScheme(runtimescheme) + v1alpha1.AddToScheme(runtimescheme) + clientBulider := GetFakeClientBuilder().WithScheme(runtimescheme) + if tc.job != nil { + clientBulider.WithRuntimeObjects(tc.job) + } + cc := clientBulider.Build() + + r, err := handleJobComplete(context.Background(), cc, tc.workflow) + if err != nil && !tc.shouldError { + t.Fatalf("handleJobComplete() err = %v, want nil", err) + } + if diff := cmp.Diff(tc.wantResult, r); diff != "" { + t.Errorf("result mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(tc.wantWorkflow, tc.workflow, cmpopts.IgnoreFields(v1alpha1.WorkflowCondition{}, "Time")); diff != "" { + t.Errorf("workflow mismatch (-want +got):\n%s", diff) + } + }) + } +} From 9f6b9adc1faf860cedc51491f96c5d6d0506a576 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 26 Sep 2024 09:34:24 -0600 Subject: [PATCH 21/24] Clean up Workflow API comments and unused code: Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_types.go | 64 ++++++------------- api/v1alpha1/zz_generated.deepcopy.go | 15 ----- .../crd/bases/tinkerbell.org_workflows.yaml | 46 ++++++------- 3 files changed, 36 insertions(+), 89 deletions(-) diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 49bdd3e82..689759284 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -68,13 +68,14 @@ type WorkflowSpec struct { // +optional HardwareRef string `json:"hardwareRef,omitempty"` - // A mapping of template devices to hadware mac addresses + // A mapping of template devices to hadware mac addresses. HardwareMap map[string]string `json:"hardwareMap,omitempty"` - // BootOpts is a set of options to be used when netbooting the hardware. + // BootOpts are options that control the booting of Hardware. BootOpts BootOpts `json:"bootOpts,omitempty"` } +// BootOpts are options that control the booting of Hardware. type BootOpts struct { // ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. // This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. @@ -88,47 +89,30 @@ type BootOpts struct { OneTimeNetboot bool `json:"oneTimeNetboot,omitempty"` } -// WorkflowStatus defines the observed state of Workflow. +// WorkflowStatus defines the observed state of a Workflow. type WorkflowStatus struct { - // State is the state of the workflow in Tinkerbell. + // State is the current overall state of the Workflow. State WorkflowState `json:"state,omitempty"` // CurrentAction is the action that is currently in the running state. CurrentAction string `json:"currentAction,omitempty"` - // JobUID is the UID of the BMCJob associated with this workflow. - // This is used to identify the unique job.bmc.tinkerbell.org object, as - // all objects are created with the same name. - // JobUID types.UID `json:"jobUid,omitempty"` - - // JobComplete bool `json:"jobComplete,omitempty"` - // ExistingJobDeleted bool `json:"existingJobDeleted,omitempty"` - + // Job holds the state of a specific job.bmc.tinkerbell.org object created. + // Only used when BootOpts.OneTimeNetboot is true. Job JobStatus `json:"jobStatus,omitempty"` // TemplateRendering indicates whether the template was rendered successfully. - // Possible values are "successful" or "failed". + // Possible values are "successful" or "failed" or "unknown". TemplateRendering string `json:"templateRending,omitempty"` - // GlobalTimeout represents the max execution time + // GlobalTimeout represents the max execution time. GlobalTimeout int64 `json:"globalTimeout,omitempty"` - // Tasks are the tasks to be completed + // Tasks are the tasks to be run by the worker(s). Tasks []Task `json:"tasks,omitempty"` - // The latest available observations of an object's current state. When a Job - // fails, one of the conditions will have type "Failed" and status true. When - // a Job is suspended, one of the conditions will have type "Suspended" and - // status true; when the Job is resumed, the status of this condition will - // become false. When a Job is completed, one of the conditions will have - // type "Complete" and status true. + // Conditions are the latest available observations of an object's current state. // - // A job is considered finished when it is in a terminal condition, either - // "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions. - // Additionally, it cannot be in the "Complete" and "FailureTarget" conditions. - // The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled. - // - // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ // +optional // +patchMergeKey=type // +patchStrategy=merge @@ -137,17 +121,17 @@ type WorkflowStatus struct { } type JobStatus struct { - // UID is the UID of the BMCJob associated with this workflow. - // This is used to identify the unique job.bmc.tinkerbell.org object, as - // all objects are created with the same name. + // UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. + // This is used to uniquely identify the job.bmc.tinkerbell.org object, as + // all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. UID types.UID `json:"uid,omitempty"` // Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. Complete bool `json:"complete,omitempty"` // ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. - // The name of each job.bmc.tinkerbell.org object is the same, so only one can exist at a time. - // Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per hardware. + // The name of each job.bmc.tinkerbell.org object created by the controller is the same, so only one can exist at a time. + // Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per Hardware/Machine.bmc.tinkerbell.org. // This makes clean up easier and we dont just orphan jobs every time. ExistingJobDeleted bool `json:"existingJobDeleted,omitempty"` } @@ -158,10 +142,10 @@ type WorkflowCondition struct { Type WorkflowConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=WorkflowConditionType"` // Status of the condition, one of True, False, Unknown. Status metav1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"` - // (brief) reason for the condition's last transition. + // Reason is a (brief) reason for the condition's last transition. // +optional Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"` - // Human readable message indicating details about last transition. + // Message is a human readable message indicating details about last transition. // +optional Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"` // Time when the condition was created. @@ -169,18 +153,6 @@ type WorkflowCondition struct { Time *metav1.Time `json:"time,omitempty" protobuf:"bytes,7,opt,name=time"` } -// Wanted to use metav1.Status but kubebuilder errors with, "must apply listType to an array, found". -type Status struct { - // Status of the operation. - // One of: "Success" or "Failure". - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - // +optional - Status string `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"` - // A human-readable description of the status of this operation. - // +optional - Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"` -} - // Task represents a series of actions to be completed by a worker. type Task struct { Name string `json:"name"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 506fa62cb..0e057e10e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -731,21 +731,6 @@ func (in *OSIE) DeepCopy() *OSIE { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Status) DeepCopyInto(out *Status) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. -func (in *Status) DeepCopy() *Status { - if in == nil { - return nil - } - out := new(Status) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 46a8b72d7..0f3b580b8 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -56,7 +56,7 @@ spec: description: WorkflowSpec defines the desired state of Workflow. properties: bootOpts: - description: BootOpts is a set of options to be used when netbooting the hardware. + description: BootOpts are options that control the booting of Hardware. properties: oneTimeNetboot: description: |- @@ -74,7 +74,7 @@ spec: hardwareMap: additionalProperties: type: string - description: A mapping of template devices to hadware mac addresses + description: A mapping of template devices to hadware mac addresses. type: object hardwareRef: description: Name of the Hardware associated with this workflow. @@ -84,31 +84,18 @@ spec: type: string type: object status: - description: WorkflowStatus defines the observed state of Workflow. + description: WorkflowStatus defines the observed state of a Workflow. properties: conditions: - description: |- - The latest available observations of an object's current state. When a Job - fails, one of the conditions will have type "Failed" and status true. When - a Job is suspended, one of the conditions will have type "Suspended" and - status true; when the Job is resumed, the status of this condition will - become false. When a Job is completed, one of the conditions will have - type "Complete" and status true. - - A job is considered finished when it is in a terminal condition, either - "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions. - Additionally, it cannot be in the "Complete" and "FailureTarget" conditions. - The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled. - - More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + description: Conditions are the latest available observations of an object's current state. items: description: JobCondition describes current state of a job. properties: message: - description: Human readable message indicating details about last transition. + description: Message is a human readable message indicating details about last transition. type: string reason: - description: (brief) reason for the condition's last transition. + description: Reason is a (brief) reason for the condition's last transition. type: string status: description: Status of the condition, one of True, False, Unknown. @@ -130,10 +117,13 @@ spec: description: CurrentAction is the action that is currently in the running state. type: string globalTimeout: - description: GlobalTimeout represents the max execution time + description: GlobalTimeout represents the max execution time. format: int64 type: integer jobStatus: + description: |- + Job holds the state of a specific job.bmc.tinkerbell.org object created. + Only used when BootOpts.OneTimeNetboot is true. properties: complete: description: Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. @@ -141,22 +131,22 @@ spec: existingJobDeleted: description: |- ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. - The name of each job.bmc.tinkerbell.org object is the same, so only one can exist at a time. - Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per hardware. + The name of each job.bmc.tinkerbell.org object created by the controller is the same, so only one can exist at a time. + Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per Hardware/Machine.bmc.tinkerbell.org. This makes clean up easier and we dont just orphan jobs every time. type: boolean uid: description: |- - UID is the UID of the BMCJob associated with this workflow. - This is used to identify the unique job.bmc.tinkerbell.org object, as - all objects are created with the same name. + UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. + This is used to uniquely identify the job.bmc.tinkerbell.org object, as + all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. type: string type: object state: - description: State is the state of the workflow in Tinkerbell. + description: State is the current overall state of the Workflow. type: string tasks: - description: Tasks are the tasks to be completed + description: Tasks are the tasks to be run by the worker(s). items: description: Task represents a series of actions to be completed by a worker. properties: @@ -218,7 +208,7 @@ spec: templateRending: description: |- TemplateRendering indicates whether the template was rendered successfully. - Possible values are "successful" or "failed". + Possible values are "successful" or "failed" or "unknown". type: string type: object type: object From 2975038c2de4e2b47cb8aeebf1af2b4b31150bfb Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 26 Sep 2024 10:59:57 -0600 Subject: [PATCH 22/24] Update ToggleAllowNetboot* condition message: Signed-off-by: Jacob Weinstock --- internal/deprecated/workflow/reconciler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index aa0a40866..70098d0d6 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -120,7 +120,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco Type: v1alpha1.ToggleAllowNetbootFalse, Status: metav1.ConditionTrue, Reason: "Complete", - Message: "setting allowPXE to false", + Message: "set allowPXE to false", Time: &metav1.Time{Time: metav1.Now().UTC()}, }) if gerr := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); gerr != nil { @@ -262,7 +262,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, Type: v1alpha1.ToggleAllowNetbootTrue, Status: metav1.ConditionTrue, Reason: "Complete", - Message: "setting allowPXE to true", + Message: "set allowPXE to true", Time: &metav1.Time{Time: metav1.Now().UTC()}, }) if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { From 7084d481c11faab34c4b2747ee0d3f82a3e9a565 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 26 Sep 2024 15:11:26 -0600 Subject: [PATCH 23/24] Update naming and organization of status struct: Make the spec and status fields for boot options the same so they are logically correlated. Change global state from WorkflowStatePreparing to WorkflowStateWaiting. This follows Kubernetes Pod container states. https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-states Signed-off-by: Jacob Weinstock --- api/v1alpha1/workflow_methods.go | 2 +- api/v1alpha1/workflow_types.go | 41 ++++-- api/v1alpha1/zz_generated.deepcopy.go | 58 +++++--- .../crd/bases/tinkerbell.org_workflows.yaml | 52 +++---- internal/deprecated/workflow/bootops.go | 12 +- internal/deprecated/workflow/bootops_test.go | 134 +++++++++++------- internal/deprecated/workflow/reconciler.go | 33 ++--- .../deprecated/workflow/reconciler_test.go | 134 ------------------ internal/server/kubernetes_api_workflow.go | 6 +- 9 files changed, 201 insertions(+), 271 deletions(-) diff --git a/api/v1alpha1/workflow_methods.go b/api/v1alpha1/workflow_methods.go index 7e1e78493..9b1e875ff 100644 --- a/api/v1alpha1/workflow_methods.go +++ b/api/v1alpha1/workflow_methods.go @@ -60,7 +60,7 @@ func (w *Workflow) getTaskActionInfo() taskInfo { INNER: for ai, action := range task.Actions { // Find the first non-successful action - switch action.Status { //nolint:exhaustive // WorkflowStatePreparing is only used in Workflows not Actions. + switch action.Status { //nolint:exhaustive // WorkflowStateWaiting is only used in Workflows not Actions. case WorkflowStateSuccess: actionIndex++ continue diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 689759284..09a4d5a5b 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -12,15 +12,16 @@ func init() { type ( WorkflowState string WorkflowConditionType string + TemplateRendering string ) const ( - WorkflowStatePending = WorkflowState("STATE_PENDING") - WorkflowStateRunning = WorkflowState("STATE_RUNNING") - WorkflowStateFailed = WorkflowState("STATE_FAILED") - WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") - WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") - WorkflowStatePreparing = WorkflowState("STATE_PREPARING") + WorkflowStateWaiting = WorkflowState("STATE_WAITING") + WorkflowStatePending = WorkflowState("STATE_PENDING") + WorkflowStateRunning = WorkflowState("STATE_RUNNING") + WorkflowStateSuccess = WorkflowState("STATE_SUCCESS") + WorkflowStateFailed = WorkflowState("STATE_FAILED") + WorkflowStateTimeout = WorkflowState("STATE_TIMEOUT") NetbootJobFailed WorkflowConditionType = "NetbootJobFailed" NetbootJobComplete WorkflowConditionType = "NetbootJobComplete" @@ -30,6 +31,9 @@ const ( ToggleAllowNetbootTrue WorkflowConditionType = "AllowNetbootTrue" ToggleAllowNetbootFalse WorkflowConditionType = "AllowNetbootFalse" TemplateRenderedSuccess WorkflowConditionType = "TemplateRenderedSuccess" + + TemplateRenderingSuccessful TemplateRendering = "successful" + TemplateRenderingFailed TemplateRendering = "failed" ) // +kubebuilder:subresource:status @@ -71,12 +75,12 @@ type WorkflowSpec struct { // A mapping of template devices to hadware mac addresses. HardwareMap map[string]string `json:"hardwareMap,omitempty"` - // BootOpts are options that control the booting of Hardware. - BootOpts BootOpts `json:"bootOpts,omitempty"` + // BootOptions are options that control the booting of Hardware. + BootOptions BootOptions `json:"bootOptions,omitempty"` } -// BootOpts are options that control the booting of Hardware. -type BootOpts struct { +// BootOptions are options that control the booting of Hardware. +type BootOptions struct { // ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. // This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. // A HardwareRef must be provided. @@ -89,6 +93,13 @@ type BootOpts struct { OneTimeNetboot bool `json:"oneTimeNetboot,omitempty"` } +// BootOptionsStatus holds the state of any boot options. +type BootOptionsStatus struct { + // OneTimeNetboot holds the state of a specific job.bmc.tinkerbell.org object created. + // Only used when BootOptions.OneTimeNetboot is true. + OneTimeNetboot OneTimeNetbootStatus `json:"netbootJob,omitempty"` +} + // WorkflowStatus defines the observed state of a Workflow. type WorkflowStatus struct { // State is the current overall state of the Workflow. @@ -97,13 +108,12 @@ type WorkflowStatus struct { // CurrentAction is the action that is currently in the running state. CurrentAction string `json:"currentAction,omitempty"` - // Job holds the state of a specific job.bmc.tinkerbell.org object created. - // Only used when BootOpts.OneTimeNetboot is true. - Job JobStatus `json:"jobStatus,omitempty"` + // BootOptions holds the state of any boot options. + BootOptions BootOptionsStatus `json:"bootOptions,omitempty"` // TemplateRendering indicates whether the template was rendered successfully. // Possible values are "successful" or "failed" or "unknown". - TemplateRendering string `json:"templateRending,omitempty"` + TemplateRendering TemplateRendering `json:"templateRending,omitempty"` // GlobalTimeout represents the max execution time. GlobalTimeout int64 `json:"globalTimeout,omitempty"` @@ -120,7 +130,8 @@ type WorkflowStatus struct { Conditions []WorkflowCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } -type JobStatus struct { +// OneTimeNetbootStatus holds the state of a specific job.bmc.tinkerbell.org object created. +type OneTimeNetbootStatus struct { // UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. // This is used to uniquely identify the job.bmc.tinkerbell.org object, as // all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 0e057e10e..c436f887f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -63,16 +63,32 @@ func (in *Action) DeepCopy() *Action { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BootOpts) DeepCopyInto(out *BootOpts) { +func (in *BootOptions) DeepCopyInto(out *BootOptions) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootOpts. -func (in *BootOpts) DeepCopy() *BootOpts { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootOptions. +func (in *BootOptions) DeepCopy() *BootOptions { if in == nil { return nil } - out := new(BootOpts) + out := new(BootOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BootOptionsStatus) DeepCopyInto(out *BootOptionsStatus) { + *out = *in + out.OneTimeNetboot = in.OneTimeNetboot +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootOptionsStatus. +func (in *BootOptionsStatus) DeepCopy() *BootOptionsStatus { + if in == nil { + return nil + } + out := new(BootOptionsStatus) in.DeepCopyInto(out) return out } @@ -340,21 +356,6 @@ func (in *Interface) DeepCopy() *Interface { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JobStatus) DeepCopyInto(out *JobStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobStatus. -func (in *JobStatus) DeepCopy() *JobStatus { - if in == nil { - return nil - } - out := new(JobStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetadataCustom) DeepCopyInto(out *MetadataCustom) { *out = *in @@ -731,6 +732,21 @@ func (in *OSIE) DeepCopy() *OSIE { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OneTimeNetbootStatus) DeepCopyInto(out *OneTimeNetbootStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OneTimeNetbootStatus. +func (in *OneTimeNetbootStatus) DeepCopy() *OneTimeNetbootStatus { + if in == nil { + return nil + } + out := new(OneTimeNetbootStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in @@ -947,7 +963,7 @@ func (in *WorkflowSpec) DeepCopyInto(out *WorkflowSpec) { (*out)[key] = val } } - out.BootOpts = in.BootOpts + out.BootOptions = in.BootOptions } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSpec. @@ -963,7 +979,7 @@ func (in *WorkflowSpec) DeepCopy() *WorkflowSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { *out = *in - out.Job = in.Job + out.BootOptions = in.BootOptions if in.Tasks != nil { in, out := &in.Tasks, &out.Tasks *out = make([]Task, len(*in)) diff --git a/config/crd/bases/tinkerbell.org_workflows.yaml b/config/crd/bases/tinkerbell.org_workflows.yaml index 0f3b580b8..5eb69d478 100644 --- a/config/crd/bases/tinkerbell.org_workflows.yaml +++ b/config/crd/bases/tinkerbell.org_workflows.yaml @@ -55,8 +55,8 @@ spec: spec: description: WorkflowSpec defines the desired state of Workflow. properties: - bootOpts: - description: BootOpts are options that control the booting of Hardware. + bootOptions: + description: BootOptions are options that control the booting of Hardware. properties: oneTimeNetboot: description: |- @@ -86,6 +86,32 @@ spec: status: description: WorkflowStatus defines the observed state of a Workflow. properties: + bootOptions: + description: BootOptions holds the state of any boot options. + properties: + netbootJob: + description: |- + OneTimeNetboot holds the state of a specific job.bmc.tinkerbell.org object created. + Only used when BootOptions.OneTimeNetboot is true. + properties: + complete: + description: Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. + type: boolean + existingJobDeleted: + description: |- + ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. + The name of each job.bmc.tinkerbell.org object created by the controller is the same, so only one can exist at a time. + Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per Hardware/Machine.bmc.tinkerbell.org. + This makes clean up easier and we dont just orphan jobs every time. + type: boolean + uid: + description: |- + UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. + This is used to uniquely identify the job.bmc.tinkerbell.org object, as + all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. + type: string + type: object + type: object conditions: description: Conditions are the latest available observations of an object's current state. items: @@ -120,28 +146,6 @@ spec: description: GlobalTimeout represents the max execution time. format: int64 type: integer - jobStatus: - description: |- - Job holds the state of a specific job.bmc.tinkerbell.org object created. - Only used when BootOpts.OneTimeNetboot is true. - properties: - complete: - description: Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. - type: boolean - existingJobDeleted: - description: |- - ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. - The name of each job.bmc.tinkerbell.org object created by the controller is the same, so only one can exist at a time. - Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per Hardware/Machine.bmc.tinkerbell.org. - This makes clean up easier and we dont just orphan jobs every time. - type: boolean - uid: - description: |- - UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. - This is used to uniquely identify the job.bmc.tinkerbell.org object, as - all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. - type: string - type: object state: description: State is the current overall state of the Workflow. type: string diff --git a/internal/deprecated/workflow/bootops.go b/internal/deprecated/workflow/bootops.go index 0a62a0855..193995899 100644 --- a/internal/deprecated/workflow/bootops.go +++ b/internal/deprecated/workflow/bootops.go @@ -20,7 +20,7 @@ const ( // handleExistingJob ensures that an existing job.bmc.tinkerbell.org is removed. func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { - if wf.Status.Job.ExistingJobDeleted { + if wf.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { return reconcile.Result{}, nil } name := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) @@ -36,16 +36,16 @@ func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workf } return reconcile.Result{Requeue: true}, nil } - wf.Status.Job.ExistingJobDeleted = true + wf.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted = true return reconcile.Result{Requeue: true}, nil } func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { - if wf.Status.Job.UID == "" && wf.Status.Job.ExistingJobDeleted { + if wf.Status.BootOptions.OneTimeNetboot.UID == "" && wf.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { existingJob := &rufio.Job{} if err := cc.Get(ctx, client.ObjectKey{Name: fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef), Namespace: wf.Namespace}, existingJob); err == nil { - wf.Status.Job.UID = existingJob.GetUID() + wf.Status.BootOptions.OneTimeNetboot.UID = existingJob.GetUID() return reconcile.Result{Requeue: true}, nil } hw := &v1alpha1.Hardware{ObjectMeta: metav1.ObjectMeta{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}} @@ -80,7 +80,7 @@ func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workf } func handleJobComplete(ctx context.Context, cc client.Client, wf *v1alpha1.Workflow) (reconcile.Result, error) { - if !wf.Status.Job.Complete && wf.Status.Job.UID != "" && wf.Status.Job.ExistingJobDeleted { + if !wf.Status.BootOptions.OneTimeNetboot.Complete && wf.Status.BootOptions.OneTimeNetboot.UID != "" && wf.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { existingJob := &rufio.Job{} jobName := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) if err := cc.Get(ctx, client.ObjectKey{Name: jobName, Namespace: wf.Namespace}, existingJob); err != nil { @@ -105,7 +105,7 @@ func handleJobComplete(ctx context.Context, cc client.Client, wf *v1alpha1.Workf Time: &metav1.Time{Time: metav1.Now().UTC()}, }) wf.Status.State = v1alpha1.WorkflowStatePending - wf.Status.Job.Complete = true + wf.Status.BootOptions.OneTimeNetboot.Complete = true return reconcile.Result{Requeue: true}, nil } if !wf.Status.HasCondition(v1alpha1.NetbootJobRunning, metav1.ConditionTrue) { diff --git a/internal/deprecated/workflow/bootops_test.go b/internal/deprecated/workflow/bootops_test.go index 00e639565..19c4e3216 100644 --- a/internal/deprecated/workflow/bootops_test.go +++ b/internal/deprecated/workflow/bootops_test.go @@ -35,8 +35,10 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: false, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: false, + }, }, }, }, @@ -49,8 +51,10 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: false, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: false, + }, }, }, }, @@ -72,7 +76,9 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{}, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{}, + }, }, }, wantWorkflow: &v1alpha1.Workflow{ @@ -84,8 +90,10 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + }, }, }, }, @@ -101,8 +109,10 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + }, }, }, }, @@ -115,8 +125,10 @@ func TestHandleExistingJob(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + }, }, }, }, @@ -164,9 +176,11 @@ func TestHandleJobCreation(t *testing.T) { Namespace: "default", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + UID: uid, + }, }, }, }, @@ -176,9 +190,11 @@ func TestHandleJobCreation(t *testing.T) { Namespace: "default", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + UID: uid, + }, }, }, }, @@ -194,8 +210,10 @@ func TestHandleJobCreation(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + }, }, }, }, @@ -208,8 +226,10 @@ func TestHandleJobCreation(t *testing.T) { HardwareRef: "machine1", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + ExistingJobDeleted: true, + }, }, Conditions: []v1alpha1.WorkflowCondition{ {Type: v1alpha1.NetbootJobSetupComplete, Status: v1.ConditionTrue, Reason: "Created", Message: "job created"}, @@ -301,8 +321,10 @@ func TestHandleJobComplete(t *testing.T) { Namespace: "default", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: true, + }, }, }, }, @@ -312,8 +334,10 @@ func TestHandleJobComplete(t *testing.T) { Namespace: "default", }, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: true, + }, }, }, }, @@ -327,10 +351,12 @@ func TestHandleJobComplete(t *testing.T) { }, Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: false, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, }, }, }, @@ -341,10 +367,12 @@ func TestHandleJobComplete(t *testing.T) { }, Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: false, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, }, Conditions: []v1alpha1.WorkflowCondition{ {Type: v1alpha1.NetbootJobRunning, Status: v1.ConditionTrue, Reason: "Running", Message: "one time netboot job running"}, @@ -372,10 +400,12 @@ func TestHandleJobComplete(t *testing.T) { }, Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: false, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, }, }, }, @@ -386,10 +416,12 @@ func TestHandleJobComplete(t *testing.T) { }, Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: false, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, }, Conditions: []v1alpha1.WorkflowCondition{ {Type: v1alpha1.NetbootJobFailed, Status: v1.ConditionTrue, Reason: "Error", Message: "one time netboot job failed"}, @@ -418,10 +450,12 @@ func TestHandleJobComplete(t *testing.T) { }, Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ - Job: v1alpha1.JobStatus{ - Complete: false, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: false, + UID: uid, + ExistingJobDeleted: true, + }, }, }, }, @@ -433,10 +467,12 @@ func TestHandleJobComplete(t *testing.T) { Spec: v1alpha1.WorkflowSpec{HardwareRef: "machine1"}, Status: v1alpha1.WorkflowStatus{ State: v1alpha1.WorkflowStatePending, - Job: v1alpha1.JobStatus{ - Complete: true, - UID: uid, - ExistingJobDeleted: true, + BootOptions: v1alpha1.BootOptionsStatus{ + OneTimeNetboot: v1alpha1.OneTimeNetbootStatus{ + Complete: true, + UID: uid, + ExistingJobDeleted: true, + }, }, Conditions: []v1alpha1.WorkflowCondition{ {Type: v1alpha1.NetbootJobComplete, Status: v1.ConditionTrue, Reason: "Complete", Message: "one time netboot job completed"}, diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 70098d0d6..8448c214a 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -17,10 +17,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -const ( - failed = "failed" -) - // Reconciler is a type for managing Workflows. type Reconciler struct { client ctrlclient.Client @@ -77,9 +73,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco if ca != "" && wflow.Status.CurrentAction != ca { wflow.Status.CurrentAction = ca } - case v1alpha1.WorkflowStatePreparing: + case v1alpha1.WorkflowStateWaiting: // make sure any existing job is deleted - if !wflow.Status.Job.ExistingJobDeleted { + if !wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleExistingJob(ctx, r.client, wflow) // Patch any changes, regardless of errors if !equality.Semantic.DeepEqual(wflow, stored) { @@ -91,7 +87,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } // create a new job - if wflow.Status.Job.UID == "" && wflow.Status.Job.ExistingJobDeleted { + if wflow.Status.BootOptions.OneTimeNetboot.UID == "" && wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleJobCreation(ctx, r.client, wflow) // Patch any changes, regardless of errors if !equality.Semantic.DeepEqual(wflow, stored) { @@ -103,7 +99,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } // check if the job is complete - if !wflow.Status.Job.Complete && wflow.Status.Job.UID != "" && wflow.Status.Job.ExistingJobDeleted { + if !wflow.Status.BootOptions.OneTimeNetboot.Complete && wflow.Status.BootOptions.OneTimeNetboot.UID != "" && wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleJobComplete(ctx, r.client, wflow) // Patch any changes, regardless of errors if !equality.Semantic.DeepEqual(wflow, stored) { @@ -114,7 +110,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return rc, err } case v1alpha1.WorkflowStateSuccess: - if wflow.Spec.BootOpts.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootFalse, metav1.ConditionTrue) { + if wflow.Spec.BootOptions.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootFalse, metav1.ConditionTrue) { // handle updating hardware allowPXE to false wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootFalse, @@ -144,6 +140,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) } } + return resp, err } @@ -165,7 +162,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, if errors.IsNotFound(err) { // Throw an error to raise awareness and take advantage of immediate requeue. logger.Error(err, "error getting Template object in processNewWorkflow function") - stored.Status.TemplateRendering = failed + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -179,7 +176,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, stored.Namespace, ) } - stored.Status.TemplateRendering = failed + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -199,7 +196,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, &hardware) if err != nil && !errors.IsNotFound(err) { logger.Error(err, "error getting Hardware object in processNewWorkflow function") - stored.Status.TemplateRendering = failed + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -212,7 +209,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, if stored.Spec.HardwareRef != "" && errors.IsNotFound(err) { logger.Error(err, "hardware not found in processNewWorkflow function") - stored.Status.TemplateRendering = failed + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -234,7 +231,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, tinkWf, err := renderTemplateHardware(stored.Name, ptr.StringValue(tpl.Spec.Data), data) if err != nil { - stored.Status.TemplateRendering = failed + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionFalse, @@ -247,7 +244,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // populate Task and Action data stored.Status = *YAMLToStatus(tinkWf) - stored.Status.TemplateRendering = "successful" + stored.Status.TemplateRendering = v1alpha1.TemplateRenderingSuccessful stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.TemplateRenderedSuccess, Status: metav1.ConditionTrue, @@ -257,7 +254,7 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, }) // set hardware allowPXE if requested. - if stored.Spec.BootOpts.ToggleAllowNetboot { + if stored.Spec.BootOptions.ToggleAllowNetboot { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootTrue, Status: metav1.ConditionTrue, @@ -278,8 +275,8 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, } // netboot the hardware if requested - if stored.Spec.BootOpts.OneTimeNetboot { - stored.Status.State = v1alpha1.WorkflowStatePreparing + if stored.Spec.BootOptions.OneTimeNetboot { + stored.Status.State = v1alpha1.WorkflowStateWaiting return reconcile.Result{Requeue: true}, err } diff --git a/internal/deprecated/workflow/reconciler_test.go b/internal/deprecated/workflow/reconciler_test.go index 782c6b304..884ce3d3c 100644 --- a/internal/deprecated/workflow/reconciler_test.go +++ b/internal/deprecated/workflow/reconciler_test.go @@ -207,140 +207,6 @@ func TestHandleHardwareAllowPXE(t *testing.T) { } } -/* -func TestHandleOneTimeNetboot(t *testing.T) { - tests := map[string]struct { - OriginalHardware *v1alpha1.Hardware - OriginalWorkflow *v1alpha1.Workflow - OriginalJob *rufio.Job - WantWorkflow *v1alpha1.Workflow - WantResult reconcile.Result - WantError error - }{ - "no bmc reference": { - OriginalHardware: &v1alpha1.Hardware{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine1", - }, - }, - WantResult: reconcile.Result{}, - WantError: fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", "machine1"), - }, - "delete existing bmc job": { - OriginalHardware: &v1alpha1.Hardware{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine1", - Namespace: "default", - }, - Spec: v1alpha1.HardwareSpec{ - BMCRef: &v1.TypedLocalObjectReference{ - Name: "bmc1", - Kind: "machine.bmc.tinkerbell.org", - }, - }, - }, - OriginalWorkflow: &v1alpha1.Workflow{ - Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePreparing, - }, - }, - OriginalJob: &rufio.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(bmcJobName, "machine1"), - Namespace: "default", - }, - Spec: rufio.JobSpec{}, - Status: rufio.JobStatus{}, - }, - WantWorkflow: &v1alpha1.Workflow{ - Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePreparing, - Conditions: []v1alpha1.WorkflowCondition{ - { - Type: v1alpha1.NetbootJobSetupComplete, - Status: metav1.ConditionTrue, - Reason: "Deleted", - Message: "existing job deleted", - }, - }, - }, - }, - WantResult: reconcile.Result{}, - }, - "create bmc job": { - OriginalHardware: &v1alpha1.Hardware{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine2", - Namespace: "default", - }, - Spec: v1alpha1.HardwareSpec{ - BMCRef: &v1.TypedLocalObjectReference{ - Name: "bmc2", - Kind: "machine.bmc.tinkerbell.org", - }, - Interfaces: []v1alpha1.Interface{ - { - DHCP: &v1alpha1.DHCP{ - UEFI: true, - }, - }, - }, - }, - }, - OriginalWorkflow: &v1alpha1.Workflow{ - Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePreparing, - }, - }, - WantWorkflow: &v1alpha1.Workflow{ - Status: v1alpha1.WorkflowStatus{ - State: v1alpha1.WorkflowStatePreparing, - Conditions: []v1alpha1.WorkflowCondition{ - { - Type: v1alpha1.NetbootJobSetupComplete, - Status: metav1.ConditionTrue, - Reason: "Created", - Message: "job created", - }, - }, - }, - }, - WantResult: reconcile.Result{}, - }, - } - - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - client := GetFakeClientBuilder().Build() - if tt.OriginalHardware.Spec.BMCRef != nil { - runtimescheme := runtime.NewScheme() - rufio.AddToScheme(runtimescheme) - v1alpha1.AddToScheme(runtimescheme) - clientBulider := GetFakeClientBuilder().WithScheme(runtimescheme) - if tt.OriginalJob != nil { - clientBulider.WithRuntimeObjects(tt.OriginalJob) - } - client = clientBulider.Build() - } - r, err := handleOneTimeNetboot(context.Background(), client, tt.OriginalHardware, tt.OriginalWorkflow) - - if diff := cmp.Diff(tt.WantError, err, cmp.Comparer(func(a, b error) bool { - return a.Error() == b.Error() - })); diff != "" { - t.Fatalf("unexpected error diff: %s", diff) - } - - if diff := cmp.Diff(tt.WantResult, r); diff != "" { - t.Fatalf("unexpected result diff: %s", diff) - } - if diff := cmp.Diff(tt.WantWorkflow, tt.OriginalWorkflow, cmpopts.IgnoreFields(v1alpha1.WorkflowCondition{}, "Time")); diff != "" { - t.Fatalf("unexpected workflow diff: %s", diff) - } - }) - } -} -*/ - func TestReconcile(t *testing.T) { cases := []struct { name string diff --git a/internal/server/kubernetes_api_workflow.go b/internal/server/kubernetes_api_workflow.go index bbd205be4..0dc557422 100644 --- a/internal/server/kubernetes_api_workflow.go +++ b/internal/server/kubernetes_api_workflow.go @@ -77,10 +77,10 @@ func (s *KubernetesBackedServer) GetWorkflowContexts(req *proto.WorkflowContextR return err } for _, wf := range wflows { - // Don't serve Actions when in a v1alpha1.WorkflowStatePreparing state. + // Don't serve Actions when in a v1alpha1.WorkflowStateWaiting state. // This is to prevent the worker from starting Actions before Workflow boot options are performed. - if wf.Spec.BootOpts.ToggleAllowNetboot || wf.Spec.BootOpts.OneTimeNetboot { - if wf.Status.State == v1alpha1.WorkflowStatePreparing { + if wf.Spec.BootOptions.ToggleAllowNetboot || wf.Spec.BootOptions.OneTimeNetboot { + if wf.Status.State == v1alpha1.WorkflowStateWaiting { continue } } From ff45778739c61a6a0ad4c0a167b96074c65d188c Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Sat, 28 Sep 2024 20:22:09 -0600 Subject: [PATCH 24/24] Improve readability: Return in each switch case. Make function for patching status. Reorganize where some conditions were being set. Replace !errors.IsNotFound with ctrlclient.IgnoreNotFound in order to improve readability. Signed-off-by: Jacob Weinstock --- docs/Workflow.md | 28 +++++ internal/deprecated/workflow/bootops.go | 10 +- internal/deprecated/workflow/reconciler.go | 126 ++++++++++----------- 3 files changed, 89 insertions(+), 75 deletions(-) create mode 100644 docs/Workflow.md diff --git a/docs/Workflow.md b/docs/Workflow.md new file mode 100644 index 000000000..b8a140b42 --- /dev/null +++ b/docs/Workflow.md @@ -0,0 +1,28 @@ +# The Workflow custom resource + +This doc provides details for different parts of the Workflow custom resource. + +## Spec + +### BootOptions + +The `spec.bootOptions` object contains optional functionality that will run before a Workflow and triggers handling of different Hardware booting capabilities. + +## Status + +### State + +There are several states that a Workflow can be in: + +`STATE_WAITING` - +`STATE_PENDING` - +`STATE_RUNNING` - +`STATE_SUCCESS` - +`STATE_FAILED` - +`STATE_TIMEOUT` - + +### OneTimeNetboot + +### TemplateRendering + +### Conditions diff --git a/internal/deprecated/workflow/bootops.go b/internal/deprecated/workflow/bootops.go index 193995899..76e55a35d 100644 --- a/internal/deprecated/workflow/bootops.go +++ b/internal/deprecated/workflow/bootops.go @@ -7,7 +7,6 @@ import ( rufio "github.com/tinkerbell/rufio/api/v1alpha1" "github.com/tinkerbell/tink/api/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -25,13 +24,13 @@ func handleExistingJob(ctx context.Context, cc client.Client, wf *v1alpha1.Workf } name := fmt.Sprintf(bmcJobName, wf.Spec.HardwareRef) namespace := wf.Namespace - if err := cc.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, &rufio.Job{}); (err != nil && !errors.IsNotFound(err)) || err == nil { + if err := cc.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, &rufio.Job{}); client.IgnoreNotFound(err) != nil || err == nil { existingJob := &rufio.Job{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}} opts := []client.DeleteOption{ client.GracePeriodSeconds(0), client.PropagationPolicy(metav1.DeletePropagationForeground), } - if err := cc.Delete(ctx, existingJob, opts...); err != nil { + if err := cc.Delete(ctx, existingJob, opts...); client.IgnoreNotFound(err) != nil { return reconcile.Result{}, fmt.Errorf("error deleting job.bmc.tinkerbell.org object: %w", err) } return reconcile.Result{Requeue: true}, nil @@ -49,8 +48,8 @@ func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workf return reconcile.Result{Requeue: true}, nil } hw := &v1alpha1.Hardware{ObjectMeta: metav1.ObjectMeta{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}} - if gerr := cc.Get(ctx, client.ObjectKey{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}, hw); gerr != nil { - return reconcile.Result{}, fmt.Errorf("error getting hardware %s: %w", wf.Spec.HardwareRef, gerr) + if err := cc.Get(ctx, client.ObjectKey{Name: wf.Spec.HardwareRef, Namespace: wf.Namespace}, hw); err != nil { + return reconcile.Result{}, fmt.Errorf("error getting hardware %s: %w", wf.Spec.HardwareRef, err) } if hw.Spec.BMCRef == nil { return reconcile.Result{}, fmt.Errorf("hardware %s does not have a BMC, cannot perform one time netboot", hw.Name) @@ -72,7 +71,6 @@ func handleJobCreation(ctx context.Context, cc client.Client, wf *v1alpha1.Workf Message: "job created", Time: &metav1.Time{Time: metav1.Now().UTC()}, }) - return reconcile.Result{Requeue: true}, nil } diff --git a/internal/deprecated/workflow/reconciler.go b/internal/deprecated/workflow/reconciler.go index 8448c214a..52781dc9b 100644 --- a/internal/deprecated/workflow/reconciler.go +++ b/internal/deprecated/workflow/reconciler.go @@ -2,6 +2,7 @@ package workflow import ( "context" + serrors "errors" "fmt" "time" @@ -57,91 +58,83 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco if !stored.DeletionTimestamp.IsZero() { return reconcile.Result{}, nil } + wflow := stored.DeepCopy() - var ( - resp reconcile.Result - err error - ) switch wflow.Status.State { case "": - resp, err = r.processNewWorkflow(ctx, logger, wflow) - case v1alpha1.WorkflowStateRunning: - resp = r.processRunningWorkflow(ctx, wflow) - // set the current action in the status - ca := runningAction(wflow) - if ca != "" && wflow.Status.CurrentAction != ca { - wflow.Status.CurrentAction = ca - } + resp, err := r.processNewWorkflow(ctx, logger, wflow) + + return resp, serrors.Join(err, mergePatchsStatus(ctx, r.client, stored, wflow)) case v1alpha1.WorkflowStateWaiting: // make sure any existing job is deleted if !wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleExistingJob(ctx, r.client, wflow) - // Patch any changes, regardless of errors - if !equality.Semantic.DeepEqual(wflow, stored) { - if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { - err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) - } - } - return rc, err + + return rc, serrors.Join(err, mergePatchsStatus(ctx, r.client, stored, wflow)) } // create a new job if wflow.Status.BootOptions.OneTimeNetboot.UID == "" && wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleJobCreation(ctx, r.client, wflow) - // Patch any changes, regardless of errors - if !equality.Semantic.DeepEqual(wflow, stored) { - if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { - err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) - } - } - return rc, err + + return rc, serrors.Join(err, mergePatchsStatus(ctx, r.client, stored, wflow)) } // check if the job is complete if !wflow.Status.BootOptions.OneTimeNetboot.Complete && wflow.Status.BootOptions.OneTimeNetboot.UID != "" && wflow.Status.BootOptions.OneTimeNetboot.ExistingJobDeleted { rc, err := handleJobComplete(ctx, r.client, wflow) - // Patch any changes, regardless of errors - if !equality.Semantic.DeepEqual(wflow, stored) { - if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { - err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) - } - } - return rc, err + + return rc, serrors.Join(err, mergePatchsStatus(ctx, r.client, stored, wflow)) + } + case v1alpha1.WorkflowStateRunning: + r.processRunningWorkflow(wflow) + // set the current action in the status + ca := runningAction(wflow) + if ca != "" && wflow.Status.CurrentAction != ca { + wflow.Status.CurrentAction = ca } + + return reconcile.Result{}, mergePatchsStatus(ctx, r.client, stored, wflow) + case v1alpha1.WorkflowStatePending, v1alpha1.WorkflowStateTimeout, v1alpha1.WorkflowStateFailed: + return reconcile.Result{}, nil case v1alpha1.WorkflowStateSuccess: if wflow.Spec.BootOptions.ToggleAllowNetboot && !wflow.Status.HasCondition(v1alpha1.ToggleAllowNetbootFalse, metav1.ConditionTrue) { // handle updating hardware allowPXE to false - wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootFalse, - Status: metav1.ConditionTrue, - Reason: "Complete", - Message: "set allowPXE to false", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }) - if gerr := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); gerr != nil { + if err := handleHardwareAllowPXE(ctx, r.client, wflow, nil, false); err != nil { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootFalse, Status: metav1.ConditionTrue, Reason: "Error", - Message: fmt.Sprintf("error setting Allow PXE: %v", gerr), + Message: fmt.Sprintf("error setting Allow PXE: %v", err), Time: &metav1.Time{Time: metav1.Now().UTC()}, }) - err = gerr + return reconcile.Result{}, serrors.Join(err, mergePatchsStatus(ctx, r.client, stored, wflow)) } + wflow.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootFalse, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "set allowPXE to false", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) + + return reconcile.Result{}, mergePatchsStatus(ctx, r.client, stored, wflow) } - default: - return resp, nil } + return reconcile.Result{}, nil +} + +// mergePatchsStatus merges an updated Workflow with an original Workflow and patches the Status object via the client (cc). +func mergePatchsStatus(ctx context.Context, cc ctrlclient.Client, original, updated *v1alpha1.Workflow) error { // Patch any changes, regardless of errors - if !equality.Semantic.DeepEqual(wflow, stored) { - if perr := r.client.Status().Patch(ctx, wflow, ctrlclient.MergeFrom(stored)); perr != nil { - err = fmt.Errorf("error patching workflow %s, %w", wflow.Name, perr) + if !equality.Semantic.DeepEqual(updated, original) { + if err := cc.Status().Patch(ctx, updated, ctrlclient.MergeFrom(original)); err != nil { + return fmt.Errorf("error patching status of workflow: %s, error: %w", updated.Name, err) } } - - return resp, err + return nil } func runningAction(wf *v1alpha1.Workflow) string { @@ -187,14 +180,9 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, return reconcile.Result{}, err } - data := make(map[string]interface{}) - for key, val := range stored.Spec.HardwareMap { - data[key] = val - } - var hardware v1alpha1.Hardware err := r.client.Get(ctx, ctrlclient.ObjectKey{Name: stored.Spec.HardwareRef, Namespace: stored.Namespace}, &hardware) - if err != nil && !errors.IsNotFound(err) { + if ctrlclient.IgnoreNotFound(err) != nil { logger.Error(err, "error getting Hardware object in processNewWorkflow function") stored.Status.TemplateRendering = v1alpha1.TemplateRenderingFailed stored.Status.SetCondition(v1alpha1.WorkflowCondition{ @@ -224,10 +212,12 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, ) } - if err == nil { - contract := toTemplateHardwareData(hardware) - data["Hardware"] = contract + data := make(map[string]interface{}) + for key, val := range stored.Spec.HardwareMap { + data[key] = val } + contract := toTemplateHardwareData(hardware) + data["Hardware"] = contract tinkWf, err := renderTemplateHardware(stored.Name, ptr.StringValue(tpl.Spec.Data), data) if err != nil { @@ -255,13 +245,6 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, // set hardware allowPXE if requested. if stored.Spec.BootOptions.ToggleAllowNetboot { - stored.Status.SetCondition(v1alpha1.WorkflowCondition{ - Type: v1alpha1.ToggleAllowNetbootTrue, - Status: metav1.ConditionTrue, - Reason: "Complete", - Message: "set allowPXE to true", - Time: &metav1.Time{Time: metav1.Now().UTC()}, - }) if err := handleHardwareAllowPXE(ctx, r.client, stored, &hardware, true); err != nil { stored.Status.SetCondition(v1alpha1.WorkflowCondition{ Type: v1alpha1.ToggleAllowNetbootTrue, @@ -272,6 +255,13 @@ func (r *Reconciler) processNewWorkflow(ctx context.Context, logger logr.Logger, }) return reconcile.Result{}, err } + stored.Status.SetCondition(v1alpha1.WorkflowCondition{ + Type: v1alpha1.ToggleAllowNetbootTrue, + Status: metav1.ConditionTrue, + Reason: "Complete", + Message: "set allowPXE to true", + Time: &metav1.Time{Time: metav1.Now().UTC()}, + }) } // netboot the hardware if requested @@ -315,7 +305,7 @@ func toTemplateHardwareData(hardware v1alpha1.Hardware) templateHardwareData { return contract } -func (r *Reconciler) processRunningWorkflow(_ context.Context, stored *v1alpha1.Workflow) reconcile.Result { //nolint:unparam // This is the way controller runtime works. +func (r *Reconciler) processRunningWorkflow(stored *v1alpha1.Workflow) { // Check for global timeout expiration if r.nowFunc().After(stored.GetStartTime().Add(time.Duration(stored.Status.GlobalTimeout) * time.Second)) { stored.Status.State = v1alpha1.WorkflowStateTimeout @@ -336,6 +326,4 @@ func (r *Reconciler) processRunningWorkflow(_ context.Context, stored *v1alpha1. } } } - - return reconcile.Result{} }