1 /* 2 Copyright 2020 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 v1beta1 18 19 import ( 20 "time" 21 22 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/types" 25 26 "github.com/fluxcd/pkg/apis/kustomize" 27 "github.com/fluxcd/pkg/apis/meta" 28 ) 29 30 const ( 31 KustomizationKind = "Kustomization" 32 KustomizationFinalizer = "finalizers.fluxcd.io" 33 MaxConditionMessageLength = 20000 34 DisabledValue = "disabled" 35 ) 36 37 // KustomizationSpec defines the desired state of a kustomization. 38 type KustomizationSpec struct { 39 // DependsOn may contain a meta.NamespacedObjectReference slice 40 // with references to Kustomization resources that must be ready before this 41 // Kustomization can be reconciled. 42 // +optional 43 DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"` 44 45 // Decrypt Kubernetes secrets before applying them on the cluster. 46 // +optional 47 Decryption *Decryption `json:"decryption,omitempty"` 48 49 // The interval at which to reconcile the Kustomization. 50 // +required 51 Interval metav1.Duration `json:"interval"` 52 53 // The interval at which to retry a previously failed reconciliation. 54 // When not specified, the controller uses the KustomizationSpec.Interval 55 // value to retry failures. 56 // +optional 57 RetryInterval *metav1.Duration `json:"retryInterval,omitempty"` 58 59 // The KubeConfig for reconciling the Kustomization on a remote cluster. 60 // When specified, KubeConfig takes precedence over ServiceAccountName. 61 // +optional 62 KubeConfig *KubeConfig `json:"kubeConfig,omitempty"` 63 64 // Path to the directory containing the kustomization.yaml file, or the 65 // set of plain YAMLs a kustomization.yaml should be generated for. 66 // Defaults to 'None', which translates to the root path of the SourceRef. 67 // +optional 68 Path string `json:"path,omitempty"` 69 70 // PostBuild describes which actions to perform on the YAML manifest 71 // generated by building the kustomize overlay. 72 // +optional 73 PostBuild *PostBuild `json:"postBuild,omitempty"` 74 75 // Prune enables garbage collection. 76 // +required 77 Prune bool `json:"prune"` 78 79 // A list of resources to be included in the health assessment. 80 // +optional 81 HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,omitempty"` 82 83 // Strategic merge and JSON patches, defined as inline YAML objects, 84 // capable of targeting objects based on kind, label and annotation selectors. 85 // +optional 86 Patches []kustomize.Patch `json:"patches,omitempty"` 87 88 // Strategic merge patches, defined as inline YAML objects. 89 // +optional 90 PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"` 91 92 // JSON 6902 patches, defined as inline YAML objects. 93 // +optional 94 PatchesJSON6902 []kustomize.JSON6902Patch `json:"patchesJson6902,omitempty"` 95 96 // Images is a list of (image name, new name, new tag or digest) 97 // for changing image names, tags or digests. This can also be achieved with a 98 // patch, but this operator is simpler to specify. 99 // +optional 100 Images []kustomize.Image `json:"images,omitempty"` 101 102 // The name of the Kubernetes service account to impersonate 103 // when reconciling this Kustomization. 104 // +optional 105 ServiceAccountName string `json:"serviceAccountName,omitempty"` 106 107 // Reference of the source where the kustomization file is. 108 // +required 109 SourceRef CrossNamespaceSourceReference `json:"sourceRef"` 110 111 // This flag tells the controller to suspend subsequent kustomize executions, 112 // it does not apply to already started executions. Defaults to false. 113 // +optional 114 Suspend bool `json:"suspend,omitempty"` 115 116 // TargetNamespace sets or overrides the namespace in the 117 // kustomization.yaml file. 118 // +kubebuilder:validation:MinLength=1 119 // +kubebuilder:validation:MaxLength=63 120 // +kubebuilder:validation:Optional 121 // +optional 122 TargetNamespace string `json:"targetNamespace,omitempty"` 123 124 // Timeout for validation, apply and health checking operations. 125 // Defaults to 'Interval' duration. 126 // +optional 127 Timeout *metav1.Duration `json:"timeout,omitempty"` 128 129 // Validate the Kubernetes objects before applying them on the cluster. 130 // The validation strategy can be 'client' (local dry-run), 'server' 131 // (APIServer dry-run) or 'none'. 132 // When 'Force' is 'true', validation will fallback to 'client' if set to 133 // 'server' because server-side validation is not supported in this scenario. 134 // +kubebuilder:validation:Enum=none;client;server 135 // +optional 136 Validation string `json:"validation,omitempty"` 137 138 // Force instructs the controller to recreate resources 139 // when patching fails due to an immutable field change. 140 // +kubebuilder:default:=false 141 // +optional 142 Force bool `json:"force,omitempty"` 143 } 144 145 // Decryption defines how decryption is handled for Kubernetes manifests. 146 type Decryption struct { 147 // Provider is the name of the decryption engine. 148 // +kubebuilder:validation:Enum=sops 149 // +required 150 Provider string `json:"provider"` 151 152 // The secret name containing the private OpenPGP keys used for decryption. 153 // +optional 154 SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` 155 } 156 157 // KubeConfig references a Kubernetes secret that contains a kubeconfig file. 158 type KubeConfig struct { 159 // SecretRef holds the name to a secret that contains a 'value' key with 160 // the kubeconfig file as the value. It must be in the same namespace as 161 // the Kustomization. 162 // It is recommended that the kubeconfig is self-contained, and the secret 163 // is regularly updated if credentials such as a cloud-access-token expire. 164 // Cloud specific `cmd-path` auth helpers will not function without adding 165 // binaries and credentials to the Pod that is responsible for reconciling 166 // the Kustomization. 167 // +required 168 SecretRef meta.LocalObjectReference `json:"secretRef,omitempty"` 169 } 170 171 // PostBuild describes which actions to perform on the YAML manifest 172 // generated by building the kustomize overlay. 173 type PostBuild struct { 174 // Substitute holds a map of key/value pairs. 175 // The variables defined in your YAML manifests 176 // that match any of the keys defined in the map 177 // will be substituted with the set value. 178 // Includes support for bash string replacement functions 179 // e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. 180 // +optional 181 Substitute map[string]string `json:"substitute,omitempty"` 182 183 // SubstituteFrom holds references to ConfigMaps and Secrets containing 184 // the variables and their values to be substituted in the YAML manifests. 185 // The ConfigMap and the Secret data keys represent the var names and they 186 // must match the vars declared in the manifests for the substitution to happen. 187 // +optional 188 SubstituteFrom []SubstituteReference `json:"substituteFrom,omitempty"` 189 } 190 191 // SubstituteReference contains a reference to a resource containing 192 // the variables name and value. 193 type SubstituteReference struct { 194 // Kind of the values referent, valid values are ('Secret', 'ConfigMap'). 195 // +kubebuilder:validation:Enum=Secret;ConfigMap 196 // +required 197 Kind string `json:"kind"` 198 199 // Name of the values referent. Should reside in the same namespace as the 200 // referring resource. 201 // +kubebuilder:validation:MinLength=1 202 // +kubebuilder:validation:MaxLength=253 203 // +required 204 Name string `json:"name"` 205 } 206 207 // KustomizationStatus defines the observed state of a kustomization. 208 type KustomizationStatus struct { 209 // ObservedGeneration is the last reconciled generation. 210 // +optional 211 ObservedGeneration int64 `json:"observedGeneration,omitempty"` 212 213 // +optional 214 Conditions []metav1.Condition `json:"conditions,omitempty"` 215 216 // The last successfully applied revision. 217 // The revision format for Git sources is <branch|tag>/<commit-sha>. 218 // +optional 219 LastAppliedRevision string `json:"lastAppliedRevision,omitempty"` 220 221 // LastAttemptedRevision is the revision of the last reconciliation attempt. 222 // +optional 223 LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"` 224 225 meta.ReconcileRequestStatus `json:",inline"` 226 227 // The last successfully applied revision metadata. 228 // +optional 229 Snapshot *Snapshot `json:"snapshot,omitempty"` 230 } 231 232 // GetTimeout returns the timeout with default. 233 func (in Kustomization) GetTimeout() time.Duration { 234 duration := in.Spec.Interval.Duration 235 if in.Spec.Timeout != nil { 236 duration = in.Spec.Timeout.Duration 237 } 238 if duration < time.Minute { 239 return time.Minute 240 } 241 return duration 242 } 243 244 // GetRetryInterval returns the retry interval 245 func (in Kustomization) GetRetryInterval() time.Duration { 246 if in.Spec.RetryInterval != nil { 247 return in.Spec.RetryInterval.Duration 248 } 249 return in.Spec.Interval.Duration 250 } 251 252 func (in Kustomization) GetDependsOn() (types.NamespacedName, []meta.NamespacedObjectReference) { 253 return types.NamespacedName{ 254 Namespace: in.Namespace, 255 Name: in.Name, 256 }, in.Spec.DependsOn 257 } 258 259 // GetStatusConditions returns a pointer to the Status.Conditions slice 260 func (in *Kustomization) GetStatusConditions() *[]metav1.Condition { 261 return &in.Status.Conditions 262 } 263 264 const ( 265 // GitRepositoryIndexKey is the key used for indexing kustomizations 266 // based on their Git sources. 267 GitRepositoryIndexKey string = ".metadata.gitRepository" 268 // BucketIndexKey is the key used for indexing kustomizations 269 // based on their S3 sources. 270 BucketIndexKey string = ".metadata.bucket" 271 ) 272 273 // +genclient 274 // +kubebuilder:object:root=true 275 // +kubebuilder:resource:shortName=ks 276 // +kubebuilder:subresource:status 277 // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" 278 // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" 279 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" 280 // +kubebuilder:deprecatedversion:warning="v1beta1 Kustomization is deprecated, upgrade to v1" 281 282 // Kustomization is the Schema for the kustomizations API. 283 type Kustomization struct { 284 metav1.TypeMeta `json:",inline"` 285 metav1.ObjectMeta `json:"metadata,omitempty"` 286 287 Spec KustomizationSpec `json:"spec,omitempty"` 288 // +kubebuilder:default:={"observedGeneration":-1} 289 Status KustomizationStatus `json:"status,omitempty"` 290 } 291 292 // +kubebuilder:object:root=true 293 294 // KustomizationList contains a list of kustomizations. 295 type KustomizationList struct { 296 metav1.TypeMeta `json:",inline"` 297 metav1.ListMeta `json:"metadata,omitempty"` 298 Items []Kustomization `json:"items"` 299 } 300 301 func init() { 302 SchemeBuilder.Register(&Kustomization{}, &KustomizationList{}) 303 } 304 305 func trimString(str string, limit int) string { 306 if len(str) <= limit { 307 return str 308 } 309 310 return str[0:limit] + "..." 311 } 312