From 0e3f717dd19b36a246b7a8281211797edcfbd3a6 Mon Sep 17 00:00:00 2001 From: Max Jonas Werner Date: Wed, 22 Mar 2023 17:40:59 +0100 Subject: [PATCH] Introduce v1 API and bump Receiver version to v1 This commit bumps the Receiver API version to v1 in preparation of the Flux GitOps GA milestone (https://fluxcd.io/roadmap/#flux-gitops-ga-q1-2023). We are now actively maintaining two versions of the notification API group in parallel: v1 which currently only holds the Receiver kind and v1beta2 for all other kinds. Since we haven't run into this situation before, I had to change the way we expose the API docs in ./docs/api: The directory now has sub-directories for each active API version. Therefore we need to change our scripts in the website repository to take this change into account so that we expose both API group version at https://fluxcd.io/flux/components/notification/api/. This change is implemented in https://github.com/fluxcd/website/pull/1427. refs #436 Signed-off-by: Max Jonas Werner --- Makefile | 3 +- PROJECT | 3 + api/v1/condition_types.go | 31 + api/v1/doc.go | 20 + api/v1/groupversion_info.go | 33 + api/v1/receiver_types.go | 160 +++ api/v1/reference_types.go | 49 + api/v1/zz_generated.deepcopy.go | 164 ++++ api/v1beta1/receiver_types.go | 1 + api/v1beta1/zz_generated.deepcopy.go | 2 +- api/v1beta2/alert_types.go | 4 +- api/v1beta2/receiver_types.go | 6 +- api/v1beta2/zz_generated.deepcopy.go | 21 +- ...notification.toolkit.fluxcd.io_alerts.yaml | 12 +- ...ification.toolkit.fluxcd.io_receivers.yaml | 241 ++++- ...ver.yaml => notification_v1_receiver.yaml} | 2 +- config/testdata/status-defaults/receiver.yaml | 2 +- controllers/alert_controller.go | 25 +- controllers/alert_controller_test.go | 27 +- controllers/provider_controller.go | 15 +- controllers/provider_controller_test.go | 9 +- controllers/receiver_controller.go | 2 +- controllers/receiver_controller_test.go | 3 +- controllers/suite_test.go | 4 +- docs/api/v1/notification.md | 442 +++++++++ docs/api/{ => v1beta2}/notification.md | 57 +- docs/spec/README.md | 68 +- docs/spec/v1/README.md | 7 + docs/spec/v1/receivers.md | 913 ++++++++++++++++++ docs/spec/v1beta2/README.md | 2 +- docs/spec/v1beta2/alerts.md | 2 + docs/spec/v1beta2/events.md | 2 + docs/spec/v1beta2/providers.md | 2 + hack/api-docs/config.json | 12 +- hack/api-docs/template/pkg.tpl | 7 +- hack/boilerplate.go.txt | 2 +- internal/server/event_handlers.go | 25 +- internal/server/receiver_handler_test.go | 2 +- internal/server/receiver_handlers.go | 2 +- internal/server/receiver_server.go | 2 +- main.go | 8 +- 41 files changed, 2210 insertions(+), 184 deletions(-) create mode 100644 api/v1/condition_types.go create mode 100644 api/v1/doc.go create mode 100644 api/v1/groupversion_info.go create mode 100644 api/v1/receiver_types.go create mode 100644 api/v1/reference_types.go create mode 100644 api/v1/zz_generated.deepcopy.go rename config/samples/{notification_v1beta2_receiver.yaml => notification_v1_receiver.yaml} (86%) create mode 100644 docs/api/v1/notification.md rename docs/api/{ => v1beta2}/notification.md (89%) create mode 100644 docs/spec/v1/README.md create mode 100644 docs/spec/v1/receivers.md 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/PROJECT b/PROJECT index c53381c21..fa7a1babe 100644 --- a/PROJECT +++ b/PROJECT @@ -1,6 +1,9 @@ domain: toolkit.fluxcd.io repo: github.com/fluxcd/notification-controller resources: +- group: notification + kind: Receiver + version: v1 - group: notification kind: Provider version: v1beta1 diff --git a/api/v1/condition_types.go b/api/v1/condition_types.go new file mode 100644 index 000000000..66f9a3375 --- /dev/null +++ b/api/v1/condition_types.go @@ -0,0 +1,31 @@ +/* +Copyright 2023 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 + +const NotificationFinalizer = "finalizers.fluxcd.io" + +const ( + // InitializedReason represents the fact that a given resource has been initialized. + InitializedReason string = "Initialized" + + // ValidationFailedReason represents the fact that some part of the spec of a given resource + // couldn't be validated. + ValidationFailedReason string = "ValidationFailed" + + // TokenNotFoundReason represents the fact that receiver token can't be found. + TokenNotFoundReason string = "TokenNotFound" +) diff --git a/api/v1/doc.go b/api/v1/doc.go new file mode 100644 index 000000000..3123630d9 --- /dev/null +++ b/api/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2023 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..7a1fff8c7 --- /dev/null +++ b/api/v1/groupversion_info.go @@ -0,0 +1,33 @@ +/* +Copyright 2023 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..f7d73cba4 --- /dev/null +++ b/api/v1/receiver_types.go @@ -0,0 +1,160 @@ +/* +Copyright 2023 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))+$" + // +kubebuilder:default:="10m" + // +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,omitempty"` + + // 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"` + + // 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..be3573d9e --- /dev/null +++ b/api/v1/reference_types.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 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"` + + // 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..04d33b5a9 --- /dev/null +++ b/api/v1/zz_generated.deepcopy.go @@ -0,0 +1,164 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 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/v1beta1/receiver_types.go b/api/v1beta1/receiver_types.go index c96b4c271..50fe28040 100644 --- a/api/v1beta1/receiver_types.go +++ b/api/v1beta1/receiver_types.go @@ -100,6 +100,7 @@ func (in *Receiver) SetConditions(conditions []metav1.Condition) { // +genclient:Namespaced // +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta1 Receiver is deprecated, upgrade to v1" // +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="" diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index a7f1bece8..a0ce355a1 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2022 The Flux authors +Copyright 2023 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. diff --git a/api/v1beta2/alert_types.go b/api/v1beta2/alert_types.go index 88a008389..b940442e1 100644 --- a/api/v1beta2/alert_types.go +++ b/api/v1beta2/alert_types.go @@ -19,6 +19,8 @@ package v1beta2 import ( "github.com/fluxcd/pkg/apis/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/notification-controller/api/v1" ) const ( @@ -41,7 +43,7 @@ type AlertSpec struct { // EventSources specifies how to filter events based // on the involved object kind, name and namespace. // +required - EventSources []CrossNamespaceObjectReference `json:"eventSources"` + EventSources []v1.CrossNamespaceObjectReference `json:"eventSources"` // ExclusionList specifies a list of Golang regular expressions // to be used for excluding messages. diff --git a/api/v1beta2/receiver_types.go b/api/v1beta2/receiver_types.go index d52a49969..ad801ae5e 100644 --- a/api/v1beta2/receiver_types.go +++ b/api/v1beta2/receiver_types.go @@ -24,6 +24,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/fluxcd/pkg/apis/meta" + + v1 "github.com/fluxcd/notification-controller/api/v1" ) const ( @@ -63,7 +65,7 @@ type ReceiverSpec struct { // A list of resources to be notified about changes. // +required - Resources []CrossNamespaceObjectReference `json:"resources"` + Resources []v1.CrossNamespaceObjectReference `json:"resources"` // SecretRef specifies the Secret containing the token used // to validate the payload authenticity. @@ -128,9 +130,9 @@ func (in *Receiver) GetInterval() time.Duration { // +genclient // +genclient:Namespaced -// +kubebuilder:storageversion // +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta2 Receiver is deprecated, upgrade to v1" // +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="" diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 431aac8ba..20e779047 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2022 The Flux authors +Copyright 2023 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. @@ -22,8 +22,9 @@ limitations under the License. package v1beta2 import ( + "github.com/fluxcd/notification-controller/api/v1" "github.com/fluxcd/pkg/apis/meta" - "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -92,7 +93,7 @@ func (in *AlertSpec) DeepCopyInto(out *AlertSpec) { out.ProviderRef = in.ProviderRef if in.EventSources != nil { in, out := &in.EventSources, &out.EventSources - *out = make([]CrossNamespaceObjectReference, len(*in)) + *out = make([]v1.CrossNamespaceObjectReference, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -120,7 +121,7 @@ func (in *AlertStatus) DeepCopyInto(out *AlertStatus) { out.ReconcileRequestStatus = in.ReconcileRequestStatus if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -223,12 +224,12 @@ func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) { *out = *in if in.Interval != nil { in, out := &in.Interval, &out.Interval - *out = new(v1.Duration) + *out = new(metav1.Duration) **out = **in } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout - *out = new(v1.Duration) + *out = new(metav1.Duration) **out = **in } if in.SecretRef != nil { @@ -259,7 +260,7 @@ func (in *ProviderStatus) DeepCopyInto(out *ProviderStatus) { out.ReconcileRequestStatus = in.ReconcileRequestStatus if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -340,7 +341,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) { *out = *in if in.Interval != nil { in, out := &in.Interval, &out.Interval - *out = new(v1.Duration) + *out = new(metav1.Duration) **out = **in } if in.Events != nil { @@ -350,7 +351,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) { } if in.Resources != nil { in, out := &in.Resources, &out.Resources - *out = make([]CrossNamespaceObjectReference, len(*in)) + *out = make([]v1.CrossNamespaceObjectReference, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -374,7 +375,7 @@ func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) { out.ReconcileRequestStatus = in.ReconcileRequestStatus if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml index 1502aaddb..6ffc4a2aa 100644 --- a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml +++ b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml @@ -256,10 +256,10 @@ spec: to let you locate the typed referenced object at cluster level properties: apiVersion: - description: API version of the referent. + description: API version of the referent type: string kind: - description: Kind of the referent. + description: Kind of the referent enum: - Bucket - GitRepository @@ -279,19 +279,21 @@ spec: {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. + are ANDed. MatchLabels requires the name to be set to `*`. type: object name: - description: Name of the referent. + description: Name of the referent If multiple resources are + targeted `*` may be set. maxLength: 53 minLength: 1 type: string namespace: - description: Namespace of the referent. + description: Namespace of the referent maxLength: 53 minLength: 1 type: string required: + - kind - name type: object type: array diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml index 4291168e0..3f5b5d48e 100644 --- a/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml +++ b/config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml @@ -25,6 +25,231 @@ spec: - 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: + default: 10m + 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: + - kind + - 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 + - secretRef + - 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 + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta1 Receiver is deprecated, upgrade to v1 name: v1beta1 schema: openAPIV3Schema: @@ -227,6 +452,8 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].message name: Status type: string + deprecated: true + deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1 name: v1beta2 schema: openAPIV3Schema: @@ -265,10 +492,10 @@ spec: to let you locate the typed referenced object at cluster level properties: apiVersion: - description: API version of the referent. + description: API version of the referent type: string kind: - description: Kind of the referent. + description: Kind of the referent enum: - Bucket - GitRepository @@ -288,19 +515,21 @@ spec: {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. + are ANDed. MatchLabels requires the name to be set to `*`. type: object name: - description: Name of the referent. + description: Name of the referent If multiple resources are + targeted `*` may be set. maxLength: 53 minLength: 1 type: string namespace: - description: Namespace of the referent. + description: Namespace of the referent maxLength: 53 minLength: 1 type: string required: + - kind - name type: object type: array @@ -434,6 +663,6 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/config/samples/notification_v1beta2_receiver.yaml b/config/samples/notification_v1_receiver.yaml similarity index 86% rename from config/samples/notification_v1beta2_receiver.yaml rename to config/samples/notification_v1_receiver.yaml index 893644d2c..f3c4c2870 100644 --- a/config/samples/notification_v1beta2_receiver.yaml +++ b/config/samples/notification_v1_receiver.yaml @@ -1,4 +1,4 @@ -apiVersion: notification.toolkit.fluxcd.io/v1beta2 +apiVersion: notification.toolkit.fluxcd.io/v1 kind: Receiver metadata: name: receiver-sample 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/alert_controller.go b/controllers/alert_controller.go index 5f3916011..c76476112 100644 --- a/controllers/alert_controller.go +++ b/controllers/alert_controller.go @@ -43,7 +43,8 @@ import ( "github.com/fluxcd/pkg/runtime/predicates" kuberecorder "k8s.io/client-go/tools/record" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2" ) var ( @@ -69,9 +70,9 @@ func (r *AlertReconciler) SetupWithManager(mgr ctrl.Manager) error { } func (r *AlertReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts AlertReconcilerOptions) error { - if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &apiv1.Alert{}, ProviderIndexKey, + if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &apiv1beta2.Alert{}, ProviderIndexKey, func(o client.Object) []string { - alert := o.(*apiv1.Alert) + alert := o.(*apiv1beta2.Alert) return []string{ fmt.Sprintf("%s/%s", alert.GetNamespace(), alert.Spec.ProviderRef.Name), } @@ -81,11 +82,11 @@ func (r *AlertReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts Aler recoverPanic := true return ctrl.NewControllerManagedBy(mgr). - For(&apiv1.Alert{}, builder.WithPredicates( + For(&apiv1beta2.Alert{}, builder.WithPredicates( predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}), )). Watches( - &source.Kind{Type: &apiv1.Provider{}}, + &source.Kind{Type: &apiv1beta2.Provider{}}, handler.EnqueueRequestsFromMapFunc(r.requestsForProviderChange), builder.WithPredicates(predicate.GenerationChangedPredicate{}), ). @@ -105,7 +106,7 @@ func (r *AlertReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu reconcileStart := time.Now() log := ctrl.LoggerFrom(ctx) - obj := &apiv1.Alert{} + obj := &apiv1beta2.Alert{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -158,7 +159,7 @@ func (r *AlertReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu return r.reconcile(ctx, obj) } -func (r *AlertReconciler) reconcile(ctx context.Context, alert *apiv1.Alert) (ctrl.Result, error) { +func (r *AlertReconciler) reconcile(ctx context.Context, alert *apiv1beta2.Alert) (ctrl.Result, error) { // Mark the resource as under reconciliation. conditions.MarkReconciling(alert, meta.ProgressingReason, "Reconciliation in progress") @@ -173,8 +174,8 @@ func (r *AlertReconciler) reconcile(ctx context.Context, alert *apiv1.Alert) (ct return ctrl.Result{}, nil } -func (r *AlertReconciler) isProviderReady(ctx context.Context, alert *apiv1.Alert) error { - provider := &apiv1.Provider{} +func (r *AlertReconciler) isProviderReady(ctx context.Context, alert *apiv1beta2.Alert) error { + provider := &apiv1beta2.Provider{} providerName := types.NamespacedName{Namespace: alert.Namespace, Name: alert.Spec.ProviderRef.Name} if err := r.Get(ctx, providerName, provider); err != nil { // log not found errors since they get filtered out @@ -190,13 +191,13 @@ func (r *AlertReconciler) isProviderReady(ctx context.Context, alert *apiv1.Aler } func (r *AlertReconciler) requestsForProviderChange(o client.Object) []reconcile.Request { - provider, ok := o.(*apiv1.Provider) + provider, ok := o.(*apiv1beta2.Provider) if !ok { panic(fmt.Errorf("expected a provider, got %T", o)) } ctx := context.Background() - var list apiv1.AlertList + var list apiv1beta2.AlertList if err := r.List(ctx, &list, client.MatchingFields{ ProviderIndexKey: client.ObjectKeyFromObject(provider).String(), }); err != nil { @@ -212,7 +213,7 @@ func (r *AlertReconciler) requestsForProviderChange(o client.Object) []reconcile } // patch updates the object status, conditions and finalizers. -func (r *AlertReconciler) patch(ctx context.Context, obj *apiv1.Alert, patcher *patch.SerialPatcher) (retErr error) { +func (r *AlertReconciler) patch(ctx context.Context, obj *apiv1beta2.Alert, patcher *patch.SerialPatcher) (retErr error) { // Configure the runtime patcher. patchOpts := []patch.Option{} ownedConditions := []string{ diff --git a/controllers/alert_controller_test.go b/controllers/alert_controller_test.go index de975f249..1ac059db7 100644 --- a/controllers/alert_controller_test.go +++ b/controllers/alert_controller_test.go @@ -44,36 +44,37 @@ import ( "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/conditions" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2" "github.com/fluxcd/notification-controller/internal/server" ) func TestAlertReconciler_Reconcile(t *testing.T) { g := NewWithT(t) timeout := 5 * time.Second - resultA := &apiv1.Alert{} + resultA := &apiv1beta2.Alert{} namespaceName := "alert-" + randStringRunes(5) providerName := "provider-" + randStringRunes(5) g.Expect(createNamespace(namespaceName)).NotTo(HaveOccurred(), "failed to create test namespace") - provider := &apiv1.Provider{ + provider := &apiv1beta2.Provider{ ObjectMeta: metav1.ObjectMeta{ Name: providerName, Namespace: namespaceName, }, - Spec: apiv1.ProviderSpec{ + Spec: apiv1beta2.ProviderSpec{ Type: "generic", Address: "https://webhook.internal", }, } - alert := &apiv1.Alert{ + alert := &apiv1beta2.Alert{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("alert-%s", randStringRunes(5)), Namespace: namespaceName, }, - Spec: apiv1.AlertSpec{ + Spec: apiv1beta2.AlertSpec{ ProviderRef: meta.LocalObjectReference{ Name: providerName, }, @@ -165,7 +166,7 @@ func TestAlertReconciler_EventHandler(t *testing.T) { var ( namespace = "events-" + randStringRunes(5) req *http.Request - provider *apiv1.Provider + provider *apiv1beta2.Provider ) g.Expect(createNamespace(namespace)).NotTo(HaveOccurred(), "failed to create test namespace") @@ -200,19 +201,19 @@ func TestAlertReconciler_EventHandler(t *testing.T) { Name: fmt.Sprintf("provider-%s", randStringRunes(5)), Namespace: namespace, } - provider = &apiv1.Provider{ + provider = &apiv1beta2.Provider{ ObjectMeta: metav1.ObjectMeta{ Name: providerKey.Name, Namespace: providerKey.Namespace, }, - Spec: apiv1.ProviderSpec{ + Spec: apiv1beta2.ProviderSpec{ Type: "generic", Address: rcvServer.URL, }, } g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed()) g.Eventually(func() bool { - var obj apiv1.Provider + var obj apiv1beta2.Provider g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), &obj)) return conditions.IsReady(&obj) }, 30*time.Second, time.Second).Should(BeTrue()) @@ -238,12 +239,12 @@ func TestAlertReconciler_EventHandler(t *testing.T) { Namespace: namespace, } - alert := &apiv1.Alert{ + alert := &apiv1beta2.Alert{ ObjectMeta: metav1.ObjectMeta{ Name: alertKey.Name, Namespace: alertKey.Namespace, }, - Spec: apiv1.AlertSpec{ + Spec: apiv1beta2.AlertSpec{ ProviderRef: meta.LocalObjectReference{ Name: providerKey.Name, }, @@ -282,7 +283,7 @@ func TestAlertReconciler_EventHandler(t *testing.T) { // wait for controller to mark the alert as ready g.Eventually(func() bool { - var obj apiv1.Alert + var obj apiv1beta2.Alert g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), &obj)) return conditions.IsReady(&obj) }, 30*time.Second, time.Second).Should(BeTrue()) diff --git a/controllers/provider_controller.go b/controllers/provider_controller.go index 5dc23eb76..1568f6889 100644 --- a/controllers/provider_controller.go +++ b/controllers/provider_controller.go @@ -43,7 +43,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" + apiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2" "github.com/fluxcd/notification-controller/internal/notifier" ) @@ -68,7 +69,7 @@ func (r *ProviderReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ProviderReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts ProviderReconcilerOptions) error { recoverPanic := true return ctrl.NewControllerManagedBy(mgr). - For(&apiv1.Provider{}, builder.WithPredicates( + For(&apiv1beta2.Provider{}, builder.WithPredicates( predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}), )). WithOptions(controller.Options{ @@ -88,7 +89,7 @@ func (r *ProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r reconcileStart := time.Now() log := ctrl.LoggerFrom(ctx) - obj := &apiv1.Provider{} + obj := &apiv1beta2.Provider{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -150,7 +151,7 @@ func (r *ProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r return r.reconcile(ctx, obj) } -func (r *ProviderReconciler) reconcile(ctx context.Context, obj *apiv1.Provider) (ctrl.Result, error) { +func (r *ProviderReconciler) reconcile(ctx context.Context, obj *apiv1beta2.Provider) (ctrl.Result, error) { // Mark the resource as under reconciliation. conditions.MarkReconciling(obj, meta.ProgressingReason, "Reconciliation in progress") conditions.Delete(obj, meta.StalledCondition) @@ -173,7 +174,7 @@ func (r *ProviderReconciler) reconcile(ctx context.Context, obj *apiv1.Provider) return ctrl.Result{RequeueAfter: obj.GetInterval()}, nil } -func (r *ProviderReconciler) validateURLs(provider *apiv1.Provider) error { +func (r *ProviderReconciler) validateURLs(provider *apiv1beta2.Provider) error { address := provider.Spec.Address proxy := provider.Spec.Proxy @@ -188,7 +189,7 @@ func (r *ProviderReconciler) validateURLs(provider *apiv1.Provider) error { return nil } -func (r *ProviderReconciler) validateCredentials(ctx context.Context, provider *apiv1.Provider) error { +func (r *ProviderReconciler) validateCredentials(ctx context.Context, provider *apiv1beta2.Provider) error { address := provider.Spec.Address proxy := provider.Spec.Proxy username := provider.Spec.Username @@ -265,7 +266,7 @@ func (r *ProviderReconciler) validateCredentials(ctx context.Context, provider * } // patch updates the object status, conditions and finalizers. -func (r *ProviderReconciler) patch(ctx context.Context, obj *apiv1.Provider, patcher *patch.SerialPatcher) (retErr error) { +func (r *ProviderReconciler) patch(ctx context.Context, obj *apiv1beta2.Provider, patcher *patch.SerialPatcher) (retErr error) { // Configure the runtime patcher. patchOpts := []patch.Option{} ownedConditions := []string{ diff --git a/controllers/provider_controller_test.go b/controllers/provider_controller_test.go index 689d21df2..ea531e677 100644 --- a/controllers/provider_controller_test.go +++ b/controllers/provider_controller_test.go @@ -33,13 +33,14 @@ import ( "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/runtime/conditions" - apiv1 "github.com/fluxcd/notification-controller/api/v1beta2" + apiv1 "github.com/fluxcd/notification-controller/api/v1" + apiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2" ) func TestProviderReconciler_Reconcile(t *testing.T) { g := NewWithT(t) timeout := 5 * time.Second - resultP := &apiv1.Provider{} + resultP := &apiv1beta2.Provider{} namespaceName := "provider-" + randStringRunes(5) secretName := "secret-" + randStringRunes(5) @@ -49,12 +50,12 @@ func TestProviderReconciler_Reconcile(t *testing.T) { Name: fmt.Sprintf("provider-%s", randStringRunes(5)), Namespace: namespaceName, } - provider := &apiv1.Provider{ + provider := &apiv1beta2.Provider{ ObjectMeta: metav1.ObjectMeta{ Name: providerKey.Name, Namespace: providerKey.Namespace, }, - Spec: apiv1.ProviderSpec{ + Spec: apiv1beta2.ProviderSpec{ Type: "generic", Address: "https://webhook.internal", }, diff --git a/controllers/receiver_controller.go b/controllers/receiver_controller.go index f441fc1cc..3d658781f 100644 --- a/controllers/receiver_controller.go +++ b/controllers/receiver_controller.go @@ -40,7 +40,7 @@ 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" ) // ReceiverReconciler reconciles a Receiver object diff --git a/controllers/receiver_controller_test.go b/controllers/receiver_controller_test.go index 0f123469f..60738f0d6 100644 --- a/controllers/receiver_controller_test.go +++ b/controllers/receiver_controller_test.go @@ -39,7 +39,7 @@ 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" "github.com/fluxcd/notification-controller/internal/server" ) @@ -102,6 +102,7 @@ func TestReceiverReconciler_Reconcile(t *testing.T) { g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse()) g.Expect(controllerutil.ContainsFinalizer(resultR, apiv1.NotificationFinalizer)).To(BeTrue()) + g.Expect(resultR.Spec.Interval.Duration).To(BeIdenticalTo(10 * time.Minute)) }) t.Run("fails with secret not found error", func(t *testing.T) { 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..8bfad07ad --- /dev/null +++ b/docs/api/v1/notification.md @@ -0,0 +1,442 @@ +

Notification API reference v1

+

Packages:

+ +

notification.toolkit.fluxcd.io/v1

+

Package v1 contains API Schema definitions for the notification v1 API group.

+Resource Types: + +

Receiver +

+

Receiver is the Schema for the receivers API.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+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 + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+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.

+
+
+status
+ + +ReceiverStatus + + +
+
+
+
+

CrossNamespaceObjectReference +

+

+(Appears on: +ReceiverSpec) +

+

CrossNamespaceObjectReference contains enough information to let you locate the +typed referenced object at cluster level

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+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.

+
+
+
+

ReceiverSpec +

+

+(Appears on: +Receiver) +

+

ReceiverSpec defines the desired state of the Receiver.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+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.

+
+
+
+

ReceiverStatus +

+

+(Appears on: +Receiver) +

+

ReceiverStatus defines the observed state of the Receiver.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+ReconcileRequestStatus
+ + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus + + +
+

+(Members of ReconcileRequestStatus are embedded into this type.) +

+
+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

+
diff --git a/docs/api/notification.md b/docs/api/v1beta2/notification.md similarity index 89% rename from docs/api/notification.md rename to docs/api/v1beta2/notification.md index cc2837b5e..c2d7a56de 100644 --- a/docs/api/notification.md +++ b/docs/api/v1beta2/notification.md @@ -1,4 +1,4 @@ -

Notification API reference

+

Notification API reference v1beta2

Packages: