Merge pull request #83 from relu/adopt-k8s-conditions

Refactor to adopt k8s standardized Condition type
This commit is contained in:
Stefan Prodan 2020-11-19 21:32:43 +02:00 committed by GitHub
commit 2d4c6e31ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 218 additions and 160 deletions

View File

@ -3,7 +3,7 @@ module github.com/fluxcd/notification-controller/api
go 1.15 go 1.15
require ( require (
github.com/fluxcd/pkg/apis/meta v0.2.0 github.com/fluxcd/pkg/apis/meta v0.4.0
k8s.io/api v0.19.3 k8s.io/api v0.19.3
k8s.io/apimachinery v0.19.3 k8s.io/apimachinery v0.19.3
sigs.k8s.io/controller-runtime v0.6.3 sigs.k8s.io/controller-runtime v0.6.3

View File

@ -61,8 +61,8 @@ github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fluxcd/pkg/apis/meta v0.2.0 h1:bxoFQtZM6OLLj0+n3h6ga7IEWUtGEDJPc65OWiXSMvY= github.com/fluxcd/pkg/apis/meta v0.4.0 h1:JChqB9GGgorW9HWKxirTVV0rzrcLyzBaVjinmqZ0iHA=
github.com/fluxcd/pkg/apis/meta v0.2.0/go.mod h1:50RLLSfqM4LlQrh/+5LiJVf7Hjdthee8WDdXBvpjBdA= github.com/fluxcd/pkg/apis/meta v0.4.0/go.mod h1:wOzQQx8CdtUQCGaLzqGu4QgnNxYkI6/wvdvlovxWhF0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=

View File

@ -19,8 +19,6 @@ package v1beta1
import ( import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
) )
// AlertSpec defines an alerting rule for events involving a list of objects // AlertSpec defines an alerting rule for events involving a list of objects
@ -49,7 +47,7 @@ type AlertSpec struct {
// AlertStatus defines the observed state of Alert // AlertStatus defines the observed state of Alert
type AlertStatus struct { type AlertStatus struct {
// +optional // +optional
Conditions []meta.Condition `json:"conditions,omitempty"` Conditions []metav1.Condition `json:"conditions,omitempty"`
} }
// +genclient // +genclient
@ -69,6 +67,11 @@ type Alert struct {
Status AlertStatus `json:"status,omitempty"` Status AlertStatus `json:"status,omitempty"`
} }
// GetStatusConditions returns a pointer to the Status.Conditions slice
func (in *Alert) GetStatusConditions() *[]metav1.Condition {
return &in.Status.Conditions
}
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// AlertList contains a list of Alert // AlertList contains a list of Alert

View File

@ -19,8 +19,6 @@ package v1beta1
import ( import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
) )
// ProviderSpec defines the desired state of Provider // ProviderSpec defines the desired state of Provider
@ -69,7 +67,7 @@ const (
// ProviderStatus defines the observed state of Provider // ProviderStatus defines the observed state of Provider
type ProviderStatus struct { type ProviderStatus struct {
// +optional // +optional
Conditions []meta.Condition `json:"conditions,omitempty"` Conditions []metav1.Condition `json:"conditions,omitempty"`
} }
// +genclient // +genclient
@ -89,6 +87,11 @@ type Provider struct {
Status ProviderStatus `json:"status,omitempty"` Status ProviderStatus `json:"status,omitempty"`
} }
// GetStatusConditions returns a pointer to the Status.Conditions slice
func (in *Provider) GetStatusConditions() *[]metav1.Condition {
return &in.Status.Conditions
}
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// ProviderList contains a list of Provider // ProviderList contains a list of Provider

View File

@ -54,7 +54,7 @@ type ReceiverSpec struct {
// ReceiverStatus defines the observed state of Receiver // ReceiverStatus defines the observed state of Receiver
type ReceiverStatus struct { type ReceiverStatus struct {
// +optional // +optional
Conditions []meta.Condition `json:"conditions,omitempty"` Conditions []metav1.Condition `json:"conditions,omitempty"`
// Generated webhook URL in the format // Generated webhook URL in the format
// of '/hook/sha256sum(token+name+namespace)'. // of '/hook/sha256sum(token+name+namespace)'.
@ -71,32 +71,19 @@ const (
) )
func ReceiverReady(receiver Receiver, reason, message, url string) Receiver { func ReceiverReady(receiver Receiver, reason, message, url string) Receiver {
receiver.Status.Conditions = []meta.Condition{ meta.SetResourceCondition(&receiver, meta.ReadyCondition, metav1.ConditionTrue, reason, message)
{
Type: meta.ReadyCondition,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: reason,
Message: message,
},
}
receiver.Status.URL = url receiver.Status.URL = url
return receiver return receiver
} }
func ReceiverNotReady(receiver Receiver, reason, message string) Receiver { func ReceiverNotReady(receiver Receiver, reason, message string) Receiver {
receiver.Status.Conditions = []meta.Condition{ meta.SetResourceCondition(&receiver, meta.ReadyCondition, metav1.ConditionFalse, reason, message)
{ return receiver
Type: meta.ReadyCondition,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: reason,
Message: message,
},
} }
return receiver // GetStatusConditions returns a pointer to the Status.Conditions slice
func (in *Receiver) GetStatusConditions() *[]metav1.Condition {
return &in.Status.Conditions
} }
// +genclient // +genclient

View File

@ -21,8 +21,8 @@ limitations under the License.
package v1beta1 package v1beta1
import ( import (
"github.com/fluxcd/pkg/apis/meta" corev1 "k8s.io/api/core/v1"
"k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
) )
@ -111,7 +111,7 @@ func (in *AlertStatus) DeepCopyInto(out *AlertStatus) {
*out = *in *out = *in
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]meta.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -207,7 +207,7 @@ func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
*out = *in *out = *in
if in.SecretRef != nil { if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef in, out := &in.SecretRef, &out.SecretRef
*out = new(v1.LocalObjectReference) *out = new(corev1.LocalObjectReference)
**out = **in **out = **in
} }
} }
@ -227,7 +227,7 @@ func (in *ProviderStatus) DeepCopyInto(out *ProviderStatus) {
*out = *in *out = *in
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]meta.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -334,7 +334,7 @@ func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) {
*out = *in *out = *in
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]meta.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }

View File

@ -109,30 +109,69 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains condition information of a toolkit description: "Condition contains details for one aspect of the current
resource. state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
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: properties:
lastTransitionTime: lastTransitionTime:
description: LastTransitionTime is the timestamp corresponding description: lastTransitionTime is the last time the condition
to the last status change of this 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 format: date-time
type: string type: string
message: message:
description: Message is a human readable description of the description: message is a human readable message indicating
details of the last transition, complementing reason. details about the transition. This may be an empty string.
maxLength: 32768
type: string 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: reason:
description: Reason is a brief machine readable explanation description: reason contains a programmatic identifier indicating
for the condition's last transition. 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 type: string
status: status:
description: Status of the condition, one of ('True', 'False', description: status of the condition, one of True, False, Unknown.
'Unknown'). enum:
- "True"
- "False"
- Unknown
type: string type: string
type: type:
description: Type of the condition. 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 type: string
required: required:
- lastTransitionTime
- message
- reason
- status - status
- type - type
type: object type: object

View File

@ -88,30 +88,69 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains condition information of a toolkit description: "Condition contains details for one aspect of the current
resource. state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
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: properties:
lastTransitionTime: lastTransitionTime:
description: LastTransitionTime is the timestamp corresponding description: lastTransitionTime is the last time the condition
to the last status change of this 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 format: date-time
type: string type: string
message: message:
description: Message is a human readable description of the description: message is a human readable message indicating
details of the last transition, complementing reason. details about the transition. This may be an empty string.
maxLength: 32768
type: string 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: reason:
description: Reason is a brief machine readable explanation description: reason contains a programmatic identifier indicating
for the condition's last transition. 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 type: string
status: status:
description: Status of the condition, one of ('True', 'False', description: status of the condition, one of True, False, Unknown.
'Unknown'). enum:
- "True"
- "False"
- Unknown
type: string type: string
type: type:
description: Type of the condition. 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 type: string
required: required:
- lastTransitionTime
- message
- reason
- status - status
- type - type
type: object type: object

View File

@ -117,30 +117,69 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains condition information of a toolkit description: "Condition contains details for one aspect of the current
resource. state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
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: properties:
lastTransitionTime: lastTransitionTime:
description: LastTransitionTime is the timestamp corresponding description: lastTransitionTime is the last time the condition
to the last status change of this 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 format: date-time
type: string type: string
message: message:
description: Message is a human readable description of the description: message is a human readable message indicating
details of the last transition, complementing reason. details about the transition. This may be an empty string.
maxLength: 32768
type: string 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: reason:
description: Reason is a brief machine readable explanation description: reason contains a programmatic identifier indicating
for the condition's last transition. 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 type: string
status: status:
description: Status of the condition, one of ('True', 'False', description: status of the condition, one of True, False, Unknown.
'Unknown'). enum:
- "True"
- "False"
- Unknown
type: string type: string
type: type:
description: Type of the condition. 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 type: string
required: required:
- lastTransitionTime
- message
- reason
- status - status
- type - type
type: object type: object

View File

@ -23,7 +23,7 @@ import (
"time" "time"
"github.com/go-logr/logr" "github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1" apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -71,38 +71,15 @@ func (r *AlertReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
// validate alert spec and provider // validate alert spec and provider
if err := r.validate(ctx, alert); err != nil { if err := r.validate(ctx, alert); err != nil {
alert.Status.Conditions = []meta.Condition{ meta.SetResourceCondition(&alert, meta.ReadyCondition, metav1.ConditionFalse, meta.ReconciliationFailedReason, err.Error())
{
Type: meta.ReadyCondition,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: meta.ReconciliationFailedReason,
Message: err.Error(),
},
}
if err := r.Status().Update(ctx, &alert); err != nil { if err := r.Status().Update(ctx, &alert); err != nil {
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
init := true if !apimeta.IsStatusConditionTrue(alert.Status.Conditions, meta.ReadyCondition) {
if c := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil { meta.SetResourceCondition(&alert, meta.ReadyCondition, metav1.ConditionTrue, v1beta1.InitializedReason, v1beta1.InitializedReason)
if c.Status == corev1.ConditionTrue {
init = false
}
}
if init {
alert.Status.Conditions = []meta.Condition{
{
Type: meta.ReadyCondition,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: v1beta1.InitializedReason,
Message: v1beta1.InitializedReason,
},
}
if err := r.Status().Update(ctx, &alert); err != nil { if err := r.Status().Update(ctx, &alert); err != nil {
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
@ -128,7 +105,7 @@ func (r *AlertReconciler) validate(ctx context.Context, alert v1beta1.Alert) err
return fmt.Errorf("failed to get provider %s, error: %w", providerName.String(), err) return fmt.Errorf("failed to get provider %s, error: %w", providerName.String(), err)
} }
if !meta.HasReadyCondition(provider.Status.Conditions) { if !apimeta.IsStatusConditionTrue(provider.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("provider %s is not ready", providerName.String()) return fmt.Errorf("provider %s is not ready", providerName.String())
} }
@ -148,12 +125,12 @@ func (r *AlertReconciler) recordReadiness(alert v1beta1.Alert, deleted bool) {
).Error(err, "unable to record readiness metric") ).Error(err, "unable to record readiness metric")
return return
} }
if rc := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); rc != nil { if rc := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); rc != nil {
r.MetricsRecorder.RecordCondition(*objRef, *rc, deleted) r.MetricsRecorder.RecordCondition(*objRef, *rc, deleted)
} else { } else {
r.MetricsRecorder.RecordCondition(*objRef, meta.Condition{ r.MetricsRecorder.RecordCondition(*objRef, metav1.Condition{
Type: meta.ReadyCondition, Type: meta.ReadyCondition,
Status: corev1.ConditionUnknown, Status: metav1.ConditionUnknown,
}, deleted) }, deleted)
} }
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/go-logr/logr" "github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -72,38 +73,15 @@ func (r *ProviderReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
// validate provider spec and credentials // validate provider spec and credentials
if err := r.validate(ctx, provider); err != nil { if err := r.validate(ctx, provider); err != nil {
provider.Status.Conditions = []meta.Condition{ meta.SetResourceCondition(&provider, meta.ReadyCondition, metav1.ConditionFalse, meta.ReconciliationFailedReason, err.Error())
{
Type: meta.ReadyCondition,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: meta.ReconciliationFailedReason,
Message: err.Error(),
},
}
if err := r.Status().Update(ctx, &provider); err != nil { if err := r.Status().Update(ctx, &provider); err != nil {
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
init := true if !apimeta.IsStatusConditionTrue(provider.Status.Conditions, meta.ReadyCondition) {
if c := meta.GetCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil { meta.SetResourceCondition(&provider, meta.ReadyCondition, metav1.ConditionTrue, v1beta1.InitializedReason, v1beta1.InitializedReason)
if c.Status == corev1.ConditionTrue {
init = false
}
}
if init {
provider.Status.Conditions = []meta.Condition{
{
Type: meta.ReadyCondition,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: v1beta1.InitializedReason,
Message: v1beta1.InitializedReason,
},
}
if err := r.Status().Update(ctx, &provider); err != nil { if err := r.Status().Update(ctx, &provider); err != nil {
return ctrl.Result{Requeue: true}, err return ctrl.Result{Requeue: true}, err
} }
@ -165,12 +143,12 @@ func (r *ProviderReconciler) recordReadiness(provider v1beta1.Provider, deleted
).Error(err, "unable to record readiness metric") ).Error(err, "unable to record readiness metric")
return return
} }
if rc := meta.GetCondition(provider.Status.Conditions, meta.ReadyCondition); rc != nil { if rc := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); rc != nil {
r.MetricsRecorder.RecordCondition(*objRef, *rc, deleted) r.MetricsRecorder.RecordCondition(*objRef, *rc, deleted)
} else { } else {
r.MetricsRecorder.RecordCondition(*objRef, meta.Condition{ r.MetricsRecorder.RecordCondition(*objRef, metav1.Condition{
Type: meta.ReadyCondition, Type: meta.ReadyCondition,
Status: corev1.ConditionUnknown, Status: metav1.ConditionUnknown,
}, deleted) }, deleted)
} }
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/go-logr/logr" "github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
@ -69,13 +70,8 @@ func (r *ReceiverReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
} }
} }
isReady := false isReady := apimeta.IsStatusConditionTrue(receiver.Status.Conditions, meta.ReadyCondition)
if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
isReady = c.Status == corev1.ConditionTrue
}
receiverURL := fmt.Sprintf("/hook/%s", sha256sum(token+receiver.Name+receiver.Namespace)) receiverURL := fmt.Sprintf("/hook/%s", sha256sum(token+receiver.Name+receiver.Namespace))
if receiver.Status.URL == receiverURL && isReady { if receiver.Status.URL == receiverURL && isReady {
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }

View File

@ -527,8 +527,8 @@ Defaults to false.</p>
<td> <td>
<code>conditions</code><br> <code>conditions</code><br>
<em> <em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#Condition"> <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#condition-v1-meta">
[]github.com/fluxcd/pkg/apis/meta.Condition []Kubernetes meta/v1.Condition
</a> </a>
</em> </em>
</td> </td>
@ -724,8 +724,8 @@ Kubernetes core/v1.LocalObjectReference
<td> <td>
<code>conditions</code><br> <code>conditions</code><br>
<em> <em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#Condition"> <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#condition-v1-meta">
[]github.com/fluxcd/pkg/apis/meta.Condition []Kubernetes meta/v1.Condition
</a> </a>
</em> </em>
</td> </td>
@ -844,8 +844,8 @@ Defaults to false.</p>
<td> <td>
<code>conditions</code><br> <code>conditions</code><br>
<em> <em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#Condition"> <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#condition-v1-meta">
[]github.com/fluxcd/pkg/apis/meta.Condition []Kubernetes meta/v1.Condition
</a> </a>
</em> </em>
</td> </td>

8
go.mod
View File

@ -5,11 +5,11 @@ go 1.15
replace github.com/fluxcd/notification-controller/api => ./api replace github.com/fluxcd/notification-controller/api => ./api
require ( require (
github.com/fluxcd/notification-controller/api v0.2.0 github.com/fluxcd/notification-controller/api v0.2.1
github.com/fluxcd/pkg/apis/meta v0.2.0 github.com/fluxcd/pkg/apis/meta v0.4.0
github.com/fluxcd/pkg/recorder v0.0.6 github.com/fluxcd/pkg/recorder v0.0.6
github.com/fluxcd/pkg/runtime v0.2.0 github.com/fluxcd/pkg/runtime v0.3.0
github.com/fluxcd/source-controller/api v0.2.0 github.com/fluxcd/source-controller/api v0.3.0
github.com/go-logr/logr v0.2.1 github.com/go-logr/logr v0.2.1
github.com/google/go-github/v32 v32.0.0 github.com/google/go-github/v32 v32.0.0
github.com/hashicorp/go-retryablehttp v0.6.7 github.com/hashicorp/go-retryablehttp v0.6.7

19
go.sum
View File

@ -85,16 +85,15 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fluxcd/pkg/apis/meta v0.0.2 h1:kyA4Y0IzNjf1joBOnFqpWG7aNDHvtLExZcaHQM7qhRI= github.com/fluxcd/pkg/apis/meta v0.3.0/go.mod h1:wOzQQx8CdtUQCGaLzqGu4QgnNxYkI6/wvdvlovxWhF0=
github.com/fluxcd/pkg/apis/meta v0.0.2/go.mod h1:nCNps5JJOcEQr3MNDmZqI4o0chjePSUYL6Q2ktDtotU= github.com/fluxcd/pkg/apis/meta v0.4.0 h1:JChqB9GGgorW9HWKxirTVV0rzrcLyzBaVjinmqZ0iHA=
github.com/fluxcd/pkg/apis/meta v0.2.0 h1:bxoFQtZM6OLLj0+n3h6ga7IEWUtGEDJPc65OWiXSMvY= github.com/fluxcd/pkg/apis/meta v0.4.0/go.mod h1:wOzQQx8CdtUQCGaLzqGu4QgnNxYkI6/wvdvlovxWhF0=
github.com/fluxcd/pkg/apis/meta v0.2.0/go.mod h1:50RLLSfqM4LlQrh/+5LiJVf7Hjdthee8WDdXBvpjBdA=
github.com/fluxcd/pkg/recorder v0.0.6 h1:me/n8syeeGXz50OXoPX3jgIj9AtinvhHdKT9Dy+MbHs= github.com/fluxcd/pkg/recorder v0.0.6 h1:me/n8syeeGXz50OXoPX3jgIj9AtinvhHdKT9Dy+MbHs=
github.com/fluxcd/pkg/recorder v0.0.6/go.mod h1:IfQxfVRSNsWs3B0Yp5B6ObEWwKHILlAx8N7XkoDdhFg= github.com/fluxcd/pkg/recorder v0.0.6/go.mod h1:IfQxfVRSNsWs3B0Yp5B6ObEWwKHILlAx8N7XkoDdhFg=
github.com/fluxcd/pkg/runtime v0.2.0 h1:aZmSLuyA9pF/KANf4wi7pZIICE19BKTYFSPRbl6WHtY= github.com/fluxcd/pkg/runtime v0.3.0 h1:WpeTmDT2meIe4NsU081I8zmUGgTYs3bIMRgs9F3Lj90=
github.com/fluxcd/pkg/runtime v0.2.0/go.mod h1:P1/S8TOSuJgVPU0SRahWzbNxLWYoUwvBcPCNGc+dWWg= github.com/fluxcd/pkg/runtime v0.3.0/go.mod h1:gPe6JgfPB4EDh5gaVkuI0SPuATk3PmclbFa1kPcZrKE=
github.com/fluxcd/source-controller/api v0.2.0 h1:a+N8+kLDH24lN2hp3klIFGuET3uMhhBWTM9qKdIRhM8= github.com/fluxcd/source-controller/api v0.3.0 h1:liDV8tqpBeQp7KDdVxX9YYb6gFoO7v2hyIFXudw2vQg=
github.com/fluxcd/source-controller/api v0.2.0/go.mod h1:1ac/vj49YVPKF+xBHTo/9pfFj64TcLc1RLaxi4MwVEM= github.com/fluxcd/source-controller/api v0.3.0/go.mod h1:MYmvbADJp/21m4C+PEY7WXCeqEErMYuhns+jnKyewqs=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -617,8 +616,6 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI=
k8s.io/api v0.18.8 h1:aIKUzJPb96f3fKec2lxtY7acZC9gQNDLVhfSGpxBAC4= k8s.io/api v0.18.8 h1:aIKUzJPb96f3fKec2lxtY7acZC9gQNDLVhfSGpxBAC4=
k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY=
k8s.io/api v0.18.9 h1:7VDtivqwbvLOf8hmXSd/PDSSbpCBq49MELg84EYBYiQ=
k8s.io/api v0.18.9/go.mod h1:9u/h6sUh6FxfErv7QqetX1EB3yBMIYOBXzdcf0Gf0rc=
k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU= k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU=
k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs=
k8s.io/apiextensions-apiserver v0.18.6 h1:vDlk7cyFsDyfwn2rNAO2DbmUbvXy5yT5GE3rrqOzaMo= k8s.io/apiextensions-apiserver v0.18.6 h1:vDlk7cyFsDyfwn2rNAO2DbmUbvXy5yT5GE3rrqOzaMo=
@ -626,8 +623,6 @@ k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKi
k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
k8s.io/apimachinery v0.18.8 h1:jimPrycCqgx2QPearX3to1JePz7wSbVLq+7PdBTTwQ0= k8s.io/apimachinery v0.18.8 h1:jimPrycCqgx2QPearX3to1JePz7wSbVLq+7PdBTTwQ0=
k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig=
k8s.io/apimachinery v0.18.9 h1:3ZABKQx3F3xPWlsGhCfUl8W+JXRRblV6Wo2A3zn0pvY=
k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk=
k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc= k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc=
k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg= k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg=

View File

@ -16,8 +16,8 @@
"docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}" "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}"
}, },
{ {
"typeMatchPrefix": "^github.com/fluxcd/pkg/apis/meta\\.Condition$", "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Condition$",
"docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/apis/meta#Condition" "docsURLTemplate": "https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Condition"
} }
], ],
"typeDisplayNamePrefixOverrides": { "typeDisplayNamePrefixOverrides": {

View File

@ -24,6 +24,7 @@ import (
"time" "time"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
@ -66,7 +67,8 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
alerts := make([]v1beta1.Alert, 0) alerts := make([]v1beta1.Alert, 0)
for _, alert := range allAlerts.Items { for _, alert := range allAlerts.Items {
// skip suspended and not ready alerts // skip suspended and not ready alerts
if alert.Spec.Suspend || !meta.HasReadyCondition(alert.Status.Conditions) { isReady := apimeta.IsStatusConditionTrue(alert.Status.Conditions, meta.ReadyCondition)
if alert.Spec.Suspend || !isReady {
continue continue
} }