Merge pull request #7 from fluxcd/helmchart
Introduce HelmChart API and controller
This commit is contained in:
commit
bb8ec6e328
|
|
@ -43,13 +43,15 @@ jobs:
|
|||
run: |
|
||||
kubectl apply -f ./config/samples
|
||||
kubectl -n source-system rollout status deploy/source-controller --timeout=1m
|
||||
kubectl wait gitrepository/podinfo --for=condition=ready --timeout=1m
|
||||
kubectl wait helmrepository/podinfo --for=condition=ready --timeout=1m
|
||||
kubectl wait gitrepository/gitrepository-sample --for=condition=ready --timeout=1m
|
||||
kubectl wait helmrepository/helmrepository-sample --for=condition=ready --timeout=1m
|
||||
kubectl wait helmchart/helmchart-sample --for=condition=ready --timeout=1m
|
||||
kubectl -n source-system logs deploy/source-controller
|
||||
- name: Debug failure
|
||||
if: failure()
|
||||
run: |
|
||||
kubectl get gitrepositories -oyaml
|
||||
kubectl get helmrepositories -oyaml
|
||||
kubectl get helmcharts -oyaml
|
||||
kubectl -n source-system get all
|
||||
kubectl -n source-system logs deploy/source-controller
|
||||
|
|
|
|||
3
PROJECT
3
PROJECT
|
|
@ -7,4 +7,7 @@ resources:
|
|||
- group: source
|
||||
kind: HelmRepository
|
||||
version: v1alpha1
|
||||
- group: source
|
||||
kind: HelmChart
|
||||
version: v1alpha1
|
||||
version: "2"
|
||||
|
|
|
|||
|
|
@ -76,34 +76,6 @@ type GitRepositoryStatus struct {
|
|||
Artifact *Artifact `json:"artifact,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url`
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// GitRepository is the Schema for the gitrepositories API
|
||||
type GitRepository struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec GitRepositorySpec `json:"spec,omitempty"`
|
||||
Status GitRepositoryStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// GitRepositoryList contains a list of GitRepository
|
||||
// +kubebuilder:object:root=true
|
||||
type GitRepositoryList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []GitRepository `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&GitRepository{}, &GitRepositoryList{})
|
||||
}
|
||||
|
||||
const (
|
||||
GitOperationSucceedReason string = "GitOperationSucceed"
|
||||
GitOperationFailedReason string = "GitOperationFailed"
|
||||
|
|
@ -153,3 +125,31 @@ func GitRepositoryReadyMessage(repository GitRepository) string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url`
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// GitRepository is the Schema for the gitrepositories API
|
||||
type GitRepository struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec GitRepositorySpec `json:"spec,omitempty"`
|
||||
Status GitRepositoryStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// GitRepositoryList contains a list of GitRepository
|
||||
// +kubebuilder:object:root=true
|
||||
type GitRepositoryList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []GitRepository `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&GitRepository{}, &GitRepositoryList{})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// HelmChartSpec defines the desired state of HelmChart
|
||||
type HelmChartSpec struct {
|
||||
// The name of the Helm chart, as made available by the referenced
|
||||
// Helm repository.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// The chart version semver expression, defaults to latest when
|
||||
// omitted.
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
|
||||
// The name of the HelmRepository the chart is available at.
|
||||
// +required
|
||||
HelmRepositoryRef corev1.LocalObjectReference `json:"helmRepositoryRef"`
|
||||
|
||||
// The interval at which to check the Helm repository for updates.
|
||||
// Defaults to the interval of the Helm repository.
|
||||
// +optional
|
||||
Interval *metav1.Duration `json:"interval,omitempty"`
|
||||
}
|
||||
|
||||
// IntervalOrDefault returns the defined interval on the HelmChartSpec
|
||||
// or the given default.
|
||||
func (s HelmChartSpec) IntervalOrDefault(interval metav1.Duration) metav1.Duration {
|
||||
if s.Interval == nil {
|
||||
return interval
|
||||
}
|
||||
return *s.Interval
|
||||
}
|
||||
|
||||
// HelmChartStatus defines the observed state of HelmChart
|
||||
type HelmChartStatus struct {
|
||||
// +optional
|
||||
Conditions []SourceCondition `json:"conditions,omitempty"`
|
||||
|
||||
// URL is the download link for the last chart pulled.
|
||||
// +optional
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// URI for the artifact of the latest successful chart pull.
|
||||
// +optional
|
||||
Artifact *Artifact `json:"artifact,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// ChartPullFailedReason represents the fact that the pull of the
|
||||
// Helm chart failed.
|
||||
ChartPullFailedReason string = "ChartPullFailed"
|
||||
|
||||
// ChartPulLSucceededReason represents the fact that the pull of
|
||||
// the Helm chart succeeded.
|
||||
ChartPullSucceededReason string = "ChartPullSucceeded"
|
||||
)
|
||||
|
||||
func HelmChartReady(chart HelmChart, artifact Artifact, url, reason, message string) HelmChart {
|
||||
chart.Status.Conditions = []SourceCondition{
|
||||
{
|
||||
Type: ReadyCondition,
|
||||
Status: corev1.ConditionTrue,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
},
|
||||
}
|
||||
chart.Status.URL = url
|
||||
|
||||
if chart.Status.Artifact != nil {
|
||||
if chart.Status.Artifact.Path != artifact.Path {
|
||||
chart.Status.Artifact = &artifact
|
||||
}
|
||||
} else {
|
||||
chart.Status.Artifact = &artifact
|
||||
}
|
||||
|
||||
return chart
|
||||
}
|
||||
|
||||
func HelmChartNotReady(chart HelmChart, reason, message string) HelmChart {
|
||||
chart.Status.Conditions = []SourceCondition{
|
||||
{
|
||||
Type: ReadyCondition,
|
||||
Status: corev1.ConditionFalse,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
},
|
||||
}
|
||||
return chart
|
||||
}
|
||||
|
||||
func HelmChartReadyMessage(chart HelmChart) string {
|
||||
for _, condition := range chart.Status.Conditions {
|
||||
if condition.Type == ReadyCondition {
|
||||
return condition.Message
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="Name",type=string,JSONPath=`.spec.name`
|
||||
// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.version`
|
||||
// +kubebuilder:printcolumn:name="Repository",type=string,JSONPath=`.spec.helmRepositoryRef.name`
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// HelmChart is the Schema for the helmcharts API
|
||||
type HelmChart struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec HelmChartSpec `json:"spec,omitempty"`
|
||||
Status HelmChartStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// HelmChartList contains a list of HelmChart
|
||||
type HelmChartList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []HelmChart `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&HelmChart{}, &HelmChartList{})
|
||||
}
|
||||
|
|
@ -47,34 +47,6 @@ type HelmRepositoryStatus struct {
|
|||
Artifact *Artifact `json:"artifact,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url`
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// HelmRepository is the Schema for the helmrepositories API
|
||||
type HelmRepository struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec HelmRepositorySpec `json:"spec,omitempty"`
|
||||
Status HelmRepositoryStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// HelmRepositoryList contains a list of HelmRepository
|
||||
// +kubebuilder:object:root=true
|
||||
type HelmRepositoryList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []HelmRepository `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&HelmRepository{}, &HelmRepositoryList{})
|
||||
}
|
||||
|
||||
const (
|
||||
// IndexationFailedReason represents the fact that the indexation
|
||||
// of the given Helm repository failed.
|
||||
|
|
@ -129,3 +101,31 @@ func HelmRepositoryReadyMessage(repository HelmRepository) string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url`
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// HelmRepository is the Schema for the helmrepositories API
|
||||
type HelmRepository struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec HelmRepositorySpec `json:"spec,omitempty"`
|
||||
Status HelmRepositoryStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// HelmRepositoryList contains a list of HelmRepository
|
||||
// +kubebuilder:object:root=true
|
||||
type HelmRepositoryList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []HelmRepository `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&HelmRepository{}, &HelmRepositoryList{})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package v1alpha1
|
|||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -168,6 +169,113 @@ func (in *GitRepositoryStatus) DeepCopy() *GitRepositoryStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmChart) DeepCopyInto(out *HelmChart) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChart.
|
||||
func (in *HelmChart) DeepCopy() *HelmChart {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HelmChart)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *HelmChart) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmChartList) DeepCopyInto(out *HelmChartList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]HelmChart, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartList.
|
||||
func (in *HelmChartList) DeepCopy() *HelmChartList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HelmChartList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *HelmChartList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmChartSpec) DeepCopyInto(out *HelmChartSpec) {
|
||||
*out = *in
|
||||
out.HelmRepositoryRef = in.HelmRepositoryRef
|
||||
if in.Interval != nil {
|
||||
in, out := &in.Interval, &out.Interval
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartSpec.
|
||||
func (in *HelmChartSpec) DeepCopy() *HelmChartSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HelmChartSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmChartStatus) DeepCopyInto(out *HelmChartStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]SourceCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Artifact != nil {
|
||||
in, out := &in.Artifact, &out.Artifact
|
||||
*out = new(Artifact)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartStatus.
|
||||
func (in *HelmChartStatus) DeepCopy() *HelmChartStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HelmChartStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmRepository) DeepCopyInto(out *HelmRepository) {
|
||||
*out = *in
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
creationTimestamp: null
|
||||
name: helmcharts.source.fluxcd.io
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .spec.name
|
||||
name: Name
|
||||
type: string
|
||||
- JSONPath: .spec.version
|
||||
name: Version
|
||||
type: string
|
||||
- JSONPath: .spec.helmRepositoryRef.name
|
||||
name: Repository
|
||||
type: string
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
- JSONPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
group: source.fluxcd.io
|
||||
names:
|
||||
kind: HelmChart
|
||||
listKind: HelmChartList
|
||||
plural: helmcharts
|
||||
singular: helmchart
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: HelmChart is the Schema for the helmcharts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: HelmChartSpec defines the desired state of HelmChart
|
||||
properties:
|
||||
helmRepositoryRef:
|
||||
description: The name of the HelmRepository the chart is available at.
|
||||
properties:
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
type: object
|
||||
interval:
|
||||
description: The interval at which to check the Helm repository for
|
||||
updates. Defaults to the interval of the Helm repository.
|
||||
type: string
|
||||
name:
|
||||
description: The name of the Helm chart, as made available by the referenced
|
||||
Helm repository.
|
||||
type: string
|
||||
version:
|
||||
description: The chart version semver expression, defaults to latest
|
||||
when omitted.
|
||||
type: string
|
||||
required:
|
||||
- helmRepositoryRef
|
||||
- name
|
||||
type: object
|
||||
status:
|
||||
description: HelmChartStatus defines the observed state of HelmChart
|
||||
properties:
|
||||
artifact:
|
||||
description: URI for the artifact of the latest successful chart pull.
|
||||
properties:
|
||||
lastUpdateTime:
|
||||
description: LastUpdateTime is the timestamp corresponding to the
|
||||
last update of this artifact.
|
||||
format: date-time
|
||||
type: string
|
||||
path:
|
||||
description: Path is the local file path of this artifact.
|
||||
type: string
|
||||
revision:
|
||||
description: Revision is a human readable identifier traceable in
|
||||
the origin source system. It can be a commit sha, git tag, a helm
|
||||
index timestamp, a helm chart version, a checksum, etc.
|
||||
type: string
|
||||
url:
|
||||
description: URL is the HTTP address of this artifact.
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
- url
|
||||
type: object
|
||||
conditions:
|
||||
items:
|
||||
description: SourceCondition contains condition information for a
|
||||
source
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the timestamp corresponding
|
||||
to the last status change of this condition.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: Message is a human readable description of the details
|
||||
of the last transition, complementing reason.
|
||||
type: string
|
||||
reason:
|
||||
description: Reason is a brief machine readable explanation for
|
||||
the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False',
|
||||
'Unknown').
|
||||
type: string
|
||||
type:
|
||||
description: Type of the condition, currently ('Ready').
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
url:
|
||||
description: URL is the download link for the last chart pulled.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
@ -3,5 +3,6 @@ kind: Kustomization
|
|||
resources:
|
||||
- bases/source.fluxcd.io_gitrepositories.yaml
|
||||
- bases/source.fluxcd.io_helmrepositories.yaml
|
||||
- bases/source.fluxcd.io_helmcharts.yaml
|
||||
# +kubebuilder:scaffold:crdkustomizeresource
|
||||
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@ resources:
|
|||
- deployment.yaml
|
||||
images:
|
||||
- name: fluxcd/source-controller
|
||||
newTag: 0.0.1-alpha.1
|
||||
newName: fluxcd/source-controller
|
||||
newTag: latest
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# permissions for end users to edit helmcharts.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: helmchart-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# permissions for end users to view helmcharts.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: helmchart-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
@ -26,6 +26,26 @@ rules:
|
|||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmcharts/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
name: gitrepository-sample
|
||||
annotations:
|
||||
source.fluxcd.io/syncAt: "2020-04-06T15:39:52+03:00"
|
||||
spec:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: HelmChart
|
||||
metadata:
|
||||
name: helmchart-sample
|
||||
spec:
|
||||
name: podinfo
|
||||
version: '^2.0.0'
|
||||
helmRepositoryRef:
|
||||
name: helmrepository-sample
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
name: helmrepository-sample
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://stefanprodan.github.io/podinfo
|
||||
|
|
|
|||
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
// HelmChartReconciler reconciles a HelmChart object
|
||||
type HelmChartReconciler struct {
|
||||
client.Client
|
||||
Log logr.Logger
|
||||
Scheme *runtime.Scheme
|
||||
Storage *Storage
|
||||
Kind string
|
||||
Getters getter.Providers
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=helmcharts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=helmcharts/status,verbs=get;update;patch
|
||||
|
||||
func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var chart sourcev1.HelmChart
|
||||
if err := r.Get(ctx, req.NamespacedName, &chart); err != nil {
|
||||
return ctrl.Result{Requeue: true}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
log := r.Log.WithValues(chart.Kind, req.NamespacedName)
|
||||
|
||||
// set initial status
|
||||
if reset, status := r.shouldResetStatus(chart); reset {
|
||||
log.Info("Initializing Helm chart")
|
||||
chart.Status = status
|
||||
if err := r.Status().Update(ctx, &chart); err != nil {
|
||||
log.Error(err, "unable to update HelmChart status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
}
|
||||
|
||||
// try to remove old artifacts
|
||||
r.gc(chart)
|
||||
|
||||
repository, err := r.chartRepository(ctx, chart)
|
||||
if err != nil {
|
||||
chart = sourcev1.HelmChartNotReady(*chart.DeepCopy(), sourcev1.ChartPullFailedReason, err.Error())
|
||||
if err := r.Status().Update(ctx, &chart); err != nil {
|
||||
log.Error(err, "unable to update HelmChart status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
// try to pull chart
|
||||
pulledChart, err := r.sync(repository, *chart.DeepCopy())
|
||||
if err != nil {
|
||||
log.Info("Helm chart pull failed", "error", err.Error())
|
||||
}
|
||||
|
||||
// update status
|
||||
if err := r.Status().Update(ctx, &pulledChart); err != nil {
|
||||
log.Error(err, "unable to update HelmChart status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
log.Info("Helm chart sync succeeded", "msg", sourcev1.HelmChartReadyMessage(pulledChart))
|
||||
|
||||
// requeue chart
|
||||
return ctrl.Result{RequeueAfter: repository.Spec.Interval.Duration}, nil
|
||||
}
|
||||
|
||||
func (r *HelmChartReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&sourcev1.HelmChart{}).
|
||||
WithEventFilter(RepositoryChangePredicate{}).
|
||||
WithEventFilter(predicate.Funcs{
|
||||
DeleteFunc: func(e event.DeleteEvent) bool {
|
||||
// delete artifacts
|
||||
artifact := r.Storage.ArtifactFor(r.Kind, e.Meta, "", "")
|
||||
if err := r.Storage.RemoveAll(artifact); err != nil {
|
||||
r.Log.Error(err, "unable to delete artifacts",
|
||||
r.Kind, fmt.Sprintf("%s/%s", e.Meta.GetNamespace(), e.Meta.GetName()))
|
||||
} else {
|
||||
r.Log.Info("Helm chart artifacts deleted",
|
||||
r.Kind, fmt.Sprintf("%s/%s", e.Meta.GetNamespace(), e.Meta.GetName()))
|
||||
}
|
||||
return false
|
||||
},
|
||||
}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *HelmChartReconciler) sync(repository sourcev1.HelmRepository, chart sourcev1.HelmChart) (sourcev1.HelmChart, error) {
|
||||
indexBytes, err := ioutil.ReadFile(repository.Status.Artifact.Path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to read Helm repository index file: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
index := &repo.IndexFile{}
|
||||
if err := yaml.Unmarshal(indexBytes, index); err != nil {
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
// find referenced chart in index
|
||||
cv, err := index.Get(chart.Spec.Name, chart.Spec.Version)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case repo.ErrNoChartName:
|
||||
err = fmt.Errorf("chart '%s' could not be found in Helm repository '%s'", chart.Spec.Name, repository.Name)
|
||||
case repo.ErrNoChartVersion:
|
||||
err = fmt.Errorf("no chart with version '%s' found for '%s'", chart.Spec.Version, chart.Spec.Name)
|
||||
}
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
if len(cv.URLs) == 0 {
|
||||
err = fmt.Errorf("chart '%s' has no downloadable URLs", cv.Name)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
// TODO(hidde): according to the Helm source the first item is not
|
||||
// always the correct one to pick, check for updates once in awhile.
|
||||
ref := cv.URLs[0]
|
||||
u, err := url.Parse(ref)
|
||||
if err != nil {
|
||||
err = errors.Errorf("invalid chart URL format '%s': %w", ref, err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
// TODO(hidde): auth options from Helm repository probably need to be
|
||||
// substituted here
|
||||
c, err := r.Getters.ByScheme(u.Scheme)
|
||||
if err != nil {
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
res, err := c.Get(u.String(), getter.WithURL(repository.Spec.URL))
|
||||
if err != nil {
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
chartBytes, err := ioutil.ReadAll(res)
|
||||
if err != nil {
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
sum := r.Storage.Checksum(chartBytes)
|
||||
artifact := r.Storage.ArtifactFor(chart.Kind, chart.GetObjectMeta(),
|
||||
fmt.Sprintf("%s-%s-%s.tgz", cv.Name, cv.Version, sum), cv.Version)
|
||||
|
||||
// create artifact dir
|
||||
err = r.Storage.MkdirAll(artifact)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to create chart directory: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
// acquire lock
|
||||
unlock, err := r.Storage.Lock(artifact)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to acquire lock: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
// save artifact to storage
|
||||
err = r.Storage.WriteFile(artifact, chartBytes)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to write chart file: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
// update index symlink
|
||||
chartUrl, err := r.Storage.Symlink(artifact, fmt.Sprintf("%s-latest.tgz", cv.Name))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("storage error: %w", err)
|
||||
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("Helm chart is available at: %s", artifact.Path)
|
||||
return sourcev1.HelmChartReady(chart, artifact, chartUrl, sourcev1.ChartPullSucceededReason, message), nil
|
||||
}
|
||||
|
||||
func (r *HelmChartReconciler) chartRepository(ctx context.Context, chart sourcev1.HelmChart) (sourcev1.HelmRepository, error) {
|
||||
if chart.Spec.HelmRepositoryRef.Name == "" {
|
||||
return sourcev1.HelmRepository{}, fmt.Errorf("no HelmRepository reference given")
|
||||
}
|
||||
|
||||
name := types.NamespacedName{
|
||||
Namespace: chart.GetNamespace(),
|
||||
Name: chart.Spec.HelmRepositoryRef.Name,
|
||||
}
|
||||
|
||||
var repository sourcev1.HelmRepository
|
||||
err := r.Client.Get(ctx, name, &repository)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to get HelmRepository '%s': %w", name, err)
|
||||
}
|
||||
|
||||
if repository.Status.Artifact == nil {
|
||||
err = fmt.Errorf("no repository index artifect found in HelmRepository '%s'", repository.Name)
|
||||
}
|
||||
|
||||
return repository, err
|
||||
}
|
||||
|
||||
func (r *HelmChartReconciler) shouldResetStatus(chart sourcev1.HelmChart) (bool, sourcev1.HelmChartStatus) {
|
||||
resetStatus := false
|
||||
if chart.Status.Artifact != nil {
|
||||
if !r.Storage.ArtifactExist(*chart.Status.Artifact) {
|
||||
resetStatus = true
|
||||
}
|
||||
}
|
||||
|
||||
// set initial status
|
||||
if len(chart.Status.Conditions) == 0 || resetStatus {
|
||||
resetStatus = true
|
||||
}
|
||||
|
||||
return resetStatus, sourcev1.HelmChartStatus{
|
||||
Conditions: []sourcev1.SourceCondition{
|
||||
{
|
||||
Type: sourcev1.ReadyCondition,
|
||||
Status: corev1.ConditionUnknown,
|
||||
Reason: sourcev1.InitializingReason,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HelmChartReconciler) gc(chart sourcev1.HelmChart) {
|
||||
if chart.Status.Artifact != nil {
|
||||
if err := r.Storage.RemoveAllButCurrent(*chart.Status.Artifact); err != nil {
|
||||
r.Log.Info("Artifacts GC failed", "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"gopkg.in/yaml.v2"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
@ -35,6 +34,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ var _ = BeforeSuite(func(done Done) {
|
|||
err = sourcev1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = sourcev1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -8,10 +8,11 @@ require (
|
|||
github.com/go-logr/logr v0.1.0
|
||||
github.com/onsi/ginkgo v1.11.0
|
||||
github.com/onsi/gomega v1.8.1
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
github.com/pkg/errors v0.9.1
|
||||
helm.sh/helm/v3 v3.1.2
|
||||
k8s.io/api v0.17.2
|
||||
k8s.io/apimachinery v0.17.2
|
||||
k8s.io/client-go v0.17.2
|
||||
sigs.k8s.io/controller-runtime v0.5.0
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
|
|
|
|||
7
go.sum
7
go.sum
|
|
@ -4,6 +4,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
|||
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
|
|
@ -116,6 +117,7 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
|
|||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
||||
|
|
@ -275,6 +277,7 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
|||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
|
|
@ -295,6 +298,7 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
|
|
@ -410,6 +414,7 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
|
|||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
|
|
@ -629,8 +634,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
helm.sh/helm v2.16.5+incompatible h1:cWIBFS2bwUEgWSIggw4gvwdWFH0BLE54X7/3WszxjWc=
|
||||
helm.sh/helm/v3 v3.1.2 h1:VpNzaNv2DX4aRnOCcV7v5Of+XT2SZrJ8iOQ25AGKOos=
|
||||
helm.sh/helm/v3 v3.1.2/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
24
main.go
24
main.go
|
|
@ -41,6 +41,12 @@ import (
|
|||
var (
|
||||
scheme = runtime.NewScheme()
|
||||
setupLog = ctrl.Log.WithName("setup")
|
||||
getters = getter.Providers{
|
||||
getter.Provider{
|
||||
Schemes: []string{"http", "https"},
|
||||
New: getter.NewHTTPGetter,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -98,16 +104,22 @@ func main() {
|
|||
Scheme: mgr.GetScheme(),
|
||||
Kind: "helmrepository",
|
||||
Storage: storage,
|
||||
Getters: getter.Providers{
|
||||
getter.Provider{
|
||||
Schemes: []string{"http", "https"},
|
||||
New: getter.NewHTTPGetter,
|
||||
},
|
||||
},
|
||||
Getters: getters,
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "HelmRepository")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err = (&controllers.HelmChartReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Log: ctrl.Log.WithName("controllers").WithName("HelmChart"),
|
||||
Scheme: mgr.GetScheme(),
|
||||
Kind: "helmchart",
|
||||
Storage: storage,
|
||||
Getters: getters,
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "HelmChart")
|
||||
os.Exit(1)
|
||||
}
|
||||
// +kubebuilder:scaffold:builder
|
||||
|
||||
setupLog.Info("starting manager")
|
||||
|
|
|
|||
Loading…
Reference in New Issue