Skip to content

Commit

Permalink
Merge pull request #101 from fluxcd/conditions-patch-helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddeco authored Jul 7, 2021
2 parents 70e2be0 + b7eec63 commit 11abd07
Show file tree
Hide file tree
Showing 62 changed files with 4,863 additions and 399 deletions.
3 changes: 1 addition & 2 deletions apis/kustomize/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// Package kustomize contains a selective set of Kustomize APIs for use by
// toolkit components.
// Package kustomize contains a selective set of Kustomize API types for use by GitOps Toolkit components.
// +kubebuilder:object:generate=true
package kustomize
46 changes: 25 additions & 21 deletions apis/kustomize/kustomize_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)

// Image contains an image name, a new name, a new tag or digest,
// which will replace the original name and tag.
// Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag.
type Image struct {
// Name is a tag-less image name.
// +required
Expand All @@ -41,19 +40,17 @@ type Image struct {
Digest string `json:"digest,omitempty"`
}

// Selector specifies a set of resources.
// Any resource that matches intersection of all conditions is included in this set.
// Selector specifies a set of resources. Any resource that matches intersection of all conditions is included in this
// set.
type Selector struct {
// Group is the API group to select resources from.
// Together with Version and Kind it is capable of unambiguously
// identifying and/or selecting resources.
// Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources.
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
// +optional
Group string `json:"group,omitempty"`

// Version of the API Group to select resources from.
// Together with Group and Kind it is capable of unambiguously
// identifying and/or selecting resources.
// Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources.
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
// +optional
Version string `json:"version,omitempty"`
Expand Down Expand Up @@ -86,44 +83,51 @@ type Selector struct {
LabelSelector string `json:"labelSelector,omitempty"`
}

// Patch contains either a StrategicMerge or a JSON6902 patch, either a file or inline,
// and the target the patch should be applied to.
// Patch contains either a StrategicMerge or a JSON6902 patch, either a file or inline, and the target the patch should
// be applied to.
type Patch struct {
// Patch contains the JSON6902 patch document with an array of
// operation objects.
// Patch contains the JSON6902 patch document with an array of operation objects.
// +required
Patch string `json:"patch,omitempty"`

// Target points to the resources that the patch document should
// be applied to.
// Target points to the resources that the patch document should be applied to.
// +optional
Target Selector `json:"target,omitempty"`
}

// JSON6902 is a JSON6902 operation object.
// https://tools.ietf.org/html/rfc6902#section-4
// https://datatracker.ietf.org/doc/html/rfc6902#section-4
type JSON6902 struct {
// Op indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or
// "test".
// https://datatracker.ietf.org/doc/html/rfc6902#section-4
// +kubebuilder:validation:Enum=test;remove;add;replace;move;copy
// +required
Op string `json:"op"`

// Path contains the JSON-pointer value that references a location within the target document where the operation
// is performed. The meaning of the value depends on the value of Op.
// +required
Path string `json:"path"`

// From contains a JSON-pointer value that references a location within the target document where the operation is
// performed. The meaning of the value depends on the value of Op, and is NOT taken into account by all operations.
// +optional
From string `json:"from,omitempty"`

// Value contains a valid JSON structure. The meaning of the value depends on the value of Op, and is NOT taken into
// account by all operations.
// +optional
Value *apiextensionsv1.JSON `json:"value,omitempty"`
}

// JSON6902Patch contains a JSON6902 patch and the target the patch
// should be applied to.
// JSON6902Patch contains a JSON6902 patch and the target the patch should be applied to.
type JSON6902Patch struct {
// Patch contains the JSON6902 patch document with an array of
// operation objects.
// Patch contains the JSON6902 patch document with an array of operation objects.
// +required
Patch []JSON6902 `json:"patch"`

// Target points to the resources that the patch document should
// be applied to.
// Target points to the resources that the patch document should be applied to.
// +required
Target Selector `json:"target"`
}
57 changes: 35 additions & 22 deletions apis/meta/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ const (
// outside of the defined schedule. Despite the name, the value is not
// interpreted as a timestamp, and any change in value shall trigger a
// reconciliation.
// DEPRECATED: has been replaced by ReconcileRequestAnnotation.
// DEPRECATED: has been replaced by ReconcileRequestAnnotation. For
// backward-compatibility, use ReconcileAnnotationValue, which will account for
// both annotations.
ReconcileAtAnnotation string = "fluxcd.io/reconcileAt"

// ReconcileRequestAnnotation is the new ReconcileAtAnnotation,
// with a better name. For backward-compatibility, use
// ReconcileAnnotationValue, which will account for both
// annotations.
// ReconcileRequestAnnotation is the annotation used for triggering a reconciliation
// outside of a defined schedule. The value is interpreted as a token, and any change
// in value SHOULD trigger a reconciliation.
ReconcileRequestAnnotation string = "reconcile.fluxcd.io/requestedAt"
)

// ReconcileAnnotationValue returns a value for the reconciliation
// request annotations, which can be used to detect changes; and, a
// boolean indicating whether either annotation was set.
// ReconcileAnnotationValue returns a value for the reconciliation request annotations, which can be used to detect
// changes; and, a boolean indicating whether either annotation was set.
func ReconcileAnnotationValue(annotations map[string]string) (string, bool) {
reconcileAt, ok1 := annotations[ReconcileAtAnnotation]
requestedAt, ok2 := annotations[ReconcileRequestAnnotation]
Expand All @@ -49,27 +49,40 @@ func ReconcileAnnotationValue(annotations map[string]string) (string, bool) {
return reconcileAt + requestedAt, ok1 || ok2
}

// ReconcileRequestStatus is a struct to embed in the status type, so
// that all types using the mechanism have the same field. Use it like
// this:
// ReconcileRequestStatus is a struct to embed in a status type, so that all types using the mechanism have the same
// field. Use it like this:
//
// ```
// type WhateverStatus struct {
// meta.ReconcileRequestStatus `json:",inline"`
// // other status fields...
// }
// ```
// type FooStatus struct {
// meta.ReconcileRequestStatus `json:",inline"`
// // other status fields...
// }
type ReconcileRequestStatus struct {
// LastHandledReconcileAt holds the value of the most recent
// reconcile request value, so a change can be detected.
// reconcile request value, so a change of the annotation value
// can be detected.
// +optional
LastHandledReconcileAt string `json:"lastHandledReconcileAt,omitempty"`
}

func (rs ReconcileRequestStatus) GetLastHandledReconcileRequest() string {
return rs.LastHandledReconcileAt
// GetLastHandledReconcileRequest returns the most recent reconcile request value from the ReconcileRequestStatus.
func (in ReconcileRequestStatus) GetLastHandledReconcileRequest() string {
return in.LastHandledReconcileAt
}

func (rs *ReconcileRequestStatus) SetLastHandledReconcileRequest(token string) {
rs.LastHandledReconcileAt = token
// SetLastHandledReconcileRequest sets the most recent reconcile request value in the ReconcileRequestStatus.
func (in *ReconcileRequestStatus) SetLastHandledReconcileRequest(token string) {
in.LastHandledReconcileAt = token
}

// StatusWithHandledReconcileRequest describes a status type which holds the value of the most recent
// ReconcileAnnotationValue.
// +k8s:deepcopy-gen=false
type StatusWithHandledReconcileRequest interface {
GetLastHandledReconcileRequest() string
}

// StatusWithHandledReconcileRequestSetter describes a status with a setter for the most ReconcileAnnotationValue.
// +k8s:deepcopy-gen=false
type StatusWithHandledReconcileRequestSetter interface {
SetLastHandledReconcileRequest(token string)
}
113 changes: 75 additions & 38 deletions apis/meta/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,62 +17,99 @@ limitations under the License.
package meta

import (
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// These constants define generic Condition types to be used by GitOps Toolkit components.
//
// The ReadyCondition SHOULD be implemented by all components' Kubernetes resources to indicate they have been fully
// reconciled by their respective reconciler. This MAY suffice for simple resources, e.g. a resource that just declares
// state once and is not expected to receive any updates afterwards.
//
// For Kubernetes resources that are expected to receive spec updates over time, take a longer time to reconcile, or
// deal with more complex logic in which for example a finite error state can be observed, it is RECOMMENDED to
// implement the StalledCondition and ReconcilingCondition.
//
// By doing this, observers making use of kstatus to determine the current state of the resource will have a better
// experience while they are e.g. waiting for a change to be reconciled, and will be able to stop waiting for a change
// if a StalledCondition is observed, without having to rely on a timeout.
//
// For more information on kstatus, see:
// https://github.com/kubernetes-sigs/cli-utils/blob/v0.25.0/pkg/kstatus/README.md
const (
// ReadyCondition is the name of the Ready condition implemented by all toolkit
// resources.
// ReadyCondition indicates the resource is ready and fully reconciled.
// If the Condition is False, the resource SHOULD be considered to be in the process of reconciling and not a
// representation of actual state.
ReadyCondition string = "Ready"

// StalledCondition is the name of the Stalled kstatus condition
// StalledCondition indicates the reconciliation of the resource has stalled, e.g. because the controller has
// encountered an error during the reconcile process or it has made insufficient progress (timeout).
// The Condition adheres to an "abnormal-true" polarity pattern, and MUST only be present on the resource if the
// Condition is True.
// For more information about polarity patterns, see:
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
StalledCondition string = "Stalled"

// ReconcilingCondition is the name of the Reconciling kstatus condition
// ReconcilingCondition indicates the controller is currently working on reconciling the latest changes. This MAY be
// True for multiple reconciliation attempts, e.g. when an transient error occurred.
// The Condition adheres to an "abnormal-true" polarity pattern, and MUST only be present on the resource if the
// Condition is True.
// For more information about polarity patterns, see:
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
ReconcilingCondition string = "Reconciling"
)

// These constants define generic Condition reasons to be used by GitOps Toolkit components.
//
// Making use of a generic Reason is RECOMMENDED whenever it can be applied to a Condition in which it provides
// sufficient context together with the type to summarize the meaning of the Condition cause.
//
// Where any of the generic Condition reasons does not suffice, GitOps Toolkit components can introduce new reasons to
// their API specification, or use an arbitrary PascalCase string when setting the Condition.
// Declaration of domain common Condition reasons in the API specification is RECOMMENDED, as it eases observations
// for user and computer.
//
// For more information on Condition reason conventions, see:
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
const (
// ReconciliationSucceededReason represents the fact that the reconciliation of
// a toolkit resource has succeeded.
ReconciliationSucceededReason string = "ReconciliationSucceeded"

// ReconciliationFailedReason represents the fact that the reconciliation of a
// toolkit resource has failed.
ReconciliationFailedReason string = "ReconciliationFailed"

// ProgressingReason represents the fact that the reconciliation of a toolkit
// resource is underway.
// SucceededReason indicates a condition or event observed a success, for example when declared desired state
// matches actual state, or a performed action succeeded.
//
// More information about the reason of success MAY be available as additional metadata in an attached message.
SucceededReason string = "Succeeded"

// FailedReason indicates a condition or event observed a failure, for example when declared state does not match
// actual state, or a performed action failed.
//
// More information about the reason of failure MAY be available as additional metadata in an attached message.
FailedReason string = "Failed"

// ProgressingReason indicates a condition or event observed progression, for example when the reconciliation of a
// resource or an action has started.
//
// When this reason is given, other conditions and types MAY no longer be considered as an up-to-date observation.
// Producers of the specific condition type or event SHOULD provide more information about the expectations and
// precise meaning in their API specification.
//
// More information about the reason or the current state of the progression MAY be available as additional metadata
// in an attached message.
ProgressingReason string = "Progressing"

// DependencyNotReadyReason represents the fact that one of the toolkit resource
// dependencies is not ready.
DependencyNotReadyReason string = "DependencyNotReady"

// SuspendedReason represents the fact that the reconciliation of a toolkit
// resource is suspended.
// SuspendedReason indicates a condition or event has observed a suspension, for
// example because a resource has been suspended, or a dependency is.
SuspendedReason string = "Suspended"
)

// ObjectWithStatusConditions is an interface that describes kubernetes resource
// type structs with Status Conditions
// ObjectWithConditions describes a Kubernetes resource object with status conditions.
// +k8s:deepcopy-gen=false
type ObjectWithStatusConditions interface {
GetStatusConditions() *[]metav1.Condition
type ObjectWithConditions interface {
// GetConditions returns a slice of metav1.Condition
GetConditions() []metav1.Condition
}

// SetResourceCondition sets the given condition with the given status,
// reason and message on a resource.
func SetResourceCondition(obj ObjectWithStatusConditions, condition string, status metav1.ConditionStatus, reason, message string) {
conditions := obj.GetStatusConditions()

newCondition := metav1.Condition{
Type: condition,
Status: status,
Reason: reason,
Message: message,
}

apimeta.SetStatusCondition(conditions, newCondition)
// ObjectWithConditionsSetter describes a Kubernetes resource object with a status conditions setter.
// +k8s:deepcopy-gen=false
type ObjectWithConditionsSetter interface {
// SetConditions sets the status conditions on the object
SetConditions([]metav1.Condition)
}
24 changes: 24 additions & 0 deletions apis/meta/dependencies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright 2021 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 meta

// ObjectWithDependencies describes a Kubernetes resource object with dependencies.
// +k8s:deepcopy-gen=false
type ObjectWithDependencies interface {
// GetDependsOn returns a NamespacedObjectReference list the object depends on.
GetDependsOn() []NamespacedObjectReference
}
7 changes: 5 additions & 2 deletions apis/meta/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// Package meta contains the generic metadata APIs for use by
// toolkit components.
// Package meta contains the generic metadata APIs for use by GitOps Toolkit components.
//
// It is intended only to help adhere to Kubernetes API conventions, utility integrations, and Flux project considered
// best practices. It may therefore be suitable for usage by Kubernetes resources with no relationship to the GitOps
// Toolkit.
// +kubebuilder:object:generate=true
package meta
Loading

0 comments on commit 11abd07

Please sign in to comment.