diff --git a/Makefile b/Makefile index 2fbc186f1..2502071f8 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,8 @@ manifests: controller-gen # Generate API reference documentation api-docs: gen-crd-api-reference-docs - $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/notification.md + $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1beta2/notification.md + $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1/notification.md # Run go mod tidy tidy: diff --git a/api/v1/doc.go b/api/v1/doc.go new file mode 100644 index 000000000..3eb81cb22 --- /dev/null +++ b/api/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1 contains API Schema definitions for the notification v1 API group. +// +kubebuilder:object:generate=true +// +groupName=notification.toolkit.fluxcd.io +package v1 diff --git a/api/v1/groupversion_info.go b/api/v1/groupversion_info.go new file mode 100644 index 000000000..20a8a0bb4 --- /dev/null +++ b/api/v1/groupversion_info.go @@ -0,0 +1,33 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "notification.toolkit.fluxcd.io", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1/receiver_types.go b/api/v1/receiver_types.go new file mode 100644 index 000000000..89a4679df --- /dev/null +++ b/api/v1/receiver_types.go @@ -0,0 +1,159 @@ +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "crypto/sha256" + "fmt" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/meta" +) + +const ( + ReceiverKind string = "Receiver" + ReceiverWebhookPath string = "/hook/" + GenericReceiver string = "generic" + GenericHMACReceiver string = "generic-hmac" + GitHubReceiver string = "github" + GitLabReceiver string = "gitlab" + BitbucketReceiver string = "bitbucket" + HarborReceiver string = "harbor" + DockerHubReceiver string = "dockerhub" + QuayReceiver string = "quay" + GCRReceiver string = "gcr" + NexusReceiver string = "nexus" + ACRReceiver string = "acr" +) + +// ReceiverSpec defines the desired state of the Receiver. +type ReceiverSpec struct { + // Type of webhook sender, used to determine + // the validation procedure and payload deserialization. + // +kubebuilder:validation:Enum=generic;generic-hmac;github;gitlab;bitbucket;harbor;dockerhub;quay;gcr;nexus;acr + // +required + Type string `json:"type"` + + // Interval at which to reconcile the Receiver with its Secret references. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +optional + Interval *metav1.Duration `json:"interval,omitempty"` + + // Events specifies the list of event types to handle, + // e.g. 'push' for GitHub or 'Push Hook' for GitLab. + // +optional + Events []string `json:"events"` + + // A list of resources to be notified about changes. + // +required + Resources []CrossNamespaceObjectReference `json:"resources"` + + // SecretRef specifies the Secret containing the token used + // to validate the payload authenticity. + // +required + SecretRef meta.LocalObjectReference `json:"secretRef,omitempty"` + + // Suspend tells the controller to suspend subsequent + // events handling for this receiver. + // +optional + Suspend bool `json:"suspend,omitempty"` +} + +// ReceiverStatus defines the observed state of the Receiver. +type ReceiverStatus struct { + meta.ReconcileRequestStatus `json:",inline"` + + // Conditions holds the conditions for the Receiver. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // URL is the generated incoming webhook address in the format + // of '/hook/sha256sum(token+name+namespace)'. + // Deprecated: Replaced by WebhookPath. + // +optional + URL string `json:"url,omitempty"` + + // WebhookPath is the generated incoming webhook address in the format + // of '/hook/sha256sum(token+name+namespace)'. + // +optional + WebhookPath string `json:"webhookPath,omitempty"` + + // ObservedGeneration is the last observed generation of the Receiver object. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// GetConditions returns the status conditions of the object. +func (in *Receiver) GetConditions() []metav1.Condition { + return in.Status.Conditions +} + +// SetConditions sets the status conditions on the object. +func (in *Receiver) SetConditions(conditions []metav1.Condition) { + in.Status.Conditions = conditions +} + +// GetWebhookPath returns the incoming webhook path for the given token. +func (in *Receiver) GetWebhookPath(token string) string { + digest := sha256.Sum256([]byte(token + in.GetName() + in.GetNamespace())) + return fmt.Sprintf("%s%x", ReceiverWebhookPath, digest) +} + +// GetInterval returns the interval value with a default of 10m for this Receiver. +func (in *Receiver) GetInterval() time.Duration { + duration := 10 * time.Minute + if in.Spec.Interval != nil { + duration = in.Spec.Interval.Duration + } + + return duration +} + +// +genclient +// +genclient:Namespaced +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" + +// Receiver is the Schema for the receivers API. +type Receiver struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ReceiverSpec `json:"spec,omitempty"` + // +kubebuilder:default:={"observedGeneration":-1} + Status ReceiverStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ReceiverList contains a list of Receivers. +type ReceiverList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Receiver `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Receiver{}, &ReceiverList{}) +} diff --git a/api/v1/reference_types.go b/api/v1/reference_types.go new file mode 100644 index 000000000..de1d42224 --- /dev/null +++ b/api/v1/reference_types.go @@ -0,0 +1,49 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +// CrossNamespaceObjectReference contains enough information to let you locate the +// typed referenced object at cluster level +type CrossNamespaceObjectReference struct { + // API version of the referent + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Kind of the referent + // +kubebuilder:validation:Enum=Bucket;GitRepository;Kustomization;HelmRelease;HelmChart;HelmRepository;ImageRepository;ImagePolicy;ImageUpdateAutomation;OCIRepository + // +required + Kind string `json:"kind,omitempty"` + + // Name of the referent + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=53 + // +required + Name string `json:"name"` + + // Namespace of the referent + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=53 + // +kubebuilder:validation:Optional + // +optional + Namespace string `json:"namespace,omitempty"` + + // MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + // map is equivalent to an element of matchExpressions, whose key field is "key", the + // operator is "In", and the values array contains only "value". The requirements are ANDed. + // +optional + MatchLabels map[string]string `json:"matchLabels,omitempty"` +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..15861e955 --- /dev/null +++ b/api/v1/zz_generated.deepcopy.go @@ -0,0 +1,164 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2022 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CrossNamespaceObjectReference) DeepCopyInto(out *CrossNamespaceObjectReference) { + *out = *in + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceObjectReference. +func (in *CrossNamespaceObjectReference) DeepCopy() *CrossNamespaceObjectReference { + if in == nil { + return nil + } + out := new(CrossNamespaceObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Receiver) DeepCopyInto(out *Receiver) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Receiver. +func (in *Receiver) DeepCopy() *Receiver { + if in == nil { + return nil + } + out := new(Receiver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Receiver) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReceiverList) DeepCopyInto(out *ReceiverList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Receiver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverList. +func (in *ReceiverList) DeepCopy() *ReceiverList { + if in == nil { + return nil + } + out := new(ReceiverList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReceiverList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) { + *out = *in + if in.Interval != nil { + in, out := &in.Interval, &out.Interval + *out = new(metav1.Duration) + **out = **in + } + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]CrossNamespaceObjectReference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.SecretRef = in.SecretRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverSpec. +func (in *ReceiverSpec) DeepCopy() *ReceiverSpec { + if in == nil { + return nil + } + out := new(ReceiverSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) { + *out = *in + out.ReconcileRequestStatus = in.ReconcileRequestStatus + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverStatus. +func (in *ReceiverStatus) DeepCopy() *ReceiverStatus { + if in == nil { + return nil + } + out := new(ReceiverStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1beta2/receiver_types.go b/api/v1beta2/receiver_types.go index d52a49969..a29808749 100644 --- a/api/v1beta2/receiver_types.go +++ b/api/v1beta2/receiver_types.go @@ -128,7 +128,6 @@ func (in *Receiver) GetInterval() time.Duration { // +genclient // +genclient:Namespaced -// +kubebuilder:storageversion // +kubebuilder:object:root=true // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml index fbf395bca..233112377 100644 --- a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml +++ b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null name: alerts.notification.toolkit.fluxcd.io spec: @@ -414,3 +414,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_providers.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_providers.yaml index 3b0da5645..5ca7a49ef 100644 --- a/config/crd/bases/notification.toolkit.fluxcd.io_providers.yaml +++ b/config/crd/bases/notification.toolkit.fluxcd.io_providers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null name: providers.notification.toolkit.fluxcd.io spec: @@ -399,3 +399,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml index 021d1882b..43d20211f 100644 --- a/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml +++ b/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null name: receivers.notification.toolkit.fluxcd.io spec: @@ -15,6 +15,226 @@ spec: singular: receiver scope: Namespaced versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Receiver is the Schema for the receivers API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ReceiverSpec defines the desired state of the Receiver. + properties: + events: + description: Events specifies the list of event types to handle, e.g. + 'push' for GitHub or 'Push Hook' for GitLab. + items: + type: string + type: array + interval: + description: Interval at which to reconcile the Receiver with its + Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + resources: + description: A list of resources to be notified about changes. + items: + description: CrossNamespaceObjectReference contains enough information + to let you locate the typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + matchLabels: + additionalProperties: + type: string + description: MatchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + name: + description: Name of the referent + maxLength: 53 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 53 + minLength: 1 + type: string + required: + - name + type: object + type: array + secretRef: + description: SecretRef specifies the Secret containing the token used + to validate the payload authenticity. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: Suspend tells the controller to suspend subsequent events + handling for this receiver. + type: boolean + type: + description: Type of webhook sender, used to determine the validation + procedure and payload deserialization. + enum: + - generic + - generic-hmac + - github + - gitlab + - bitbucket + - harbor + - dockerhub + - quay + - gcr + - nexus + - acr + type: string + required: + - resources + - type + type: object + status: + default: + observedGeneration: -1 + description: ReceiverStatus defines the observed state of the Receiver. + properties: + conditions: + description: Conditions holds the conditions for the Receiver. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value can + be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of + the Receiver object. + format: int64 + type: integer + url: + description: 'URL is the generated incoming webhook address in the + format of ''/hook/sha256sum(token+name+namespace)''. Deprecated: + Replaced by WebhookPath.' + type: string + webhookPath: + description: WebhookPath is the generated incoming webhook address + in the format of '/hook/sha256sum(token+name+namespace)'. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age @@ -435,6 +655,12 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/testdata/status-defaults/receiver.yaml b/config/testdata/status-defaults/receiver.yaml index 254f51afb..fbba61a78 100644 --- a/config/testdata/status-defaults/receiver.yaml +++ b/config/testdata/status-defaults/receiver.yaml @@ -1,4 +1,4 @@ -apiVersion: notification.toolkit.fluxcd.io/v1beta1 +apiVersion: notification.toolkit.fluxcd.io/v1 kind: Receiver metadata: name: status-defaults diff --git a/controllers/receiver_controller.go b/controllers/receiver_controller.go index f441fc1cc..5d2af0125 100644 --- a/controllers/receiver_controller.go +++ b/controllers/receiver_controller.go @@ -40,7 +40,8 @@ import ( "github.com/fluxcd/pkg/runtime/patch" "github.com/fluxcd/pkg/runtime/predicates" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2" ) // ReceiverReconciler reconciles a Receiver object @@ -126,14 +127,14 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r } }() - if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) { - controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer) + if !controllerutil.ContainsFinalizer(obj, apiv1b2.NotificationFinalizer) { + controllerutil.AddFinalizer(obj, apiv1b2.NotificationFinalizer) result = ctrl.Result{Requeue: true} return } if !obj.ObjectMeta.DeletionTimestamp.IsZero() { - controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer) + controllerutil.RemoveFinalizer(obj, apiv1b2.NotificationFinalizer) result = ctrl.Result{} return } @@ -155,7 +156,7 @@ func (r *ReceiverReconciler) reconcile(ctx context.Context, obj *apiv1.Receiver) token, err := r.token(ctx, obj) if err != nil { - conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.TokenNotFoundReason, err.Error()) + conditions.MarkFalse(obj, meta.ReadyCondition, apiv1b2.TokenNotFoundReason, err.Error()) obj.Status.URL = "" obj.Status.WebhookPath = "" return ctrl.Result{Requeue: true}, err diff --git a/controllers/receiver_controller_test.go b/controllers/receiver_controller_test.go index 0f123469f..b57b40b98 100644 --- a/controllers/receiver_controller_test.go +++ b/controllers/receiver_controller_test.go @@ -39,7 +39,8 @@ import ( "github.com/fluxcd/pkg/runtime/conditions" "github.com/fluxcd/pkg/ssa" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2" "github.com/fluxcd/notification-controller/internal/server" ) @@ -101,7 +102,7 @@ func TestReceiverReconciler_Reconcile(t *testing.T) { g.Expect(conditions.GetReason(resultR, meta.ReadyCondition)).To(BeIdenticalTo(meta.SucceededReason)) g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse()) - g.Expect(controllerutil.ContainsFinalizer(resultR, apiv1.NotificationFinalizer)).To(BeTrue()) + g.Expect(controllerutil.ContainsFinalizer(resultR, apiv1b2.NotificationFinalizer)).To(BeTrue()) }) t.Run("fails with secret not found error", func(t *testing.T) { @@ -122,7 +123,7 @@ func TestReceiverReconciler_Reconcile(t *testing.T) { return !conditions.IsReady(resultR) }, timeout, time.Second).Should(BeTrue()) - g.Expect(conditions.GetReason(resultR, meta.ReadyCondition)).To(BeIdenticalTo(apiv1.TokenNotFoundReason)) + g.Expect(conditions.GetReason(resultR, meta.ReadyCondition)).To(BeIdenticalTo(apiv1b2.TokenNotFoundReason)) g.Expect(conditions.GetMessage(resultR, meta.ReadyCondition)).To(ContainSubstring(secretName)) g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeTrue()) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 4ab956a5c..9c2302d3a 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -40,7 +40,8 @@ import ( "github.com/fluxcd/pkg/runtime/testenv" "github.com/fluxcd/pkg/ssa" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2" // +kubebuilder:scaffold:imports ) @@ -54,6 +55,7 @@ var ( func TestMain(m *testing.M) { var err error utilruntime.Must(apiv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(apiv1b2.AddToScheme(scheme.Scheme)) testEnv = testenv.New(testenv.WithCRDPath( filepath.Join("..", "config", "crd", "bases"), diff --git a/docs/api/v1/notification.md b/docs/api/v1/notification.md new file mode 100644 index 000000000..a124fee16 --- /dev/null +++ b/docs/api/v1/notification.md @@ -0,0 +1,442 @@ +
Packages:
+ +Package v1 contains API Schema definitions for the notification v1 API group.
+Resource Types: +Receiver is the Schema for the receivers API.
+Field | +Description | +||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+apiVersion +string |
+
+notification.toolkit.fluxcd.io/v1
+ |
+||||||||||||
+kind +string + |
+
+Receiver
+ |
+||||||||||||
+metadata + + +Kubernetes meta/v1.ObjectMeta + + + |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||||
+spec + + +ReceiverSpec + + + |
+
+ + +
|
+||||||||||||
+status + + +ReceiverStatus + + + |
++ | +
+(Appears on: +ReceiverSpec) +
+CrossNamespaceObjectReference contains enough information to let you locate the +typed referenced object at cluster level
+Field | +Description | +
---|---|
+apiVersion + +string + + |
+
+(Optional)
+ API version of the referent + |
+
+kind + +string + + |
+
+ Kind of the referent + |
+
+name + +string + + |
+
+ Name of the referent + |
+
+namespace + +string + + |
+
+(Optional)
+ Namespace of the referent + |
+
+matchLabels + +map[string]string + + |
+
+(Optional)
+ MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is “key”, the +operator is “In”, and the values array contains only “value”. The requirements are ANDed. + |
+
+(Appears on: +Receiver) +
+ReceiverSpec defines the desired state of the Receiver.
+Field | +Description | +
---|---|
+type + +string + + |
+
+ Type of webhook sender, used to determine +the validation procedure and payload deserialization. + |
+
+interval + + +Kubernetes meta/v1.Duration + + + |
+
+(Optional)
+ Interval at which to reconcile the Receiver with its Secret references. + |
+
+events + +[]string + + |
+
+(Optional)
+ Events specifies the list of event types to handle, +e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab. + |
+
+resources + + +[]CrossNamespaceObjectReference + + + |
+
+ A list of resources to be notified about changes. + |
+
+secretRef + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + + |
+
+ SecretRef specifies the Secret containing the token used +to validate the payload authenticity. + |
+
+suspend + +bool + + |
+
+(Optional)
+ Suspend tells the controller to suspend subsequent +events handling for this receiver. + |
+
+(Appears on: +Receiver) +
+ReceiverStatus defines the observed state of the Receiver.
+Field | +Description | +
---|---|
+ReconcileRequestStatus + + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus + + + |
+
+
+(Members of |
+
+conditions + + +[]Kubernetes meta/v1.Condition + + + |
+
+(Optional)
+ Conditions holds the conditions for the Receiver. + |
+
+url + +string + + |
+
+(Optional)
+ URL is the generated incoming webhook address in the format +of ‘/hook/sha256sum(token+name+namespace)’. +Deprecated: Replaced by WebhookPath. + |
+
+webhookPath + +string + + |
+
+(Optional)
+ WebhookPath is the generated incoming webhook address in the format +of ‘/hook/sha256sum(token+name+namespace)’. + |
+
+observedGeneration + +int64 + + |
+
+(Optional)
+ ObservedGeneration is the last observed generation of the Receiver object. + |
+
This page was automatically generated with gen-crd-api-reference-docs
Packages:
Packages:
diff --git a/internal/server/receiver_handler_test.go b/internal/server/receiver_handler_test.go index c134b04d6..de3d00381 100644 --- a/internal/server/receiver_handler_test.go +++ b/internal/server/receiver_handler_test.go @@ -38,7 +38,7 @@ import ( "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/logger" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" ) func Test_handlePayload(t *testing.T) { diff --git a/internal/server/receiver_handlers.go b/internal/server/receiver_handlers.go index 7ebc2cc50..f6059cf91 100644 --- a/internal/server/receiver_handlers.go +++ b/internal/server/receiver_handlers.go @@ -40,7 +40,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" ) // defaultFluxAPIVersions is a map of Flux API kinds to their API versions. diff --git a/main.go b/main.go index 4f68abfb3..017d91b82 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,8 @@ import ( "github.com/fluxcd/pkg/runtime/pprof" "github.com/fluxcd/pkg/runtime/probes" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2" "github.com/fluxcd/notification-controller/controllers" "github.com/fluxcd/notification-controller/internal/features" "github.com/fluxcd/notification-controller/internal/server" @@ -60,6 +61,7 @@ func init() { _ = clientgoscheme.AddToScheme(scheme) _ = apiv1.AddToScheme(scheme) + _ = apiv1b2.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } @@ -188,6 +190,10 @@ func main() { store, err := memorystore.New(&memorystore.Config{ Interval: rateLimitInterval, }) + if err != nil { + setupLog.Error(err, "unable to create middleware store") + os.Exit(1) + } setupLog.Info("starting event server", "addr", eventsAddr) eventMdlw := middleware.New(middleware.Config{