1 /* 2 Copyright 2023 The Flux authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1 18 19 import ( 20 "time" 21 22 "github.com/fluxcd/pkg/apis/kustomize" 23 "github.com/fluxcd/pkg/apis/meta" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ) 26 27 const ( 28 KustomizationKind = "Kustomization" 29 KustomizationFinalizer = "finalizers.fluxcd.io" 30 MaxConditionMessageLength = 20000 31 EnabledValue = "enabled" 32 DisabledValue = "disabled" 33 MergeValue = "Merge" 34 IfNotPresentValue = "IfNotPresent" 35 IgnoreValue = "Ignore" 36 ) 37 38 // KustomizationSpec defines the configuration to calculate the desired state 39 // from a Source using Kustomize. 40 type KustomizationSpec struct { 41 // CommonMetadata specifies the common labels and annotations that are 42 // applied to all resources. Any existing label or annotation will be 43 // overridden if its key matches a common one. 44 // +optional 45 CommonMetadata *CommonMetadata `json:"commonMetadata,omitempty"` 46 47 // DependsOn may contain a meta.NamespacedObjectReference slice 48 // with references to Kustomization resources that must be ready before this 49 // Kustomization can be reconciled. 50 // +optional 51 DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"` 52 53 // Decrypt Kubernetes secrets before applying them on the cluster. 54 // +optional 55 Decryption *Decryption `json:"decryption,omitempty"` 56 57 // The interval at which to reconcile the Kustomization. 58 // This interval is approximate and may be subject to jitter to ensure 59 // efficient use of resources. 60 // +kubebuilder:validation:Type=string 61 // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" 62 // +required 63 Interval metav1.Duration `json:"interval"` 64 65 // The interval at which to retry a previously failed reconciliation. 66 // When not specified, the controller uses the KustomizationSpec.Interval 67 // value to retry failures. 68 // +kubebuilder:validation:Type=string 69 // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" 70 // +optional 71 RetryInterval *metav1.Duration `json:"retryInterval,omitempty"` 72 73 // The KubeConfig for reconciling the Kustomization on a remote cluster. 74 // When used in combination with KustomizationSpec.ServiceAccountName, 75 // forces the controller to act on behalf of that Service Account at the 76 // target cluster. 77 // If the --default-service-account flag is set, its value will be used as 78 // a controller level fallback for when KustomizationSpec.ServiceAccountName 79 // is empty. 80 // +optional 81 KubeConfig *meta.KubeConfigReference `json:"kubeConfig,omitempty"` 82 83 // Path to the directory containing the kustomization.yaml file, or the 84 // set of plain YAMLs a kustomization.yaml should be generated for. 85 // Defaults to 'None', which translates to the root path of the SourceRef. 86 // +optional 87 Path string `json:"path,omitempty"` 88 89 // PostBuild describes which actions to perform on the YAML manifest 90 // generated by building the kustomize overlay. 91 // +optional 92 PostBuild *PostBuild `json:"postBuild,omitempty"` 93 94 // Prune enables garbage collection. 95 // +required 96 Prune bool `json:"prune"` 97 98 // A list of resources to be included in the health assessment. 99 // +optional 100 HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,omitempty"` 101 102 // NamePrefix will prefix the names of all managed resources. 103 // +kubebuilder:validation:MinLength=1 104 // +kubebuilder:validation:MaxLength=200 105 // +kubebuilder:validation:Optional 106 // +optional 107 NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"` 108 109 // NameSuffix will suffix the names of all managed resources. 110 // +kubebuilder:validation:MinLength=1 111 // +kubebuilder:validation:MaxLength=200 112 // +kubebuilder:validation:Optional 113 // +optional 114 NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"` 115 116 // Strategic merge and JSON patches, defined as inline YAML objects, 117 // capable of targeting objects based on kind, label and annotation selectors. 118 // +optional 119 Patches []kustomize.Patch `json:"patches,omitempty"` 120 121 // Images is a list of (image name, new name, new tag or digest) 122 // for changing image names, tags or digests. This can also be achieved with a 123 // patch, but this operator is simpler to specify. 124 // +optional 125 Images []kustomize.Image `json:"images,omitempty"` 126 127 // The name of the Kubernetes service account to impersonate 128 // when reconciling this Kustomization. 129 // +optional 130 ServiceAccountName string `json:"serviceAccountName,omitempty"` 131 132 // Reference of the source where the kustomization file is. 133 // +required 134 SourceRef CrossNamespaceSourceReference `json:"sourceRef"` 135 136 // This flag tells the controller to suspend subsequent kustomize executions, 137 // it does not apply to already started executions. Defaults to false. 138 // +optional 139 Suspend bool `json:"suspend,omitempty"` 140 141 // TargetNamespace sets or overrides the namespace in the 142 // kustomization.yaml file. 143 // +kubebuilder:validation:MinLength=1 144 // +kubebuilder:validation:MaxLength=63 145 // +kubebuilder:validation:Optional 146 // +optional 147 TargetNamespace string `json:"targetNamespace,omitempty"` 148 149 // Timeout for validation, apply and health checking operations. 150 // Defaults to 'Interval' duration. 151 // +kubebuilder:validation:Type=string 152 // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" 153 // +optional 154 Timeout *metav1.Duration `json:"timeout,omitempty"` 155 156 // Force instructs the controller to recreate resources 157 // when patching fails due to an immutable field change. 158 // +kubebuilder:default:=false 159 // +optional 160 Force bool `json:"force,omitempty"` 161 162 // Wait instructs the controller to check the health of all the reconciled 163 // resources. When enabled, the HealthChecks are ignored. Defaults to false. 164 // +optional 165 Wait bool `json:"wait,omitempty"` 166 167 // Components specifies relative paths to specifications of other Components. 168 // +optional 169 Components []string `json:"components,omitempty"` 170 } 171 172 // CommonMetadata defines the common labels and annotations. 173 type CommonMetadata struct { 174 // Annotations to be added to the object's metadata. 175 // +optional 176 Annotations map[string]string `json:"annotations,omitempty"` 177 178 // Labels to be added to the object's metadata. 179 // +optional 180 Labels map[string]string `json:"labels,omitempty"` 181 } 182 183 // Decryption defines how decryption is handled for Kubernetes manifests. 184 type Decryption struct { 185 // Provider is the name of the decryption engine. 186 // +kubebuilder:validation:Enum=sops 187 // +required 188 Provider string `json:"provider"` 189 190 // The secret name containing the private OpenPGP keys used for decryption. 191 // +optional 192 SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` 193 } 194 195 // PostBuild describes which actions to perform on the YAML manifest 196 // generated by building the kustomize overlay. 197 type PostBuild struct { 198 // Substitute holds a map of key/value pairs. 199 // The variables defined in your YAML manifests that match any of the keys 200 // defined in the map will be substituted with the set value. 201 // Includes support for bash string replacement functions 202 // e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. 203 // +optional 204 Substitute map[string]string `json:"substitute,omitempty"` 205 206 // SubstituteFrom holds references to ConfigMaps and Secrets containing 207 // the variables and their values to be substituted in the YAML manifests. 208 // The ConfigMap and the Secret data keys represent the var names, and they 209 // must match the vars declared in the manifests for the substitution to 210 // happen. 211 // +optional 212 SubstituteFrom []SubstituteReference `json:"substituteFrom,omitempty"` 213 } 214 215 // SubstituteReference contains a reference to a resource containing 216 // the variables name and value. 217 type SubstituteReference struct { 218 // Kind of the values referent, valid values are ('Secret', 'ConfigMap'). 219 // +kubebuilder:validation:Enum=Secret;ConfigMap 220 // +required 221 Kind string `json:"kind"` 222 223 // Name of the values referent. Should reside in the same namespace as the 224 // referring resource. 225 // +kubebuilder:validation:MinLength=1 226 // +kubebuilder:validation:MaxLength=253 227 // +required 228 Name string `json:"name"` 229 230 // Optional indicates whether the referenced resource must exist, or whether to 231 // tolerate its absence. If true and the referenced resource is absent, proceed 232 // as if the resource was present but empty, without any variables defined. 233 // +kubebuilder:default:=false 234 // +optional 235 Optional bool `json:"optional,omitempty"` 236 } 237 238 // KustomizationStatus defines the observed state of a kustomization. 239 type KustomizationStatus struct { 240 meta.ReconcileRequestStatus `json:",inline"` 241 242 // ObservedGeneration is the last reconciled generation. 243 // +optional 244 ObservedGeneration int64 `json:"observedGeneration,omitempty"` 245 246 // +optional 247 Conditions []metav1.Condition `json:"conditions,omitempty"` 248 249 // The last successfully applied revision. 250 // Equals the Revision of the applied Artifact from the referenced Source. 251 // +optional 252 LastAppliedRevision string `json:"lastAppliedRevision,omitempty"` 253 254 // LastAttemptedRevision is the revision of the last reconciliation attempt. 255 // +optional 256 LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"` 257 258 // Inventory contains the list of Kubernetes resource object references that 259 // have been successfully applied. 260 // +optional 261 Inventory *ResourceInventory `json:"inventory,omitempty"` 262 } 263 264 // GetTimeout returns the timeout with default. 265 func (in Kustomization) GetTimeout() time.Duration { 266 duration := in.Spec.Interval.Duration - 30*time.Second 267 if in.Spec.Timeout != nil { 268 duration = in.Spec.Timeout.Duration 269 } 270 if duration < 30*time.Second { 271 return 30 * time.Second 272 } 273 return duration 274 } 275 276 // GetRetryInterval returns the retry interval 277 func (in Kustomization) GetRetryInterval() time.Duration { 278 if in.Spec.RetryInterval != nil { 279 return in.Spec.RetryInterval.Duration 280 } 281 return in.GetRequeueAfter() 282 } 283 284 // GetRequeueAfter returns the duration after which the Kustomization must be 285 // reconciled again. 286 func (in Kustomization) GetRequeueAfter() time.Duration { 287 return in.Spec.Interval.Duration 288 } 289 290 // GetDependsOn returns the list of dependencies across-namespaces. 291 func (in Kustomization) GetDependsOn() []meta.NamespacedObjectReference { 292 return in.Spec.DependsOn 293 } 294 295 // GetConditions returns the status conditions of the object. 296 func (in Kustomization) GetConditions() []metav1.Condition { 297 return in.Status.Conditions 298 } 299 300 // SetConditions sets the status conditions on the object. 301 func (in *Kustomization) SetConditions(conditions []metav1.Condition) { 302 in.Status.Conditions = conditions 303 } 304 305 // +genclient 306 // +kubebuilder:storageversion 307 // +kubebuilder:object:root=true 308 // +kubebuilder:resource:shortName=ks 309 // +kubebuilder:subresource:status 310 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" 311 // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" 312 // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" 313 314 // Kustomization is the Schema for the kustomizations API. 315 type Kustomization struct { 316 metav1.TypeMeta `json:",inline"` 317 metav1.ObjectMeta `json:"metadata,omitempty"` 318 319 Spec KustomizationSpec `json:"spec,omitempty"` 320 // +kubebuilder:default:={"observedGeneration":-1} 321 Status KustomizationStatus `json:"status,omitempty"` 322 } 323 324 // +kubebuilder:object:root=true 325 326 // KustomizationList contains a list of kustomizations. 327 type KustomizationList struct { 328 metav1.TypeMeta `json:",inline"` 329 metav1.ListMeta `json:"metadata,omitempty"` 330 Items []Kustomization `json:"items"` 331 } 332 333 func init() { 334 SchemeBuilder.Register(&Kustomization{}, &KustomizationList{}) 335 } 336