diff --git a/Makefile b/Makefile index 87e3c78..fa07ba3 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,7 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi CONTROLLER_GEN = $(shell pwd)/bin/controller-gen .PHONY: controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.13.0) KUSTOMIZE = $(shell pwd)/bin/kustomize .PHONY: kustomize diff --git a/api/v1alpha1/machine.go b/api/v1alpha1/machine.go index e9cbdf2..ed0defd 100644 --- a/api/v1alpha1/machine.go +++ b/api/v1alpha1/machine.go @@ -49,6 +49,28 @@ const ( type MachineSpec struct { // Connection contains connection data for a Baseboard Management Controller. Connection Connection `json:"connection"` + + // ProviderOptions contains provider specific options. + // +optional + ProviderOptions ProviderOptions `json:"providerOptions,omitempty"` +} + +type ProviderOptions struct { + // IntelAMT contains the options to customize the IntelAMT provider. + // +optional + IntelAMT *IntelAMTOptions `json:"intelAMT"` + + // IPMITOOL contains the options to customize the Ipmitool provider. + // +optional + IPMITOOL *IPMITOOLOptions `json:"ipmitool"` + + // Redfish contains the options to customize the Redfish provider. + // +optional + Redfish *RedfishOptions `json:"redfish"` + + // RPC contains the options to customize the RPC provider. + // +optional + RPC *RPCOptions `json:"rpc"` } // Connection contains connection data for a Baseboard Management Controller. diff --git a/api/v1alpha1/provider_opts.go b/api/v1alpha1/provider_opts.go new file mode 100644 index 0000000..ba2daf2 --- /dev/null +++ b/api/v1alpha1/provider_opts.go @@ -0,0 +1,94 @@ +package v1alpha1 + +import ( + "net/http" + + corev1 "k8s.io/api/core/v1" +) + +// RedfishOptions contains the redfish provider specific options. +type RedfishOptions struct { + // Port that redfish will use for calls. + Port int `json:"port"` +} + +// IPMITOOLOptions contains the ipmitool provider specific options. +type IPMITOOLOptions struct { + // Port that ipmitool will use for calls. + Port int `json:"port"` + // CipherSuite that ipmitool will use for calls. + CipherSuite string `json:"cipherSuite"` +} + +// IntelAMTOptions contains the intelAMT provider specific options. +type IntelAMTOptions struct { + // Port that intelAMT will use for calls. + Port int `json:"port"` +} + +// HMACAlgorithm is a type for HMAC algorithms. +type HMACAlgorithm string + +// HMACSecrets holds per Algorithm slice secrets. +// These secrets will be used to create HMAC signatures. +type HMACSecrets map[HMACAlgorithm][]corev1.SecretReference + +// RPCOptions defines the configurable options to use when sending rpc notifications. +type RPCOptions struct { + // ConsumerURL is the URL where an rpc consumer/listener is running + // and to which we will send and receive all notifications. + ConsumerURL string `json:"consumerURL"` + // LogNotificationsDisabled determines whether responses from rpc consumer/listeners will be logged or not. + LogNotificationsDisabled bool `json:"logNotificationsDisabled"` + // Request is the options used to create the rpc HTTP request. + Request RequestOpts `json:"request"` + // Signature is the options used for adding an HMAC signature to an HTTP request. + Signature SignatureOpts `json:"signature"` + // HMAC is the options used to create a HMAC signature. + HMAC HMACOpts `json:"hmac"` + // Experimental options. + Experimental ExperimentalOpts `json:"experimental"` +} + +// RequestOpts are the options used when creating an HTTP request. +type RequestOpts struct { + // HTTPContentType is the content type to use for the rpc request notification. + HTTPContentType string `json:"httpContentType"` + // HTTPMethod is the HTTP method to use for the rpc request notification. + HTTPMethod string `json:"httpMethod"` + // StaticHeaders are predefined headers that will be added to every request. + StaticHeaders http.Header `json:"staticHeaders"` + // TimestampFormat is the time format for the timestamp header. + TimestampFormat string `json:"timestampFormat"` + // TimestampHeader is the header name that should contain the timestamp. Example: X-BMCLIB-Timestamp + TimestampHeader string `json:"timestampHeader"` +} + +// SignatureOpts are the options used for adding an HMAC signature to an HTTP request. +type SignatureOpts struct { + // HeaderName is the header name that should contain the signature(s). Example: X-BMCLIB-Signature + HeaderName string `json:"headerName"` + // AppendAlgoToHeaderDisabled decides whether to append the algorithm to the signature header or not. + // Example: X-BMCLIB-Signature becomes X-BMCLIB-Signature-256 + // When set to true, a header will be added for each algorithm. Example: X-BMCLIB-Signature-256 and X-BMCLIB-Signature-512 + AppendAlgoToHeaderDisabled bool `json:"appendAlgoToHeaderDisabled"` + // IncludedPayloadHeaders are headers whose values will be included in the signature payload. Example: X-BMCLIB-My-Custom-Header + // All headers will be deduplicated. + IncludedPayloadHeaders []string `json:"includedPayloadHeaders"` +} + +// HMACOpts are the options used to create an HMAC signature. +type HMACOpts struct { + // PrefixSigDisabled determines whether the algorithm will be prefixed to the signature. Example: sha256=abc123 + PrefixSigDisabled bool `json:"prefixSigDisabled"` + // Secrets are a map of algorithms to secrets used for signing. + Secrets HMACSecrets `json:"secrets"` +} + +// ExperimentalOpts are options we're still learning about and should be used carefully. +type ExperimentalOpts struct { + // CustomRequestPayload must be in json. + CustomRequestPayload string `json:"customRequestPayload"` + // DotPath is the path to the json object where the bmclib RequestPayload{} struct will be embedded. For example: object.data.body + DotPath string `json:"dotPath"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 561326b..bbdba00 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright 2022 Tinkerbell. @@ -22,6 +21,9 @@ limitations under the License. package v1alpha1 import ( + "net/http" + + v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -71,6 +73,112 @@ func (in *Connection) DeepCopy() *Connection { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExperimentalOpts) DeepCopyInto(out *ExperimentalOpts) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExperimentalOpts. +func (in *ExperimentalOpts) DeepCopy() *ExperimentalOpts { + if in == nil { + return nil + } + out := new(ExperimentalOpts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HMACOpts) DeepCopyInto(out *HMACOpts) { + *out = *in + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make(HMACSecrets, len(*in)) + for key, val := range *in { + var outVal []v1.SecretReference + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]v1.SecretReference, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HMACOpts. +func (in *HMACOpts) DeepCopy() *HMACOpts { + if in == nil { + return nil + } + out := new(HMACOpts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in HMACSecrets) DeepCopyInto(out *HMACSecrets) { + { + in := &in + *out = make(HMACSecrets, len(*in)) + for key, val := range *in { + var outVal []v1.SecretReference + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]v1.SecretReference, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HMACSecrets. +func (in HMACSecrets) DeepCopy() HMACSecrets { + if in == nil { + return nil + } + out := new(HMACSecrets) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPMITOOLOptions) DeepCopyInto(out *IPMITOOLOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPMITOOLOptions. +func (in *IPMITOOLOptions) DeepCopy() *IPMITOOLOptions { + if in == nil { + return nil + } + out := new(IPMITOOLOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntelAMTOptions) DeepCopyInto(out *IntelAMTOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntelAMTOptions. +func (in *IntelAMTOptions) DeepCopy() *IntelAMTOptions { + if in == nil { + return nil + } + out := new(IntelAMTOptions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Job) DeepCopyInto(out *Job) { *out = *in @@ -201,7 +309,7 @@ func (in *Machine) DeepCopyInto(out *Machine) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) } @@ -290,6 +398,7 @@ func (in *MachineRef) DeepCopy() *MachineRef { func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { *out = *in out.Connection = in.Connection + in.ProviderOptions.DeepCopyInto(&out.ProviderOptions) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. @@ -344,6 +453,126 @@ func (in *OneTimeBootDeviceAction) DeepCopy() *OneTimeBootDeviceAction { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProviderOptions) DeepCopyInto(out *ProviderOptions) { + *out = *in + if in.IntelAMT != nil { + in, out := &in.IntelAMT, &out.IntelAMT + *out = new(IntelAMTOptions) + **out = **in + } + if in.IPMITOOL != nil { + in, out := &in.IPMITOOL, &out.IPMITOOL + *out = new(IPMITOOLOptions) + **out = **in + } + if in.Redfish != nil { + in, out := &in.Redfish, &out.Redfish + *out = new(RedfishOptions) + **out = **in + } + if in.RPC != nil { + in, out := &in.RPC, &out.RPC + *out = new(RPCOptions) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderOptions. +func (in *ProviderOptions) DeepCopy() *ProviderOptions { + if in == nil { + return nil + } + out := new(ProviderOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RPCOptions) DeepCopyInto(out *RPCOptions) { + *out = *in + in.Request.DeepCopyInto(&out.Request) + in.Signature.DeepCopyInto(&out.Signature) + in.HMAC.DeepCopyInto(&out.HMAC) + out.Experimental = in.Experimental +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RPCOptions. +func (in *RPCOptions) DeepCopy() *RPCOptions { + if in == nil { + return nil + } + out := new(RPCOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RedfishOptions) DeepCopyInto(out *RedfishOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedfishOptions. +func (in *RedfishOptions) DeepCopy() *RedfishOptions { + if in == nil { + return nil + } + out := new(RedfishOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestOpts) DeepCopyInto(out *RequestOpts) { + *out = *in + if in.StaticHeaders != nil { + in, out := &in.StaticHeaders, &out.StaticHeaders + *out = make(http.Header, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestOpts. +func (in *RequestOpts) DeepCopy() *RequestOpts { + if in == nil { + return nil + } + out := new(RequestOpts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SignatureOpts) DeepCopyInto(out *SignatureOpts) { + *out = *in + if in.IncludedPayloadHeaders != nil { + in, out := &in.IncludedPayloadHeaders, &out.IncludedPayloadHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SignatureOpts. +func (in *SignatureOpts) DeepCopy() *SignatureOpts { + if in == nil { + return nil + } + out := new(SignatureOpts) + 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/bmc.tinkerbell.org_jobs.yaml b/config/crd/bases/bmc.tinkerbell.org_jobs.yaml index 544080e..1f710ed 100644 --- a/config/crd/bases/bmc.tinkerbell.org_jobs.yaml +++ b/config/crd/bases/bmc.tinkerbell.org_jobs.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: jobs.bmc.tinkerbell.org spec: group: bmc.tinkerbell.org @@ -156,9 +155,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/bmc.tinkerbell.org_machines.yaml b/config/crd/bases/bmc.tinkerbell.org_machines.yaml index 097ead7..10bba5a 100644 --- a/config/crd/bases/bmc.tinkerbell.org_machines.yaml +++ b/config/crd/bases/bmc.tinkerbell.org_machines.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: machines.bmc.tinkerbell.org spec: group: bmc.tinkerbell.org @@ -55,6 +54,7 @@ spec: secret name must be unique. type: string type: object + x-kubernetes-map-type: atomic host: description: Host is the host IP address or hostname of the Machine. minLength: 1 @@ -72,6 +72,173 @@ spec: - insecureTLS - port type: object + providerOptions: + description: ProviderOptions contains provider specific options. + properties: + intelAMT: + description: IntelAMT contains the options to customize the IntelAMT + provider. + properties: + port: + description: Port that intelAMT will use for calls. + type: integer + required: + - port + type: object + ipmitool: + description: IPMITOOL contains the options to customize the Ipmitool + provider. + properties: + cipherSuite: + description: CipherSuite that ipmitool will use for calls. + type: string + port: + description: Port that ipmitool will use for calls. + type: integer + required: + - cipherSuite + - port + type: object + redfish: + description: Redfish contains the options to customize the Redfish + provider. + properties: + port: + description: Port that redfish will use for calls. + type: integer + required: + - port + type: object + rpc: + description: RPC contains the options to customize the RPC provider. + properties: + consumerURL: + description: ConsumerURL is the URL where an rpc consumer/listener + is running and to which we will send and receive all notifications. + type: string + experimental: + description: Experimental options. + properties: + customRequestPayload: + description: CustomRequestPayload must be in json. + type: string + dotPath: + description: 'DotPath is the path to the json object where + the bmclib RequestPayload{} struct will be embedded. + For example: object.data.body' + type: string + required: + - customRequestPayload + - dotPath + type: object + hmac: + description: HMAC is the options used to create a HMAC signature. + properties: + prefixSigDisabled: + description: 'PrefixSigDisabled determines whether the + algorithm will be prefixed to the signature. Example: + sha256=abc123' + type: boolean + secrets: + additionalProperties: + items: + description: SecretReference represents a Secret Reference. + It has enough information to retrieve secret in + any namespace + properties: + name: + description: name is unique within a namespace + to reference a secret resource. + type: string + namespace: + description: namespace defines the space within + which the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + type: array + description: Secrets are a map of algorithms to secrets + used for signing. + type: object + required: + - prefixSigDisabled + - secrets + type: object + logNotificationsDisabled: + description: LogNotificationsDisabled determines whether responses + from rpc consumer/listeners will be logged or not. + type: boolean + request: + description: Request is the options used to create the rpc + HTTP request. + properties: + httpContentType: + description: HTTPContentType is the content type to use + for the rpc request notification. + type: string + httpMethod: + description: HTTPMethod is the HTTP method to use for + the rpc request notification. + type: string + staticHeaders: + additionalProperties: + items: + type: string + type: array + description: StaticHeaders are predefined headers that + will be added to every request. + type: object + timestampFormat: + description: TimestampFormat is the time format for the + timestamp header. + type: string + timestampHeader: + description: 'TimestampHeader is the header name that + should contain the timestamp. Example: X-BMCLIB-Timestamp' + type: string + required: + - httpContentType + - httpMethod + - staticHeaders + - timestampFormat + - timestampHeader + type: object + signature: + description: Signature is the options used for adding an HMAC + signature to an HTTP request. + properties: + appendAlgoToHeaderDisabled: + description: 'AppendAlgoToHeaderDisabled decides whether + to append the algorithm to the signature header or not. + Example: X-BMCLIB-Signature becomes X-BMCLIB-Signature-256 + When set to true, a header will be added for each algorithm. + Example: X-BMCLIB-Signature-256 and X-BMCLIB-Signature-512' + type: boolean + headerName: + description: 'HeaderName is the header name that should + contain the signature(s). Example: X-BMCLIB-Signature' + type: string + includedPayloadHeaders: + description: 'IncludedPayloadHeaders are headers whose + values will be included in the signature payload. Example: + X-BMCLIB-My-Custom-Header All headers will be deduplicated.' + items: + type: string + type: array + required: + - appendAlgoToHeaderDisabled + - headerName + - includedPayloadHeaders + type: object + required: + - consumerURL + - experimental + - hmac + - logNotificationsDisabled + - request + - signature + type: object + type: object required: - connection type: object @@ -116,9 +283,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/bmc.tinkerbell.org_tasks.yaml b/config/crd/bases/bmc.tinkerbell.org_tasks.yaml index 6cdcc37..17d8fd1 100644 --- a/config/crd/bases/bmc.tinkerbell.org_tasks.yaml +++ b/config/crd/bases/bmc.tinkerbell.org_tasks.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: tasks.bmc.tinkerbell.org spec: group: bmc.tinkerbell.org @@ -56,6 +55,7 @@ spec: secret name must be unique. type: string type: object + x-kubernetes-map-type: atomic host: description: Host is the host IP address or hostname of the Machine. minLength: 1 @@ -162,9 +162,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 45d0b8f..93dc1e1 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role rules: - apiGroups: diff --git a/controllers/helpers_test.go b/controllers/helpers_test.go index 91fdb0d..d63a44c 100644 --- a/controllers/helpers_test.go +++ b/controllers/helpers_test.go @@ -11,7 +11,6 @@ import ( "github.com/tinkerbell/rufio/controllers" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) @@ -33,22 +32,6 @@ func newClientBuilder() *fake.ClientBuilder { WithScheme(scheme) } -// createKubeClientWithObjects creates a kubernetes client with the given objects. -func createKubeClientWithObjects(objects ...client.Object) client.WithWatch { - return newClientBuilder(). - WithObjects(objects...). - Build() -} - -// createKubeClientWithObjectsForJobController creates a kubernetes client with the given objects -// and the indexes required by the Job controller. -func createKubeClientWithObjectsForJobController(objects ...client.Object) client.WithWatch { - return newClientBuilder(). - WithObjects(objects...). - WithIndex(&v1alpha1.Task{}, ".metadata.controller", controllers.TaskOwnerIndexFunc). - Build() -} - type testProvider struct { PName string Proto string diff --git a/controllers/machine.go b/controllers/machine.go index 12130e0..0493830 100644 --- a/controllers/machine.go +++ b/controllers/machine.go @@ -108,12 +108,11 @@ func (r *MachineReconciler) doReconcile(ctx context.Context, bm *v1alpha1.Machin if err != nil { logger.Error(err, "BMC connection failed", "host", bm.Spec.Connection.Host) bm.SetCondition(v1alpha1.Contactable, v1alpha1.ConditionFalse, v1alpha1.WithMachineConditionMessage(err.Error())) - result, patchErr := r.patchStatus(ctx, bm, bmPatch) - if patchErr != nil { - return result, utilerrors.NewAggregate([]error{patchErr, err}) + if patchErr := r.patchStatus(ctx, bm, bmPatch); patchErr != nil { + return ctrl.Result{}, utilerrors.NewAggregate([]error{patchErr, err}) } - return result, err + return ctrl.Result{}, err } // Close BMC connection after reconciliation @@ -145,12 +144,11 @@ func (r *MachineReconciler) doReconcile(ctx context.Context, bm *v1alpha1.Machin } // Patch the status after each reconciliation - result, err := r.patchStatus(ctx, bm, bmPatch) - if err != nil { + if err := r.patchStatus(ctx, bm, bmPatch); err != nil { aggErr = utilerrors.NewAggregate([]error{err, aggErr}) } - return result, utilerrors.Flatten(aggErr) + return ctrl.Result{}, utilerrors.Flatten(aggErr) } // reconcilePower ensures the Machine Power is in the desired state. @@ -172,13 +170,13 @@ func (r *MachineReconciler) reconcilePower(ctx context.Context, bm *v1alpha1.Mac } // patchStatus patches the specifies patch on the Machine. -func (r *MachineReconciler) patchStatus(ctx context.Context, bm *v1alpha1.Machine, patch client.Patch) (ctrl.Result, error) { +func (r *MachineReconciler) patchStatus(ctx context.Context, bm *v1alpha1.Machine, patch client.Patch) error { err := r.client.Status().Patch(ctx, bm, patch) if err != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch Machine %s/%s status: %w", bm.Namespace, bm.Name, err) + return fmt.Errorf("failed to patch Machine %s/%s status: %w", bm.Namespace, bm.Name, err) } - return ctrl.Result{}, nil + return nil } // convertRawBMCPowerState takes a raw BMC power state response and attempts to convert it to diff --git a/lint.mk b/lint.mk index a132280..26af564 100644 --- a/lint.mk +++ b/lint.mk @@ -20,7 +20,7 @@ LINTERS := FIXERS := GOLANGCI_LINT_CONFIG := $(LINT_ROOT)/.golangci.yml -GOLANGCI_LINT_VERSION ?= v1.52.2 +GOLANGCI_LINT_VERSION ?= v1.54.2 GOLANGCI_LINT_BIN := out/linters/golangci-lint-$(GOLANGCI_LINT_VERSION)-$(LINT_ARCH) $(GOLANGCI_LINT_BIN): mkdir -p out/linters @@ -30,11 +30,11 @@ $(GOLANGCI_LINT_BIN): LINTERS += golangci-lint-lint golangci-lint-lint: $(GOLANGCI_LINT_BIN) - find . -name go.mod -execdir "$(GOLANGCI_LINT_BIN)" run -c "$(GOLINT_CONFIG)" \; + "$(GOLANGCI_LINT_BIN)" run -c "$(GOLANGCI_LINT_CONFIG)" FIXERS += golangci-lint-fix golangci-lint-fix: $(GOLANGCI_LINT_BIN) - find . -name go.mod -execdir "$(GOLANGCI_LINT_BIN)" run -c "$(GOLINT_CONFIG)" --fix \; + find . -name go.mod -execdir "$(GOLANGCI_LINT_BIN)" run -c "$(GOLANGCI_LINT_CONFIG)" --fix \; .PHONY: _lint $(LINTERS) _lint: $(LINTERS)