From 526eb671cf824822bc805fe3a1569ef06f00a4ee Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Fri, 1 Sep 2023 15:36:02 -0600 Subject: [PATCH 1/6] Update API with per provider opts: This enables customization per provider. For example, redfish port, ipmitool cipher suite. Signed-off-by: Jacob Weinstock --- Makefile | 2 +- api/v1alpha1/machine.go | 19 ++ api/v1alpha1/provider_opts.go | 96 ++++++++++ config/crd/bases/bmc.tinkerbell.org_jobs.yaml | 9 +- .../bases/bmc.tinkerbell.org_machines.yaml | 178 +++++++++++++++++- .../crd/bases/bmc.tinkerbell.org_tasks.yaml | 10 +- config/rbac/role.yaml | 1 - 7 files changed, 289 insertions(+), 26 deletions(-) create mode 100644 api/v1alpha1/provider_opts.go 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..1dec3da 100644 --- a/api/v1alpha1/machine.go +++ b/api/v1alpha1/machine.go @@ -49,6 +49,25 @@ const ( type MachineSpec struct { // Connection contains connection data for a Baseboard Management Controller. Connection Connection `json:"connection"` + + // ProviderOptions contains provider specific options. + // +optional + ProviderOpts ProviderOpts `json:"providerOpts,omitempty"` +} + +type ProviderOpts struct { + // RPC contains rpc provider options. + // +optional + RPC OptRPC `json:"rpc"` + // Redfish contains redfish provider options. + // +optional + Redfish OptRedfish `json:"redfish"` + // IPMITOOL contains ipmitool provider options. + // +optional + IPMITOOL OptIPMITOOL `json:"ipmitool"` + // IPMI contains ipmi provider options. + // +optional + IntelAMT OptIntelAMT `json:"intelAMT"` } // 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..c8148a6 --- /dev/null +++ b/api/v1alpha1/provider_opts.go @@ -0,0 +1,96 @@ +package v1alpha1 + +import ( + "net/http" + + corev1 "k8s.io/api/core/v1" +) + +// Config defines the configuration for sending rpc notifications. +type OptRPC 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"` + // Opts are the options for the rpc provider. + Opts Opts `json:"opts"` +} + +// Opts are the options for the rpc provider. +type Opts struct { + // 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 Experimental `json:"experimental"` +} + +// RequestOpts are the options used to create the rpc 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 a 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 Secrets `json:"secrets"` +} + +// Experimental options. +type Experimental struct { + // CustomRequestPayload must be in json. + CustomRequestPayload string `json:"customRequestPayload"` + // DotPath is the path to where the bmclib RequestPayload{} will be embedded. For example: object.data.body + DotPath string `json:"dotPath"` +} + +// Algorithm is the type for HMAC algorithms. +type Algorithm string + +// Secrets hold per algorithm slice secrets. +// These secrets will be used to create HMAC signatures. +type Secrets map[Algorithm][]corev1.SecretReference + +// OptRedfish contains redfish provider options. +type OptRedfish struct { + Port int `json:"port"` +} + +// OptIPMITOOL contains ipmitool provider options. +type OptIPMITOOL struct { + Port int `json:"port"` + CipherSuite string `json:"cipherSuite"` +} + +// OptIntelAMT contains intel amt provider options. +type OptIntelAMT struct { + Port int `json:"port"` +} 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..e7ead1a 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,174 @@ spec: - insecureTLS - port type: object + providerOpts: + description: ProviderOptions contains provider specific options. + properties: + intelAMT: + description: IPMI contains ipmi provider options. + properties: + port: + type: integer + required: + - port + type: object + ipmitool: + description: IPMITOOL contains ipmitool provider options. + properties: + cipherSuite: + type: string + port: + type: integer + required: + - cipherSuite + - port + type: object + redfish: + description: Redfish contains redfish provider options. + properties: + port: + type: integer + required: + - port + type: object + rpc: + description: RPC contains rpc provider options. + 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 + logNotificationsDisabled: + description: LogNotificationsDisabled determines whether responses + from rpc consumer/listeners will be logged or not. + type: boolean + opts: + description: Opts are the options for the rpc provider. + properties: + experimental: + description: Experimental options. + properties: + customRequestPayload: + description: CustomRequestPayload must be in json. + type: string + dotPath: + description: 'DotPath is the path to where the bmclib + RequestPayload{} 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 + 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: + - experimental + - hmac + - request + - signature + type: object + required: + - consumerURL + - logNotificationsDisabled + - opts + type: object + type: object required: - connection type: object @@ -116,9 +284,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: From 137264b1b850657494a7f87e91cbc93d942c2611 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 13 Sep 2023 17:10:12 -0600 Subject: [PATCH 2/6] Update the naming for provider options: Signed-off-by: Jacob Weinstock --- api/v1alpha1/machine.go | 23 ++++++----- api/v1alpha1/provider_opts.go | 74 +++++++++++++++++------------------ 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/api/v1alpha1/machine.go b/api/v1alpha1/machine.go index 1dec3da..ed0defd 100644 --- a/api/v1alpha1/machine.go +++ b/api/v1alpha1/machine.go @@ -52,22 +52,25 @@ type MachineSpec struct { // ProviderOptions contains provider specific options. // +optional - ProviderOpts ProviderOpts `json:"providerOpts,omitempty"` + ProviderOptions ProviderOptions `json:"providerOptions,omitempty"` } -type ProviderOpts struct { - // RPC contains rpc provider options. +type ProviderOptions struct { + // IntelAMT contains the options to customize the IntelAMT provider. // +optional - RPC OptRPC `json:"rpc"` - // Redfish contains redfish provider options. + IntelAMT *IntelAMTOptions `json:"intelAMT"` + + // IPMITOOL contains the options to customize the Ipmitool provider. // +optional - Redfish OptRedfish `json:"redfish"` - // IPMITOOL contains ipmitool provider options. + IPMITOOL *IPMITOOLOptions `json:"ipmitool"` + + // Redfish contains the options to customize the Redfish provider. // +optional - IPMITOOL OptIPMITOOL `json:"ipmitool"` - // IPMI contains ipmi provider options. + Redfish *RedfishOptions `json:"redfish"` + + // RPC contains the options to customize the RPC provider. // +optional - IntelAMT OptIntelAMT `json:"intelAMT"` + 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 index c8148a6..6f0cd79 100644 --- a/api/v1alpha1/provider_opts.go +++ b/api/v1alpha1/provider_opts.go @@ -6,19 +6,40 @@ import ( corev1 "k8s.io/api/core/v1" ) -// Config defines the configuration for sending rpc notifications. -type OptRPC struct { +// 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"` +} + +// RPCAlgorithm is a type for HMAC algorithms. +type RPCAlgorithm string + +// RPCSecrets holds per Algorithm slice secrets. +// These secrets will be used to create HMAC signatures. +type RPCSecrets map[RPCAlgorithm][]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"` - // Opts are the options for the rpc provider. - Opts Opts `json:"opts"` -} - -// Opts are the options for the rpc provider. -type Opts struct { // 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. @@ -26,10 +47,10 @@ type Opts struct { // HMAC is the options used to create a HMAC signature. HMAC HMACOpts `json:"hmac"` // Experimental options. - Experimental Experimental `json:"experimental"` + Experimental ExperimentalOpts `json:"experimental"` } -// RequestOpts are the options used to create the rpc HTTP request. +// 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"` @@ -56,41 +77,18 @@ type SignatureOpts struct { IncludedPayloadHeaders []string `json:"includedPayloadHeaders"` } -// HMACOpts are the options used to create a HMAC signature. +// 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 Secrets `json:"secrets"` + Secrets RPCSecrets `json:"secrets"` } -// Experimental options. -type Experimental struct { +// 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 where the bmclib RequestPayload{} will be embedded. For example: object.data.body + // 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"` } - -// Algorithm is the type for HMAC algorithms. -type Algorithm string - -// Secrets hold per algorithm slice secrets. -// These secrets will be used to create HMAC signatures. -type Secrets map[Algorithm][]corev1.SecretReference - -// OptRedfish contains redfish provider options. -type OptRedfish struct { - Port int `json:"port"` -} - -// OptIPMITOOL contains ipmitool provider options. -type OptIPMITOOL struct { - Port int `json:"port"` - CipherSuite string `json:"cipherSuite"` -} - -// OptIntelAMT contains intel amt provider options. -type OptIntelAMT struct { - Port int `json:"port"` -} From c23c9a4187ce6b48ab48abda69bba94f5613a4f8 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 13 Sep 2023 17:10:36 -0600 Subject: [PATCH 3/6] Update generated files Signed-off-by: Jacob Weinstock --- api/v1alpha1/zz_generated.deepcopy.go | 232 ++++++++++++++++- .../bases/bmc.tinkerbell.org_machines.yaml | 243 +++++++++--------- 2 files changed, 351 insertions(+), 124 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 561326b..1bd5983 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,7 +21,9 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" + "net/http" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -71,6 +72,82 @@ 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(RPCSecrets, 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 *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 +278,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 +367,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 +422,156 @@ 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 RPCSecrets) DeepCopyInto(out *RPCSecrets) { + { + in := &in + *out = make(RPCSecrets, 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 RPCSecrets. +func (in RPCSecrets) DeepCopy() RPCSecrets { + if in == nil { + return nil + } + out := new(RPCSecrets) + 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_machines.yaml b/config/crd/bases/bmc.tinkerbell.org_machines.yaml index e7ead1a..10bba5a 100644 --- a/config/crd/bases/bmc.tinkerbell.org_machines.yaml +++ b/config/crd/bases/bmc.tinkerbell.org_machines.yaml @@ -72,172 +72,171 @@ spec: - insecureTLS - port type: object - providerOpts: + providerOptions: description: ProviderOptions contains provider specific options. properties: intelAMT: - description: IPMI contains ipmi provider options. + 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 ipmitool provider options. + 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 redfish provider options. + 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 rpc provider options. + 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 - opts: - description: Opts are the options for the rpc provider. + request: + description: Request is the options used to create the rpc + HTTP request. properties: - experimental: - description: Experimental options. - properties: - customRequestPayload: - description: CustomRequestPayload must be in json. + 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 - dotPath: - description: 'DotPath is the path to where the bmclib - RequestPayload{} 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 - 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: 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: - - experimental - - hmac - - request - - signature + - appendAlgoToHeaderDisabled + - headerName + - includedPayloadHeaders type: object required: - consumerURL + - experimental + - hmac - logNotificationsDisabled - - opts + - request + - signature type: object type: object required: From 51ab75841388da676c6690a8e8ba5e0947c2cc0b Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 13 Sep 2023 17:17:15 -0600 Subject: [PATCH 4/6] Run goimports on deepcopy.go Signed-off-by: Jacob Weinstock --- api/v1alpha1/zz_generated.deepcopy.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1bd5983..10f9888 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,9 +21,10 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/api/core/v1" - runtime "k8s.io/apimachinery/pkg/runtime" "net/http" + + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. From 3ec4a9b24f7a70b81db8b2dbd373d3cfc720769a Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Wed, 13 Sep 2023 18:08:14 -0600 Subject: [PATCH 5/6] Update linting version, fix linting issues: The way the linter was run the exit code was being swallowed up and always return 0. This meant that even with linting issues could CI was passing. This fixes that. The new version of the linter found some unused functions, so they were removed. The other changes were to resolve linting issues that were found. Signed-off-by: Jacob Weinstock --- controllers/helpers_test.go | 17 ----------------- controllers/machine.go | 18 ++++++++---------- lint.mk | 6 +++--- 3 files changed, 11 insertions(+), 30 deletions(-) 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) From 950d970d8c2ff412b7bb4d412715bbeadd603e37 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Thu, 14 Sep 2023 09:21:55 -0600 Subject: [PATCH 6/6] Update naming for algorithm and secrets for HMAC Signed-off-by: Jacob Weinstock --- api/v1alpha1/provider_opts.go | 10 ++--- api/v1alpha1/zz_generated.deepcopy.go | 62 +++++++++++++-------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/api/v1alpha1/provider_opts.go b/api/v1alpha1/provider_opts.go index 6f0cd79..ba2daf2 100644 --- a/api/v1alpha1/provider_opts.go +++ b/api/v1alpha1/provider_opts.go @@ -26,12 +26,12 @@ type IntelAMTOptions struct { Port int `json:"port"` } -// RPCAlgorithm is a type for HMAC algorithms. -type RPCAlgorithm string +// HMACAlgorithm is a type for HMAC algorithms. +type HMACAlgorithm string -// RPCSecrets holds per Algorithm slice secrets. +// HMACSecrets holds per Algorithm slice secrets. // These secrets will be used to create HMAC signatures. -type RPCSecrets map[RPCAlgorithm][]corev1.SecretReference +type HMACSecrets map[HMACAlgorithm][]corev1.SecretReference // RPCOptions defines the configurable options to use when sending rpc notifications. type RPCOptions struct { @@ -82,7 +82,7 @@ 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 RPCSecrets `json:"secrets"` + Secrets HMACSecrets `json:"secrets"` } // ExperimentalOpts are options we're still learning about and should be used carefully. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 10f9888..bbdba00 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -93,7 +93,7 @@ func (in *HMACOpts) DeepCopyInto(out *HMACOpts) { *out = *in if in.Secrets != nil { in, out := &in.Secrets, &out.Secrets - *out = make(RPCSecrets, len(*in)) + *out = make(HMACSecrets, len(*in)) for key, val := range *in { var outVal []v1.SecretReference if val == nil { @@ -119,6 +119,36 @@ func (in *HMACOpts) DeepCopy() *HMACOpts { 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 @@ -477,36 +507,6 @@ func (in *RPCOptions) DeepCopy() *RPCOptions { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in RPCSecrets) DeepCopyInto(out *RPCSecrets) { - { - in := &in - *out = make(RPCSecrets, 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 RPCSecrets. -func (in RPCSecrets) DeepCopy() RPCSecrets { - if in == nil { - return nil - } - out := new(RPCSecrets) - 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