diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 7463c457..e2ab4546 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -22,7 +22,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v2-beta with: - go-version: 1.14.x + go-version: 1.15.x - name: Setup Kubernetes uses: engineerd/setup-kind@v0.3.0 - name: Setup Kustomize diff --git a/Dockerfile b/Dockerfile index 1f741f7e..2d2d1934 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Docker buildkit multi-arch build requires golang alpine -FROM golang:1.14-alpine as builder +FROM golang:1.15-alpine as builder WORKDIR /workspace diff --git a/Makefile b/Makefile index 108805b6..2d7cdf15 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ manifests: controller-gen # Generate API reference documentation api-docs: gen-crd-api-reference-docs - $(API_REF_GEN) -api-dir=./api/v1alpha1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/source.md + $(API_REF_GEN) -api-dir=./api/v1beta1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/source.md # Run go fmt against code fmt: diff --git a/PROJECT b/PROJECT index e1408f7f..a807390b 100644 --- a/PROJECT +++ b/PROJECT @@ -3,14 +3,14 @@ repo: github.com/fluxcd/source-controller resources: - group: source kind: GitRepository - version: v1alpha1 + version: v1beta1 - group: source kind: HelmRepository - version: v1alpha1 + version: v1beta1 - group: source kind: HelmChart - version: v1alpha1 + version: v1beta1 - group: source kind: Bucket - version: v1alpha1 + version: v1beta1 version: "2" diff --git a/README.md b/README.md index df15d86b..8a521eef 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ [![release](https://img.shields.io/github/release/fluxcd/source-controller/all.svg)](https://github.com/fluxcd/source-controller/releases) The source-controller is a Kubernetes operator, specialised in artifacts acquisition -from external sources such as Git and Helm repositories. +from external sources such as Git, Helm repositories and S3 buckets. The source-controller implements the -[source.toolkit.fluxcd.io](https://github.com/fluxcd/source-controller/tree/master/docs/spec/v1alpha1) API +[source.toolkit.fluxcd.io](https://github.com/fluxcd/source-controller/tree/master/docs/spec/v1beta1) API and is a core component of the [GitOps toolkit](https://toolkit.fluxcd.io). ![overview](docs/diagrams/source-controller-overview.png) diff --git a/api/go.mod b/api/go.mod index 8f1f6a18..5925d41f 100644 --- a/api/go.mod +++ b/api/go.mod @@ -1,6 +1,6 @@ module github.com/fluxcd/source-controller/api -go 1.14 +go 1.15 require ( github.com/fluxcd/pkg/apis/meta v0.0.2 diff --git a/api/v1alpha1/artifact_types.go b/api/v1beta1/artifact_types.go similarity index 99% rename from api/v1alpha1/artifact_types.go rename to api/v1beta1/artifact_types.go index d902cf0e..634009ba 100644 --- a/api/v1alpha1/artifact_types.go +++ b/api/v1beta1/artifact_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "path" diff --git a/api/v1alpha1/bucket_types.go b/api/v1beta1/bucket_types.go similarity index 99% rename from api/v1alpha1/bucket_types.go rename to api/v1beta1/bucket_types.go index 51663413..919cd152 100644 --- a/api/v1alpha1/bucket_types.go +++ b/api/v1beta1/bucket_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "time" diff --git a/api/v1alpha1/condition_types.go b/api/v1beta1/condition_types.go similarity index 98% rename from api/v1alpha1/condition_types.go rename to api/v1beta1/condition_types.go index ba4354ee..b8ae2e7b 100644 --- a/api/v1alpha1/condition_types.go +++ b/api/v1beta1/condition_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 const SourceFinalizer = "finalizers.fluxcd.io" diff --git a/api/v1alpha1/doc.go b/api/v1beta1/doc.go similarity index 86% rename from api/v1alpha1/doc.go rename to api/v1beta1/doc.go index 2f0db689..7054f20f 100644 --- a/api/v1alpha1/doc.go +++ b/api/v1beta1/doc.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package v1alpha1 contains API Schema definitions for the source v1alpha1 API group +// Package v1beta1 contains API Schema definitions for the source v1beta1 API group // +kubebuilder:object:generate=true // +groupName=source.toolkit.fluxcd.io -package v1alpha1 +package v1beta1 diff --git a/api/v1alpha1/gitrepository_types.go b/api/v1beta1/gitrepository_types.go similarity index 99% rename from api/v1alpha1/gitrepository_types.go rename to api/v1beta1/gitrepository_types.go index 7addd52f..280d27a9 100644 --- a/api/v1alpha1/gitrepository_types.go +++ b/api/v1beta1/gitrepository_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "time" diff --git a/api/v1alpha1/groupversion_info.go b/api/v1beta1/groupversion_info.go similarity index 95% rename from api/v1alpha1/groupversion_info.go rename to api/v1beta1/groupversion_info.go index 76eb67c4..af904bd5 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1beta1/groupversion_info.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "k8s.io/apimachinery/pkg/runtime/schema" @@ -23,7 +23,7 @@ import ( var ( // GroupVersion is group version used to register these objects. - GroupVersion = schema.GroupVersion{Group: "source.toolkit.fluxcd.io", Version: "v1alpha1"} + GroupVersion = schema.GroupVersion{Group: "source.toolkit.fluxcd.io", Version: "v1beta1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1alpha1/helmchart_types.go b/api/v1beta1/helmchart_types.go similarity index 99% rename from api/v1alpha1/helmchart_types.go rename to api/v1beta1/helmchart_types.go index a4edf84d..d90e12ca 100644 --- a/api/v1alpha1/helmchart_types.go +++ b/api/v1beta1/helmchart_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "github.com/fluxcd/pkg/apis/meta" diff --git a/api/v1alpha1/helmrepository_types.go b/api/v1beta1/helmrepository_types.go similarity index 99% rename from api/v1alpha1/helmrepository_types.go rename to api/v1beta1/helmrepository_types.go index 087625c4..522bb79a 100644 --- a/api/v1alpha1/helmrepository_types.go +++ b/api/v1beta1/helmrepository_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "time" diff --git a/api/v1alpha1/source.go b/api/v1beta1/source.go similarity index 95% rename from api/v1alpha1/source.go rename to api/v1beta1/source.go index 581a3fe6..b5afd25e 100644 --- a/api/v1alpha1/source.go +++ b/api/v1beta1/source.go @@ -1,4 +1,4 @@ -package v1alpha1 +package v1beta1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go similarity index 99% rename from api/v1alpha1/zz_generated.deepcopy.go rename to api/v1beta1/zz_generated.deepcopy.go index 0120706c..f7dcc5dd 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -18,7 +18,7 @@ limitations under the License. // Code generated by controller-gen. DO NOT EDIT. -package v1alpha1 +package v1beta1 import ( "github.com/fluxcd/pkg/apis/meta" diff --git a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml index 39fe367d..f6244fbe 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml @@ -29,7 +29,7 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - name: v1alpha1 + name: v1beta1 schema: openAPIV3Schema: description: Bucket is the Schema for the buckets API diff --git a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml index 9a27c785..59bd4bfb 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml @@ -29,7 +29,7 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - name: v1alpha1 + name: v1beta1 schema: openAPIV3Schema: description: GitRepository is the Schema for the gitrepositories API diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index 4bf53806..7b1218c2 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -38,7 +38,7 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - name: v1alpha1 + name: v1beta1 schema: openAPIV3Schema: description: HelmChart is the Schema for the helmcharts API diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml index dd7035c2..c2ee96ba 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml @@ -29,7 +29,7 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - name: v1alpha1 + name: v1beta1 schema: openAPIV3Schema: description: HelmRepository is the Schema for the helmrepositories API diff --git a/config/samples/source_v1alpha1_bucket.yaml b/config/samples/source_v1alpha1_bucket.yaml index 6fa1b140..e536d45c 100644 --- a/config/samples/source_v1alpha1_bucket.yaml +++ b/config/samples/source_v1alpha1_bucket.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: Bucket metadata: name: bucket-sample diff --git a/config/samples/source_v1alpha1_gitrepository.yaml b/config/samples/source_v1alpha1_gitrepository.yaml index 51e4222a..9719fd21 100644 --- a/config/samples/source_v1alpha1_gitrepository.yaml +++ b/config/samples/source_v1alpha1_gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: GitRepository metadata: name: gitrepository-sample diff --git a/config/samples/source_v1alpha1_helmchart_gitrepository.yaml b/config/samples/source_v1alpha1_helmchart_gitrepository.yaml index 5e8fec85..0a8db7c6 100644 --- a/config/samples/source_v1alpha1_helmchart_gitrepository.yaml +++ b/config/samples/source_v1alpha1_helmchart_gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmChart metadata: name: helmchart-git-sample diff --git a/config/samples/source_v1alpha1_helmchart_helmrepository.yaml b/config/samples/source_v1alpha1_helmchart_helmrepository.yaml index 2aa32c54..07cd3b5d 100644 --- a/config/samples/source_v1alpha1_helmchart_helmrepository.yaml +++ b/config/samples/source_v1alpha1_helmchart_helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmChart metadata: name: helmchart-sample diff --git a/config/samples/source_v1alpha1_helmrepository.yaml b/config/samples/source_v1alpha1_helmrepository.yaml index 6a6be4f6..6a6e65f4 100644 --- a/config/samples/source_v1alpha1_helmrepository.yaml +++ b/config/samples/source_v1alpha1_helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: helmrepository-sample diff --git a/config/testdata/bucket/source.yaml b/config/testdata/bucket/source.yaml index 3bc569d3..459e7400 100644 --- a/config/testdata/bucket/source.yaml +++ b/config/testdata/bucket/source.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: Bucket metadata: name: podinfo diff --git a/config/testdata/helmchart-from-bucket/source.yaml b/config/testdata/helmchart-from-bucket/source.yaml index 9c09321f..0609cf54 100644 --- a/config/testdata/helmchart-from-bucket/source.yaml +++ b/config/testdata/helmchart-from-bucket/source.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: Bucket metadata: name: charts @@ -13,7 +13,7 @@ spec: secretRef: name: minio-credentials --- -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmChart metadata: name: helmchart-bucket diff --git a/config/testdata/helmchart-valuesfile/gitrepository.yaml b/config/testdata/helmchart-valuesfile/gitrepository.yaml index a72ff950..b9324f6b 100644 --- a/config/testdata/helmchart-valuesfile/gitrepository.yaml +++ b/config/testdata/helmchart-valuesfile/gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: GitRepository metadata: name: bitnami-charts diff --git a/config/testdata/helmchart-valuesfile/helmchart_gitrepository.yaml b/config/testdata/helmchart-valuesfile/helmchart_gitrepository.yaml index f6e85fd8..25163995 100644 --- a/config/testdata/helmchart-valuesfile/helmchart_gitrepository.yaml +++ b/config/testdata/helmchart-valuesfile/helmchart_gitrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmChart metadata: name: mariadb-git diff --git a/config/testdata/helmchart-valuesfile/helmchart_helmrepository.yaml b/config/testdata/helmchart-valuesfile/helmchart_helmrepository.yaml index fa479fab..e0c03517 100644 --- a/config/testdata/helmchart-valuesfile/helmchart_helmrepository.yaml +++ b/config/testdata/helmchart-valuesfile/helmchart_helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmChart metadata: name: mariadb diff --git a/config/testdata/helmchart-valuesfile/helmrepository.yaml b/config/testdata/helmchart-valuesfile/helmrepository.yaml index 432e3e3c..adb1cf54 100644 --- a/config/testdata/helmchart-valuesfile/helmrepository.yaml +++ b/config/testdata/helmchart-valuesfile/helmrepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1alpha1 +apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: bitnami-charts diff --git a/controllers/bucket_controller.go b/controllers/bucket_controller.go index 3c62f005..b0fc6792 100644 --- a/controllers/bucket_controller.go +++ b/controllers/bucket_controller.go @@ -42,7 +42,7 @@ import ( "github.com/fluxcd/pkg/recorder" "github.com/fluxcd/pkg/runtime/predicates" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) // BucketReconciler reconciles a Bucket object @@ -315,7 +315,7 @@ func (r *BucketReconciler) checksum(root string) (string, error) { return fmt.Sprintf("%x", sha1.Sum([]byte(checksum))), nil } -// resetStatus returns a modified v1alpha1.Bucket and a boolean indicating +// resetStatus returns a modified v1beta1.Bucket and a boolean indicating // if the status field has been reset. func (r *BucketReconciler) resetStatus(bucket sourcev1.Bucket) (sourcev1.Bucket, bool) { // We do not have an artifact, or it does no longer exist diff --git a/controllers/gitrepository_controller.go b/controllers/gitrepository_controller.go index 5afb0c65..04269742 100644 --- a/controllers/gitrepository_controller.go +++ b/controllers/gitrepository_controller.go @@ -40,7 +40,7 @@ import ( "github.com/fluxcd/pkg/recorder" "github.com/fluxcd/pkg/runtime/predicates" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/source-controller/pkg/git" ) @@ -274,7 +274,7 @@ func (r *GitRepositoryReconciler) verify(ctx context.Context, publicKeySecret ty return nil } -// resetStatus returns a modified v1alpha1.GitRepository and a boolean indicating +// resetStatus returns a modified v1beta1.GitRepository and a boolean indicating // if the status field has been reset. func (r *GitRepositoryReconciler) resetStatus(repository sourcev1.GitRepository) (sourcev1.GitRepository, bool) { // We do not have an artifact, or it does no longer exist diff --git a/controllers/gitrepository_controller_test.go b/controllers/gitrepository_controller_test.go index 053b3d05..4e01dad4 100644 --- a/controllers/gitrepository_controller_test.go +++ b/controllers/gitrepository_controller_test.go @@ -41,7 +41,7 @@ import ( "github.com/fluxcd/pkg/gittestserver" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var _ = Describe("GitRepositoryReconciler", func() { diff --git a/controllers/helmchart_controller.go b/controllers/helmchart_controller.go index 8448d63a..7d7aabf9 100644 --- a/controllers/helmchart_controller.go +++ b/controllers/helmchart_controller.go @@ -44,7 +44,7 @@ import ( "github.com/fluxcd/pkg/runtime/predicates" "github.com/fluxcd/pkg/untar" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/source-controller/internal/helm" ) @@ -474,7 +474,7 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context, return sourcev1.HelmChartReady(chart, newArtifact, cUrl, sourcev1.ChartPackageSucceededReason, message), nil } -// resetStatus returns a modified v1alpha1.HelmChart and a boolean indicating +// resetStatus returns a modified v1beta1.HelmChart and a boolean indicating // if the status field has been reset. func (r *HelmChartReconciler) resetStatus(chart sourcev1.HelmChart) (sourcev1.HelmChart, bool) { // We do not have an artifact, or it does no longer exist diff --git a/controllers/helmchart_controller_test.go b/controllers/helmchart_controller_test.go index 15b494c3..6c088ef7 100644 --- a/controllers/helmchart_controller_test.go +++ b/controllers/helmchart_controller_test.go @@ -45,7 +45,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/yaml" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var _ = Describe("HelmChartReconciler", func() { diff --git a/controllers/helmrepository_controller.go b/controllers/helmrepository_controller.go index c0b9fb01..2bc9178e 100644 --- a/controllers/helmrepository_controller.go +++ b/controllers/helmrepository_controller.go @@ -40,7 +40,7 @@ import ( "github.com/fluxcd/pkg/recorder" "github.com/fluxcd/pkg/runtime/predicates" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/source-controller/internal/helm" ) @@ -248,7 +248,7 @@ func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, repository sou return sourcev1.HelmRepositoryReady(repository, artifact, indexURL, sourcev1.IndexationSucceededReason, message), nil } -// resetStatus returns a modified v1alpha1.HelmRepository and a boolean indicating +// resetStatus returns a modified v1beta1.HelmRepository and a boolean indicating // if the status field has been reset. func (r *HelmRepositoryReconciler) resetStatus(repository sourcev1.HelmRepository) (sourcev1.HelmRepository, bool) { // We do not have an artifact, or it does no longer exist diff --git a/controllers/helmrepository_controller_test.go b/controllers/helmrepository_controller_test.go index 2a8fd072..8483ec62 100644 --- a/controllers/helmrepository_controller_test.go +++ b/controllers/helmrepository_controller_test.go @@ -32,7 +32,7 @@ import ( "github.com/fluxcd/pkg/helmtestserver" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var _ = Describe("HelmRepositoryReconciler", func() { diff --git a/controllers/storage.go b/controllers/storage.go index 18d1db9c..5469b383 100644 --- a/controllers/storage.go +++ b/controllers/storage.go @@ -37,7 +37,7 @@ import ( "github.com/fluxcd/pkg/lockedfile" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/source-controller/internal/fs" ) @@ -71,7 +71,7 @@ func NewStorage(basePath string, hostname string, timeout time.Duration) (*Stora }, nil } -// NewArtifactFor returns a new v1alpha1.Artifact. +// NewArtifactFor returns a new v1beta1.Artifact. func (s *Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, fileName string) sourcev1.Artifact { path := sourcev1.ArtifactPath(kind, metadata.GetNamespace(), metadata.GetName(), fileName) artifact := sourcev1.Artifact{ @@ -82,7 +82,7 @@ func (s *Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, return artifact } -// SetArtifactURL sets the URL on the given v1alpha1.Artifact. +// SetArtifactURL sets the URL on the given v1beta1.Artifact. func (s Storage) SetArtifactURL(artifact *sourcev1.Artifact) { if artifact.Path == "" { return @@ -101,19 +101,19 @@ func (s Storage) SetHostname(URL string) string { return u.String() } -// MkdirAll calls os.MkdirAll for the given v1alpha1.Artifact base dir. +// MkdirAll calls os.MkdirAll for the given v1beta1.Artifact base dir. func (s *Storage) MkdirAll(artifact sourcev1.Artifact) error { dir := filepath.Dir(s.LocalPath(artifact)) return os.MkdirAll(dir, 0777) } -// RemoveAll calls os.RemoveAll for the given v1alpha1.Artifact base dir. +// RemoveAll calls os.RemoveAll for the given v1beta1.Artifact base dir. func (s *Storage) RemoveAll(artifact sourcev1.Artifact) error { dir := filepath.Dir(s.LocalPath(artifact)) return os.RemoveAll(dir) } -// RemoveAllButCurrent removes all files for the given v1alpha1.Artifact base dir, +// RemoveAllButCurrent removes all files for the given v1beta1.Artifact base dir, // excluding the current one. func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error { localPath := s.LocalPath(artifact) @@ -139,7 +139,7 @@ func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error { return nil } -// ArtifactExist returns a boolean indicating whether the v1alpha1.Artifact exists in storage +// ArtifactExist returns a boolean indicating whether the v1beta1.Artifact exists in storage // and is a regular file. func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool { fi, err := os.Lstat(s.LocalPath(artifact)) @@ -149,7 +149,7 @@ func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool { return fi.Mode().IsRegular() } -// Archive atomically archives the given directory as a tarball to the given v1alpha1.Artifact +// Archive atomically archives the given directory as a tarball to the given v1beta1.Artifact // path, excluding any VCS specific files and directories, or any of the excludes defined in // the excludeFiles. If successful, it sets the checksum and last update time on the artifact. func (s *Storage) Archive(artifact *sourcev1.Artifact, dir string, ignore *string) (err error) { @@ -265,7 +265,7 @@ func writeToArchiveExcludeMatches(dir string, matcher gitignore.Matcher, writer return filepath.Walk(dir, fn) } -// AtomicWriteFile atomically writes the io.Reader contents to the v1alpha1.Artifact path. +// AtomicWriteFile atomically writes the io.Reader contents to the v1beta1.Artifact path. // If successful, it sets the checksum and last update time on the artifact. func (s *Storage) AtomicWriteFile(artifact *sourcev1.Artifact, reader io.Reader, mode os.FileMode) (err error) { localPath := s.LocalPath(*artifact) @@ -304,7 +304,7 @@ func (s *Storage) AtomicWriteFile(artifact *sourcev1.Artifact, reader io.Reader, return nil } -// Copy atomically copies the io.Reader contents to the v1alpha1.Artifact path. +// Copy atomically copies the io.Reader contents to the v1beta1.Artifact path. // If successful, it sets the checksum and last update time on the artifact. func (s *Storage) Copy(artifact *sourcev1.Artifact, reader io.Reader) (err error) { localPath := s.LocalPath(*artifact) @@ -340,7 +340,7 @@ func (s *Storage) Copy(artifact *sourcev1.Artifact, reader io.Reader) (err error } // CopyFromPath atomically copies the contents of the given path to the path of -// the v1alpha1.Artifact. If successful, the checksum and last update time on the +// the v1beta1.Artifact. If successful, the checksum and last update time on the // artifact is set. func (s *Storage) CopyFromPath(artifact *sourcev1.Artifact, path string) (err error) { f, err := os.Open(path) @@ -351,7 +351,7 @@ func (s *Storage) CopyFromPath(artifact *sourcev1.Artifact, path string) (err er return s.Copy(artifact, f) } -// Symlink creates or updates a symbolic link for the given v1alpha1.Artifact +// Symlink creates or updates a symbolic link for the given v1beta1.Artifact // and returns the URL for the symlink. func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string, error) { localPath := s.LocalPath(artifact) @@ -382,7 +382,7 @@ func (s *Storage) Checksum(reader io.Reader) string { return fmt.Sprintf("%x", h.Sum(nil)) } -// Lock creates a file lock for the given v1alpha1.Artifact. +// Lock creates a file lock for the given v1beta1.Artifact. func (s *Storage) Lock(artifact sourcev1.Artifact) (unlock func(), err error) { lockFile := s.LocalPath(artifact) + ".lock" mutex := lockedfile.MutexAt(lockFile) diff --git a/controllers/storage_test.go b/controllers/storage_test.go index 8ec9d42c..fe1d8bc3 100644 --- a/controllers/storage_test.go +++ b/controllers/storage_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) type ignoreMap map[string]bool diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 74912c9d..9c792752 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -36,7 +36,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" // +kubebuilder:scaffold:imports ) diff --git a/docs/api/source.md b/docs/api/source.md index 2971dbd5..b32c4c6f 100644 --- a/docs/api/source.md +++ b/docs/api/source.md @@ -2,22 +2,22 @@

Packages:

-

source.toolkit.fluxcd.io/v1alpha1

-

Package v1alpha1 contains API Schema definitions for the source v1alpha1 API group

+

source.toolkit.fluxcd.io/v1beta1

+

Package v1beta1 contains API Schema definitions for the source v1beta1 API group

Resource Types: -

Bucket +

Bucket

Bucket is the Schema for the buckets API

@@ -35,7 +35,7 @@ Resource Types: apiVersion
string -source.toolkit.fluxcd.io/v1alpha1 +source.toolkit.fluxcd.io/v1beta1 @@ -65,7 +65,7 @@ Refer to the Kubernetes API documentation for the fields of the spec
- + BucketSpec @@ -194,7 +194,7 @@ string status
- + BucketStatus @@ -206,7 +206,7 @@ BucketStatus
-

GitRepository +

GitRepository

GitRepository is the Schema for the gitrepositories API

@@ -224,7 +224,7 @@ BucketStatus apiVersion
string -source.toolkit.fluxcd.io/v1alpha1 +source.toolkit.fluxcd.io/v1beta1 @@ -254,7 +254,7 @@ Refer to the Kubernetes API documentation for the fields of the spec
- + GitRepositorySpec @@ -323,7 +323,7 @@ Kubernetes meta/v1.Duration ref
- + GitRepositoryRef @@ -338,7 +338,7 @@ master branch.

verify
- + GitRepositoryVerification @@ -369,7 +369,7 @@ consult the documentation for your version to find out what those are.

status
- + GitRepositoryStatus @@ -381,7 +381,7 @@ GitRepositoryStatus
-

HelmChart +

HelmChart

HelmChart is the Schema for the helmcharts API

@@ -399,7 +399,7 @@ GitRepositoryStatus apiVersion
string -source.toolkit.fluxcd.io/v1alpha1 +source.toolkit.fluxcd.io/v1beta1 @@ -429,7 +429,7 @@ Refer to the Kubernetes API documentation for the fields of the spec
- + HelmChartSpec @@ -466,7 +466,7 @@ and Bucket sources. Defaults to latest when omitted.

sourceRef
- + LocalHelmChartSourceReference @@ -508,7 +508,7 @@ relative path in the SourceRef. Ignored when omitted.

status
- + HelmChartStatus @@ -520,7 +520,7 @@ HelmChartStatus
-

HelmRepository +

HelmRepository

HelmRepository is the Schema for the helmrepositories API

@@ -538,7 +538,7 @@ HelmChartStatus apiVersion
string -source.toolkit.fluxcd.io/v1alpha1 +source.toolkit.fluxcd.io/v1beta1 @@ -568,7 +568,7 @@ Refer to the Kubernetes API documentation for the fields of the spec
- + HelmRepositorySpec @@ -641,7 +641,7 @@ Kubernetes meta/v1.Duration status
- + HelmRepositoryStatus @@ -653,14 +653,14 @@ HelmRepositoryStatus
-

Artifact +

Artifact

(Appears on: -BucketStatus, -GitRepositoryStatus, -HelmChartStatus, -HelmRepositoryStatus) +BucketStatus, +GitRepositoryStatus, +HelmChartStatus, +HelmRepositoryStatus)

Artifact represents the output of a source synchronisation.

@@ -739,11 +739,11 @@ artifact.

-

BucketSpec +

BucketSpec

(Appears on: -Bucket) +Bucket)

BucketSpec defines the desired state of an S3 compatible bucket

@@ -873,11 +873,11 @@ string
-

BucketStatus +

BucketStatus

(Appears on: -Bucket) +Bucket)

BucketStatus defines the observed state of a bucket

@@ -932,7 +932,7 @@ string artifact
- + Artifact @@ -946,11 +946,11 @@ Artifact
-

GitRepositoryRef +

GitRepositoryRef

(Appears on: -GitRepositorySpec) +GitRepositorySpec)

GitRepositoryRef defines the git ref used for pull and checkout operations.

@@ -1015,11 +1015,11 @@ string
-

GitRepositorySpec +

GitRepositorySpec

(Appears on: -GitRepository) +GitRepository)

GitRepositorySpec defines the desired state of a Git repository.

@@ -1092,7 +1092,7 @@ Kubernetes meta/v1.Duration ref
- + GitRepositoryRef @@ -1107,7 +1107,7 @@ master branch.

verify
- + GitRepositoryVerification @@ -1135,11 +1135,11 @@ consult the documentation for your version to find out what those are.

-

GitRepositoryStatus +

GitRepositoryStatus

(Appears on: -GitRepository) +GitRepository)

GitRepositoryStatus defines the observed state of a Git repository.

@@ -1195,7 +1195,7 @@ sync.

artifact
- + Artifact @@ -1209,11 +1209,11 @@ Artifact
-

GitRepositoryVerification +

GitRepositoryVerification

(Appears on: -GitRepositorySpec) +GitRepositorySpec)

GitRepositoryVerification defines the OpenPGP signature verification process.

@@ -1254,11 +1254,11 @@ Kubernetes core/v1.LocalObjectReference
-

HelmChartSpec +

HelmChartSpec

(Appears on: -HelmChart) +HelmChart)

HelmChartSpec defines the desired state of a Helm chart.

@@ -1299,7 +1299,7 @@ and Bucket sources. Defaults to latest when omitted.

sourceRef
- + LocalHelmChartSourceReference @@ -1338,11 +1338,11 @@ relative path in the SourceRef. Ignored when omitted.

-

HelmChartStatus +

HelmChartStatus

(Appears on: -HelmChart) +HelmChart)

HelmChartStatus defines the observed state of the HelmChart.

@@ -1397,7 +1397,7 @@ string artifact
- + Artifact @@ -1411,11 +1411,11 @@ Artifact
-

HelmRepositorySpec +

HelmRepositorySpec

(Appears on: -HelmRepository) +HelmRepository)

HelmRepositorySpec defines the reference to a Helm repository.

@@ -1489,11 +1489,11 @@ Kubernetes meta/v1.Duration
-

HelmRepositoryStatus +

HelmRepositoryStatus

(Appears on: -HelmRepository) +HelmRepository)

HelmRepositoryStatus defines the observed state of the HelmRepository.

@@ -1548,7 +1548,7 @@ string artifact
- + Artifact @@ -1562,11 +1562,11 @@ Artifact
-

LocalHelmChartSourceReference +

LocalHelmChartSourceReference

(Appears on: -HelmChartSpec) +HelmChartSpec)

LocalHelmChartSourceReference contains enough information to let you locate the typed referenced object at namespace level.

@@ -1619,7 +1619,7 @@ string -

Source +

Source

Source interface must be supported by all API types.

diff --git a/docs/spec/README.md b/docs/spec/README.md index d0bd5dd0..16ca15fd 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -20,7 +20,7 @@ of the components using them. ## API Specification -* [v1alpha1](v1alpha1/README.md) +* [v1beta1](v1beta1/README.md) ## Implementation diff --git a/docs/spec/v1beta1/README.md b/docs/spec/v1beta1/README.md new file mode 100644 index 00000000..728f4062 --- /dev/null +++ b/docs/spec/v1beta1/README.md @@ -0,0 +1,21 @@ +# source.toolkit.fluxcd.io/v1beta1 + +This is the v1beta1 API specification for defining the desired state sources of Kubernetes clusters. + +## Specification + +* [Common](common.md) +* Source kinds: + + [GitRepository](gitrepositories.md) + + [HelmRepository](helmrepositories.md) + + [HelmChart](helmcharts.md) + + [Bucket](buckets.md) + +## Implementation + +* [source-controller](https://github.com/fluxcd/source-controller/) + +## Consumers + +* [kustomize-controller](https://github.com/fluxcd/kustomize-controller/) +* [helm-controller](https://github.com/fluxcd/helm-controller/) diff --git a/docs/spec/v1beta1/buckets.md b/docs/spec/v1beta1/buckets.md new file mode 100644 index 00000000..ee3e7be8 --- /dev/null +++ b/docs/spec/v1beta1/buckets.md @@ -0,0 +1,234 @@ +# Object storage buckets + +The `Bucket` API defines a source for artifacts coming from S3 compatible storage +such as Minio, Amazon S3, Google Cloud Storage, Alibaba Cloud OSS and others. + +## Specification + +Bucket: + +```go +// BucketSpec defines the desired state of an S3 compatible bucket +type BucketSpec struct { + // The S3 compatible storage provider name, default ('generic'). + // +kubebuilder:validation:Enum=generic;aws + // +optional + Provider string `json:"provider,omitempty"` + + // The bucket name. + // +required + BucketName string `json:"bucketName"` + + // The bucket endpoint address. + // +required + Endpoint string `json:"endpoint"` + + // Insecure allows connecting to a non-TLS S3 HTTP endpoint. + // +optional + Insecure bool `json:"insecure,omitempty"` + + // The bucket region. + // +optional + Region string `json:"region,omitempty"` + + // The name of the secret containing authentication credentials + // for the Bucket. + // +optional + SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` + + // The interval at which to check for bucket updates. + // +required + Interval metav1.Duration `json:"interval"` + + // The timeout for download operations, default ('20s'). + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). + // +optional + Ignore *string `json:"ignore,omitempty"` +} +``` + +Supported providers: + +```go +const ( + GenericBucketProvider string = "generic" + AmazonBucketProvider string = "aws" +) +``` + +### Status + +```go +// BucketStatus defines the observed state of a bucket +type BucketStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions holds the conditions for the Bucket. + // +optional + Conditions []meta.Condition `json:"conditions,omitempty"` + + // URL is the download link for the artifact output of the last Bucket sync. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful Bucket sync. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` +} +``` + +### Condition reasons + +```go +const ( + // BucketOperationSucceedReason represents the fact that the bucket listing and + // download operations succeeded. + BucketOperationSucceedReason string = "BucketOperationSucceed" + + // BucketOperationFailedReason represents the fact that the bucket listing or + // download operations failed. + BucketOperationFailedReason string = "BucketOperationFailed" +) +``` + +## Artifact + +The resource exposes the latest synchronized state from S3 as an artifact +in a gzip compressed TAR archive (`.tar.gz`). + +### Excluding files + +Git files (`.git/`, `.gitignore`, `.gitmodules`, and `.gitattributes`) are +excluded from the archive by default, as well as some extensions (`.jpg, .jpeg, +.gif, .png, .wmv, .flv, .tar.gz, .zip`) + +Excluding additional files from the archive is possible by adding a +`.sourceignore` file in the root of the bucket. The `.sourceignore` file +follows [the `.gitignore` pattern +format](https://git-scm.com/docs/gitignore#_pattern_format), pattern +entries may overrule default exclusions. + +Another option is to use the `spec.ignore` field, for example: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: Bucket +metadata: + name: podinfo +spec: + ignore: | + # exclude all + /* + # include deploy dir + !/deploy + # exclude file extensions from deploy dir + /deploy/**/*.md + /deploy/**/*.txt +``` + +When specified, `spec.ignore` overrides the default exclusion list. + +## Spec examples + +### Static authentication + +Authentication credentials can be provided with a Kubernetes secret that contains +`accesskey` and `secretkey` fields: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: Bucket +metadata: + name: podinfo + namespace: gitops-system +spec: + interval: 1m + provider: generic + bucketName: podinfo + endpoint: minio.minio.svc.cluster.local:9000 + insecure: true + secretRef: + name: minio-credentials +--- +apiVersion: v1 +kind: Secret +metadata: + name: minio-credentials + namespace: gitops-system +type: Opaque +data: + accesskey: + secretkey: +``` + +> **Note:** that for Google Cloud Storage you have to enable +> S3 compatible access in your GCP project. + +### AWS IAM authentication + +When the provider is `aws` and the `secretRef` is not specified, +the credentials are retrieve from the EC2 service: + +```yaml +apiVersion: source.toolkit.fluccd.io/v1beta1 +kind: Bucket +metadata: + name: podinfo + namespace: gitops-system +spec: + interval: 5m + provider: aws + bucketName: podinfo + endpoint: s3.amazonaws.com + region: us-east-1 + timeout: 30s +``` + +> **Note:** that on EKS you have to create an IAM role for the source-controller +> service account that grants access to the bucket. + +## Status examples + +Successful download: + +```yaml + status: + artifact: + checksum: b249024b8544521792a079c4037d0a06dd0497a9 + lastUpdateTime: "2020-09-18T08:34:49Z" + path: bucket/gitops-system/podinfo/aeaba8b6dd51c53084f99b098cfae4f5148ad410.tar.gz + revision: aeaba8b6dd51c53084f99b098cfae4f5148ad410 + url: http://localhost:9090/bucket/gitops-system/podinfo/aeaba8b6dd51c53084f99b098cfae4f5148ad410.tar.gz + conditions: + - lastTransitionTime: "2020-09-18T08:34:49Z" + message: 'Fetched revision: aeaba8b6dd51c53084f99b098cfae4f5148ad410' + reason: BucketOperationSucceed + status: "True" + type: Ready + observedGeneration: 2 + url: http://localhost:9090/bucket/gitops-system/podinfo/latest.tar.gz +``` + +Failed download: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-09-18T08:34:49Z" + message: "bucket 'test' not found" + reason: BucketOperationFailed + status: "False" + type: Ready +``` + +Wait for ready condition: + +```bash +kubectl -n gitios-system wait bucket/podinfo --for=condition=ready --timeout=1m +``` diff --git a/docs/spec/v1beta1/common.md b/docs/spec/v1beta1/common.md new file mode 100644 index 00000000..ab35da57 --- /dev/null +++ b/docs/spec/v1beta1/common.md @@ -0,0 +1,114 @@ +# Common + +Common defines resources used across all source types. + +## Specification + +### Source interface + +Source objects should adhere to the `Source` interface. This interface exposes the [interval](#source-synchronization) +and [artifact](#source-status) of the source to clients without the prerequisite of knowing the source kind: + +````go +type Source interface { + // GetInterval returns the interval at which the source is updated. + GetInterval() metav1.Duration + + // GetArtifact returns the latest artifact from the source, or nil. + GetArtifact() *Artifact +} +```` + +### Source reconciliation + +Source objects should contain a `spec.interval` field that tells the controller at which interval to check for updates: + +```go +type SourceSpec struct { + // The interval at which to check for source updates. + // +required + Interval metav1.Duration `json:"interval"` +} +``` + +Valid time units are `s`, `m` and `h` e.g. `interval: 5m`. + +The controller can be told to check for updates right away by setting an annotation on source objects: + +```bash +kubectl annotate --overwrite gitrepository/podinfo fluxcd.io/reconcileAt="$(date +%s)" +``` + +### Source status + +Source objects should contain a status sub-resource that embeds an artifact object: + +```go +// Artifact represents the output of a source synchronisation. +type Artifact struct { + // Path is the relative file path of this artifact. + // +required + Path string `json:"path"` + + // URL is the HTTP address of this artifact. + // +required + URL string `json:"url"` + + // Revision is a human readable identifier traceable in the origin + // source system. It can be a Git commit sha, Git tag, a Helm index + // timestamp, a Helm chart version, etc. + // +optional + Revision string `json:"revision"` + + // Checksum is the SHA1 checksum of the artifact. + // +optional + Checksum string `json:"checksum"` + + // LastUpdateTime is the timestamp corresponding to the last + // update of this artifact. + // +required + LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` +} +``` + +### Source condition + +> **Note:** to be replaced with +> once made available. + +Source objects should implement the [`meta.Condition`](https://godoc.org/github.com/fluxcd/pkg/apis/meta#Condition). + +#### Types + +Source objects should implement the [`meta.ReadyCondition`](https://godoc.org/github.com/fluxcd/pkg/apis/meta#pkg-constants), +but may implement additional domain-specific types. + +#### Reasons + +Source objects may implement the [`meta` condition +reasons](https://godoc.org/github.com/fluxcd/pkg/apis/meta#pkg-constants), but +are allowed to use their own reasons if they provide a better explanation. + +In addition, the following source specific reasons are available: + +```go +const ( + // URLInvalidReason represents the fact that a given source has an invalid URL. + URLInvalidReason string = "URLInvalid" + + // StorageOperationFailedReason signals a failure caused by a storage operation. + StorageOperationFailedReason string = "StorageOperationFailed" + + // AuthenticationFailedReason represents the fact that a given secret does not + // have the required fields or the provided credentials do not match. + AuthenticationFailedReason string = "AuthenticationFailed" + + // VerificationFailedReason represents the fact that the cryptographic provenance + // verification for the source failed. + VerificationFailedReason string = "VerificationFailed" +) +``` + +## Examples + +See the [`GitRepository`](gitrepositories.md) and [`HelmChart`](helmcharts.md) APIs. diff --git a/docs/spec/v1beta1/gitrepositories.md b/docs/spec/v1beta1/gitrepositories.md new file mode 100644 index 00000000..f0e29630 --- /dev/null +++ b/docs/spec/v1beta1/gitrepositories.md @@ -0,0 +1,394 @@ +# Git Repositories + +The `GitRepository` API defines a source for artifacts coming from Git. The +resource exposes the latest synchronized state from Git as an artifact in a +[gzip compressed TAR archive](#artifact). + +## Specification + +Git repository: + +```go +// GitRepositorySpec defines the desired state of a Git repository. +type GitRepositorySpec struct { + // The repository URL, can be a HTTP or SSH address. + // +kubebuilder:validation:Pattern="^(http|https|ssh)://" + // +required + URL string `json:"url"` + + // The secret name containing the Git credentials. + // For HTTPS repositories the secret must contain username and password + // fields. + // For SSH repositories the secret must contain identity, identity.pub and + // known_hosts fields. + // +optional + SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` + + // The interval at which to check for repository updates. + // +required + Interval metav1.Duration `json:"interval"` + + // The timeout for remote git operations like cloning, default to 20s. + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // The git reference to checkout and monitor for changes, defaults to + // master branch. + // +optional + Reference *GitRepositoryRef `json:"ref,omitempty"` + + // Verify OpenPGP signature for the commit that HEAD points to. + // +optional + Verification *GitRepositoryVerification `json:"verify,omitempty"` + + // Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + // +optional + Ignore *string `json:"ignore,omitempty"` +} +``` + +Git repository reference: + +```go +// GitRepositoryRef defines the git ref used for pull and checkout operations. +type GitRepositoryRef struct { + // The git branch to checkout, defaults to master. + // +optional + Branch string `json:"branch,omitempty"` + + // The git tag to checkout, takes precedence over branch. + // +optional + Tag string `json:"tag,omitempty"` + + // The git tag semver expression, takes precedence over tag. + // +optional + SemVer string `json:"semver,omitempty"` + + // The git commit sha to checkout, if specified tag filters will be ignored. + // +optional + Commit string `json:"commit,omitempty"` +} +``` + +Git repository cryptographic provenance verification: + +```go +// GitRepositoryVerification defines the OpenPGP signature verification process. +type GitRepositoryVerification struct { + // Mode describes what git object should be verified, currently ('head'). + // +kubebuilder:validation:Enum=head + Mode string `json:"mode"` + + // The secret name containing the public keys of all trusted git authors. + SecretRef corev1.LocalObjectReference `json:"secretRef"` +} +``` + +### Status + +```go +// GitRepositoryStatus defines the observed state of the GitRepository. +type GitRepositoryStatus struct { + // +optional + Conditions []meta.Condition `json:"conditions,omitempty"` + + // URL is the download link for the artifact output of the last repository + // sync. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful repository sync. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` +} +``` + +### Condition reasons + +```go +const ( + // GitOperationSucceedReason represents the fact that the git + // clone, pull and checkout operations succeeded. + GitOperationSucceedReason string = "GitOperationSucceed" + + // GitOperationFailedReason represents the fact that the git + // clone, pull or checkout operations failed. + GitOperationFailedReason string = "GitOperationFailed" +) +``` + +## Artifact + +The `GitRepository` API defines a source for artifacts coming from Git. The +resource exposes the latest synchronized state from Git as an artifact in a +gzip compressed TAR archive (`.tar.gz`). + +### Excluding files + +Git files (`.git/`, `.gitignore`, `.gitmodules`, and `.gitattributes`) are +excluded from the archive by default, as well as some extensions (`.jpg, .jpeg, +.gif, .png, .wmv, .flv, .tar.gz, .zip`) + +Excluding additional files from the archive is possible by adding a +`.sourceignore` file in the root of the repository. The `.sourceignore` file +follows [the `.gitignore` pattern +format](https://git-scm.com/docs/gitignore#_pattern_format), pattern +entries may overrule default exclusions. + +Another option is to use the `spec.ignore` field, for example: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 5m + url: https://github.com/stefanprodan/podinfo + ignore: | + # exclude all + /* + # include deploy dir + !/deploy + # exclude file extensions from deploy dir + /deploy/**/*.md + /deploy/**/*.txt +``` + +When specified, `spec.ignore` overrides the default exclusion list. + +## Spec examples + +### Checkout strategies + +Pull the master branch of a public repository every minute: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo +``` + +Pull a specific branch: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo + ref: + branch: v3.x +``` + +Checkout a specific commit from a branch: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo + ref: + branch: master + commit: 363a6a8fe6a7f13e05d34c163b0ef02a777da20a +``` + +Pull a specific tag: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo + ref: + tag: 3.2.0 +``` + +Pull tag based on a [semver range](https://github.com/blang/semver#ranges): + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo + ref: + semver: ">=3.1.0-rc.1 <3.2.0" +``` + +### HTTPS authentication + +HTTPS authentication requires a Kubernetes secret with `username` and `password` fields: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + url: https://github.com/stefanprodan/podinfo + secretRef: + name: https-credentials +--- +apiVersion: v1 +kind: Secret +metadata: + name: https-credentials + namespace: default +type: Opaque +data: + username: + password: +``` + +> **Note:** that self-signed certificates are not supported. + +### SSH authentication + +SSH authentication requires a Kubernetes secret with `identity` and `known_hosts` fields: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + url: ssh://git@github.com/stefanprodan/podinfo + secretRef: + name: ssh-credentials +--- +apiVersion: v1 +kind: Secret +metadata: + name: ssh-credentials + namespace: default +type: Opaque +data: + identity: + identity.pub: + known_hosts: +``` + +> **Note:** that the SSH address does not support SCP syntax. The URL format is +> `ssh://user@host:port/org/repository`. + +Example of generating the SSH credentials secret: + +```bash +ssh-keygen -q -N "" -f ./identity +ssh-keyscan github.com > ./known_hosts + +kubectl create secret generic ssh-credentials \ + --from-file=./identity \ + --from-file=./identity.pub \ + --from-file=./known_hosts +``` + +### GPG signature verification + +Verify the OpenPGP signature for the commit that master branch HEAD points to: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 1m + url: https://github.com/stefanprodan/podinfo + ref: + branch: master + verify: + mode: head + secretRef: + name: pgp-public-keys +--- +apiVersion: v1 +kind: Secret +metadata: + name: pgp-public-keys + namespace: default +type: Opaque +data: + author1.asc: + author2.asc: +``` + +Example of generating the PGP public keys secret: + +```bash +gpg --export --armor 3CB12BA185C47B67 > author1.asc +gpg --export --armor 6A7436E8790F8689 > author2.asc + +kubectl create secret generic pgp-public-keys \ + --from-file=author1.asc \ + --from-file=author2.asc +``` + +## Status examples + +Successful sync: + +```yaml +status: + artifact: + lastUpdateTime: "2020-04-07T06:59:23Z" + path: /data/gitrepository/default/podinfo/363a6a8fe6a7f13e05d34c163b0ef02a777da20a.tar.gz + revision: master/363a6a8fe6a7f13e05d34c163b0ef02a777da20a + url: http:///gitrepository/default/podinfo/363a6a8fe6a7f13e05d34c163b0ef02a777da20a.tar.gz + conditions: + - lastTransitionTime: "2020-04-07T06:59:23Z" + message: 'Git repoistory artifacts are available at: + /data/gitrepository/default/podinfo/363a6a8fe6a7f13e05d34c163b0ef02a777da20a.tar.gz' + reason: GitOperationSucceed + status: "True" + type: Ready + url: http:///gitrepository/default/podinfo/latest.tar.gz +``` + +Failed authentication: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-04-06T06:48:59Z" + message: 'git clone error ssh: handshake failed: ssh: unable to authenticate, + attempted methods [none publickey], no supported methods remain' + reason: AuthenticationFailed + status: "False" + type: Ready +``` + +Failed PGP signature verification: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-04-06T06:48:59Z" + message: 'PGP signature of {Stefan Prodan 2020-04-04 13:36:58 +0300 +0300} can not be verified' + reason: VerificationFailed + status: "False" + type: Ready +``` + +Wait for ready condition: + +```bash +kubectl wait gitrepository/podinfo --for=condition=ready --timeout=1m +``` diff --git a/docs/spec/v1beta1/helmcharts.md b/docs/spec/v1beta1/helmcharts.md new file mode 100644 index 00000000..29c29046 --- /dev/null +++ b/docs/spec/v1beta1/helmcharts.md @@ -0,0 +1,197 @@ +# Helm Charts + +The `HelmChart` API defines a source for Helm chart artifacts coming +from [`HelmRepository` sources](helmrepositories.md). The resource +exposes the latest pulled or packaged chart as an artifact. + +## Specification + +Helm chart: + +```go +// HelmChartSpec defines the desired state of a Helm chart. +type HelmChartSpec struct { + // The name or path the Helm chart is available at in the SourceRef. + // +required + Chart string `json:"chart"` + + // The chart version semver expression, ignored for charts from GitRepository + // and Bucket sources. Defaults to latest when omitted. + // +optional + Version string `json:"version,omitempty"` + + // The reference to the Source the chart is available at. + // +required + SourceRef LocalHelmChartSourceReference `json:"sourceRef"` + + // The interval at which to check the Source for updates. + // +required + Interval metav1.Duration `json:"interval"` + + // Alternative values file to use as the default chart values, expected to be a + // relative path in the SourceRef. Ignored when omitted. + // +optional + ValuesFile string `json:"valuesFile,omitempty"` +} +``` + +### Reference types + +```go +// LocalHelmChartSourceReference contains enough information to let you locate +// the typed referenced object at namespace level. +type LocalHelmChartSourceReference struct { + // APIVersion of the referent. + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + // 'Bucket'). + // +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket + // +required + Kind string `json:"kind"` + + // Name of the referent. + // +required + Name string `json:"name"` +} +``` + +### Status + +```go +// HelmChartStatus defines the observed state of the HelmChart. +type HelmChartStatus struct { + // +optional + Conditions []meta.Condition `json:"conditions,omitempty"` + + // URL is the download link for the last chart fetched. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful chart sync. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` +} +``` + +### Condition reasons + +```go +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" + + // ChartPackageFailedReason represent the fact that the package of the Helm + // chart failed. + ChartPackageFailedReason string = "ChartPackageFailed" + + // ChartPackageSucceededReason represents the fact that the package of the Helm + // chart succeeded. + ChartPackageSucceededReason string = "ChartPackageSucceeded" +) +``` + +## Spec examples + +Pull a specific chart version every five minutes: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmChart +metadata: + name: redis +spec: + chart: redis + version: 10.5.7 + sourceRef: + name: stable + kind: HelmRepository + interval: 5m +``` + +Pull the latest chart version that matches the semver range every ten minutes: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmChart +metadata: + name: redis +spec: + chart: redis + version: 10.5.x + sourceRef: + name: stable + kind: HelmRepository + interval: 10m +``` + +Check a Git repository every ten minutes for a new `version` in the +`Chart.yaml`, and package a new chart if the revision differs: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmChart +metadata: + name: podinfo +spec: + chart: ./charts/podinfo + sourceRef: + name: podinfo + kind: GitRepository + interval: 10m +``` + +Check a S3 compatible bucket every ten minutes for a new `version` in the +`Chart.yaml`, and package a new chart if the revision differs: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmChart +metadata: + name: podinfo +spec: + chart: ./podinfo + sourceRef: + name: charts + kind: Bucket + interval: 10m +``` + +## Status examples + +Successful chart pull: + +```yaml +status: + url: http:///helmchart/default/redis/redis-10.5.7.tgz + conditions: + - lastTransitionTime: "2020-04-10T09:34:45Z" + message: Helm chart is available at /data/helmchart/default/redis/redis-10.5.7.tgz + reason: ChartPullSucceeded + status: "True" + type: Ready +``` + +Failed chart pull: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-04-10T09:34:45Z" + message: 'invalid chart URL format' + reason: ChartPullFailed + status: "False" + type: Ready +``` + +Wait for ready condition: + +```bash +kubectl wait helmchart/redis --for=condition=ready --timeout=1m +``` diff --git a/docs/spec/v1beta1/helmrepositories.md b/docs/spec/v1beta1/helmrepositories.md new file mode 100644 index 00000000..9431ef05 --- /dev/null +++ b/docs/spec/v1beta1/helmrepositories.md @@ -0,0 +1,153 @@ +# Helm Repositories + +The `HelmRepository` API defines a source for Helm repositories. +The resource exposes the latest synchronized repository index as +an artifact. + +## Specification + +Helm repository: + +```go +// HelmRepositorySpec defines the reference to a Helm repository. +type HelmRepositorySpec struct { + // The Helm repository URL, a valid URL contains at least a protocol and host. + // +required + URL string `json:"url"` + + // The name of the secret containing authentication credentials for the Helm + // repository. + // For HTTP/S basic auth the secret must contain username and + // password fields. + // For TLS the secret must contain caFile, keyFile and caCert + // fields. + // +optional + SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` + + // The interval at which to check the upstream for updates. + // +required + Interval metav1.Duration `json:"interval"` + + // The timeout of index downloading, defaults to 60s. + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` +} +``` + +### Status + +```go +// HelmRepositoryStatus defines the observed state of the HelmRepository. +type HelmRepositoryStatus struct { + // +optional + Conditions []meta.Condition `json:"conditions,omitempty"` + + // URL is the download link for the last index fetched. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful repository sync. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` +} +``` + +### Condition reasons + +```go +const ( + // IndexationFailedReason represents the fact that the indexation of the given + // Helm repository failed. + IndexationFailedReason string = "IndexationFailed" + + // IndexationSucceededReason represents the fact that the indexation of the + // given Helm repository succeeded. + IndexationSucceededReason string = "IndexationSucceed" +) +``` + +## Spec examples + +Pull the index of a public Helm repository every ten minutes: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: stable +spec: + url: https://kubernetes-charts.storage.googleapis.com/ + interval: 10m +``` + +Pull the index of a private Helm repository every minute: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: private +spec: + url: https://charts.example.com + secretRef: + name: https-credentials + interval: 1m +--- +apiVersion: v1 +kind: Secret +metadata: + name: https-credentials + namespace: default +type: Opaque +data: + username: + password: + certFile: + keyFile: + caFile: +``` + +## Status examples + +Successful indexation: + +```yaml +status: + url: http:///helmrepository/default/stable/index.yaml + conditions: + - lastTransitionTime: "2020-04-10T09:34:45Z" + message: Helm repository index is available at /data/helmrepository/default/stable/index-21c195d78e699e4b656e2885887d019627838993.yaml + reason: IndexationSucceeded + status: "True" + type: Ready +``` + +Failed indexation: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-04-10T09:27:21Z" + message: 'failed to fetch https://invalid.example.com/index.yaml : 404 Not Found' + reason: IndexationFailed + status: "False" + type: Ready +``` + +Invalid repository URL: + +```yaml +status: + conditions: + - lastTransitionTime: "2020-04-10T09:27:21Z" + message: scheme "invalid" not supported + reason: URLInvalid + status: "False" + type: Ready +``` + +Wait for ready condition: + +```bash +kubectl wait helmrepository/stable --for=condition=ready --timeout=1m +``` diff --git a/go.mod b/go.mod index 0c99547e..e86ab290 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fluxcd/source-controller -go 1.14 +go 1.15 replace github.com/fluxcd/source-controller/api => ./api diff --git a/main.go b/main.go index 137b6c35..9435aef4 100644 --- a/main.go +++ b/main.go @@ -36,7 +36,7 @@ import ( "github.com/fluxcd/pkg/recorder" "github.com/fluxcd/pkg/runtime/logger" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/source-controller/controllers" // +kubebuilder:scaffold:imports ) @@ -239,11 +239,11 @@ func mustInitStorage(path string, storageAddr string, l logr.Logger) *controller return storage } -func envOrDefault(envName, dflt string) string { +func envOrDefault(envName, defaultValue string) string { ret := os.Getenv(envName) if ret != "" { return ret } - return dflt + return defaultValue } diff --git a/pkg/git/checkout.go b/pkg/git/checkout.go index e640dab7..1f504978 100644 --- a/pkg/git/checkout.go +++ b/pkg/git/checkout.go @@ -26,7 +26,7 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/transport" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) const (