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 apimeta "k8s.io/apimachinery/pkg/api/meta" 21 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 23 "github.com/fluxcd/pkg/apis/acl" 24 "github.com/fluxcd/pkg/apis/meta" 25 ) 26 27 // HelmChartKind is the string representation of a HelmChart. 28 const HelmChartKind = "HelmChart" 29 30 // HelmChartSpec defines the desired state of a Helm chart. 31 type HelmChartSpec struct { 32 // The name or path the Helm chart is available at in the SourceRef. 33 // +required 34 Chart string `json:"chart"` 35 36 // The chart version semver expression, ignored for charts from GitRepository 37 // and Bucket sources. Defaults to latest when omitted. 38 // +kubebuilder:default:=* 39 // +optional 40 Version string `json:"version,omitempty"` 41 42 // The reference to the Source the chart is available at. 43 // +required 44 SourceRef LocalHelmChartSourceReference `json:"sourceRef"` 45 46 // The interval at which to check the Source for updates. 47 // +required 48 Interval metav1.Duration `json:"interval"` 49 50 // Determines what enables the creation of a new artifact. Valid values are 51 // ('ChartVersion', 'Revision'). 52 // See the documentation of the values for an explanation on their behavior. 53 // Defaults to ChartVersion when omitted. 54 // +kubebuilder:validation:Enum=ChartVersion;Revision 55 // +kubebuilder:default:=ChartVersion 56 // +optional 57 ReconcileStrategy string `json:"reconcileStrategy,omitempty"` 58 59 // Alternative list of values files to use as the chart values (values.yaml 60 // is not included by default), expected to be a relative path in the SourceRef. 61 // Values files are merged in the order of this list with the last file overriding 62 // the first. Ignored when omitted. 63 // +optional 64 ValuesFiles []string `json:"valuesFiles,omitempty"` 65 66 // Alternative values file to use as the default chart values, expected to 67 // be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, 68 // for backwards compatibility the file defined here is merged before the 69 // ValuesFiles items. Ignored when omitted. 70 // +optional 71 // +deprecated 72 ValuesFile string `json:"valuesFile,omitempty"` 73 74 // This flag tells the controller to suspend the reconciliation of this source. 75 // +optional 76 Suspend bool `json:"suspend,omitempty"` 77 78 // AccessFrom defines an Access Control List for allowing cross-namespace references to this object. 79 // +optional 80 AccessFrom *acl.AccessFrom `json:"accessFrom,omitempty"` 81 } 82 83 const ( 84 // ReconcileStrategyChartVersion reconciles when the version of the Helm chart is different. 85 ReconcileStrategyChartVersion string = "ChartVersion" 86 87 // ReconcileStrategyRevision reconciles when the Revision of the source is different. 88 ReconcileStrategyRevision string = "Revision" 89 ) 90 91 // LocalHelmChartSourceReference contains enough information to let you locate 92 // the typed referenced object at namespace level. 93 type LocalHelmChartSourceReference struct { 94 // APIVersion of the referent. 95 // +optional 96 APIVersion string `json:"apiVersion,omitempty"` 97 98 // Kind of the referent, valid values are ('HelmRepository', 'GitRepository', 99 // 'Bucket'). 100 // +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket 101 // +required 102 Kind string `json:"kind"` 103 104 // Name of the referent. 105 // +required 106 Name string `json:"name"` 107 } 108 109 // HelmChartStatus defines the observed state of the HelmChart. 110 type HelmChartStatus struct { 111 // ObservedGeneration is the last observed generation. 112 // +optional 113 ObservedGeneration int64 `json:"observedGeneration,omitempty"` 114 115 // Conditions holds the conditions for the HelmChart. 116 // +optional 117 Conditions []metav1.Condition `json:"conditions,omitempty"` 118 119 // URL is the download link for the last chart pulled. 120 // +optional 121 URL string `json:"url,omitempty"` 122 123 // Artifact represents the output of the last successful chart sync. 124 // +optional 125 Artifact *Artifact `json:"artifact,omitempty"` 126 127 meta.ReconcileRequestStatus `json:",inline"` 128 } 129 130 const ( 131 // ChartPullFailedReason represents the fact that the pull of the Helm chart 132 // failed. 133 ChartPullFailedReason string = "ChartPullFailed" 134 135 // ChartPullSucceededReason represents the fact that the pull of the Helm chart 136 // succeeded. 137 ChartPullSucceededReason string = "ChartPullSucceeded" 138 139 // ChartPackageFailedReason represent the fact that the package of the Helm 140 // chart failed. 141 ChartPackageFailedReason string = "ChartPackageFailed" 142 143 // ChartPackageSucceededReason represents the fact that the package of the Helm 144 // chart succeeded. 145 ChartPackageSucceededReason string = "ChartPackageSucceeded" 146 ) 147 148 // HelmChartProgressing resets the conditions of the HelmChart to meta.Condition 149 // of type meta.ReadyCondition with status 'Unknown' and meta.ProgressingReason 150 // reason and message. It returns the modified HelmChart. 151 func HelmChartProgressing(chart HelmChart) HelmChart { 152 chart.Status.ObservedGeneration = chart.Generation 153 chart.Status.URL = "" 154 chart.Status.Conditions = []metav1.Condition{} 155 newCondition := metav1.Condition{ 156 Type: meta.ReadyCondition, 157 Status: metav1.ConditionUnknown, 158 Reason: meta.ProgressingReason, 159 Message: "reconciliation in progress", 160 } 161 apimeta.SetStatusCondition(chart.GetStatusConditions(), newCondition) 162 return chart 163 } 164 165 // HelmChartReady sets the given Artifact and URL on the HelmChart and sets the 166 // meta.ReadyCondition to 'True', with the given reason and message. It returns 167 // the modified HelmChart. 168 func HelmChartReady(chart HelmChart, artifact Artifact, url, reason, message string) HelmChart { 169 chart.Status.Artifact = &artifact 170 chart.Status.URL = url 171 newCondition := metav1.Condition{ 172 Type: meta.ReadyCondition, 173 Status: metav1.ConditionTrue, 174 Reason: reason, 175 Message: message, 176 } 177 apimeta.SetStatusCondition(chart.GetStatusConditions(), newCondition) 178 return chart 179 } 180 181 // HelmChartNotReady sets the meta.ReadyCondition on the given HelmChart to 182 // 'False', with the given reason and message. It returns the modified 183 // HelmChart. 184 func HelmChartNotReady(chart HelmChart, reason, message string) HelmChart { 185 newCondition := metav1.Condition{ 186 Type: meta.ReadyCondition, 187 Status: metav1.ConditionFalse, 188 Reason: reason, 189 Message: message, 190 } 191 apimeta.SetStatusCondition(chart.GetStatusConditions(), newCondition) 192 return chart 193 } 194 195 // HelmChartReadyMessage returns the message of the meta.ReadyCondition with 196 // status 'True', or an empty string. 197 func HelmChartReadyMessage(chart HelmChart) string { 198 if c := apimeta.FindStatusCondition(chart.Status.Conditions, meta.ReadyCondition); c != nil { 199 if c.Status == metav1.ConditionTrue { 200 return c.Message 201 } 202 } 203 return "" 204 } 205 206 // GetArtifact returns the latest artifact from the source if present in the 207 // status sub-resource. 208 func (in *HelmChart) GetArtifact() *Artifact { 209 return in.Status.Artifact 210 } 211 212 // GetStatusConditions returns a pointer to the Status.Conditions slice 213 func (in *HelmChart) GetStatusConditions() *[]metav1.Condition { 214 return &in.Status.Conditions 215 } 216 217 // GetInterval returns the interval at which the source is updated. 218 func (in *HelmChart) GetInterval() metav1.Duration { 219 return in.Spec.Interval 220 } 221 222 // GetValuesFiles returns a merged list of ValuesFiles. 223 func (in *HelmChart) GetValuesFiles() []string { 224 valuesFiles := in.Spec.ValuesFiles 225 226 // Prepend the deprecated ValuesFile to the list 227 if in.Spec.ValuesFile != "" { 228 valuesFiles = append([]string{in.Spec.ValuesFile}, valuesFiles...) 229 } 230 return valuesFiles 231 } 232 233 // +genclient 234 // +kubebuilder:object:root=true 235 // +kubebuilder:resource:shortName=hc 236 // +kubebuilder:subresource:status 237 // +kubebuilder:deprecatedversion:warning="v1beta1 HelmChart is deprecated, upgrade to v1" 238 // +kubebuilder:printcolumn:name="Chart",type=string,JSONPath=`.spec.chart` 239 // +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.version` 240 // +kubebuilder:printcolumn:name="Source Kind",type=string,JSONPath=`.spec.sourceRef.kind` 241 // +kubebuilder:printcolumn:name="Source Name",type=string,JSONPath=`.spec.sourceRef.name` 242 // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" 243 // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" 244 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" 245 246 // HelmChart is the Schema for the helmcharts API 247 type HelmChart struct { 248 metav1.TypeMeta `json:",inline"` 249 metav1.ObjectMeta `json:"metadata,omitempty"` 250 251 Spec HelmChartSpec `json:"spec,omitempty"` 252 // +kubebuilder:default={"observedGeneration":-1} 253 Status HelmChartStatus `json:"status,omitempty"` 254 } 255 256 // +kubebuilder:object:root=true 257 258 // HelmChartList contains a list of HelmChart 259 type HelmChartList struct { 260 metav1.TypeMeta `json:",inline"` 261 metav1.ListMeta `json:"metadata,omitempty"` 262 Items []HelmChart `json:"items"` 263 } 264 265 func init() { 266 SchemeBuilder.Register(&HelmChart{}, &HelmChartList{}) 267 } 268