Skip to content

Commit

Permalink
Add ready condition helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanprodan committed Apr 10, 2020
1 parent 131b9b8 commit e7ff6b2
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 145 deletions.
3 changes: 3 additions & 0 deletions api/v1alpha1/condition_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ const (

// InitializingReason represents the fact that a given source is being initialize.
InitializingReason string = "Initializing"

// StorageOperationFailedReason signals a failure caused by a storage operation.
StorageOperationFailedReason string = "StorageOperationFailed"
)
15 changes: 10 additions & 5 deletions api/v1alpha1/gitrepository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (

// GitRepositorySpec defines the desired state of GitRepository
type GitRepositorySpec struct {
// +kubebuilder:validation:Pattern="^(http|https|ssh)://"

// The repository URL, can be a HTTP or SSH address.
Url string `json:"url"`
// +kubebuilder:validation:Pattern="^(http|https|ssh)://"
// +required
URL string `json:"url"`

// The interval at which to check for repository updates.
// +required
Interval metav1.Duration `json:"interval"`

// The git branch to checkout, defaults to ('master').
Expand Down Expand Up @@ -74,9 +75,8 @@ type GitRepository struct {
Status GitRepositoryStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// GitRepositoryList contains a list of GitRepository
// +kubebuilder:object:root=true
type GitRepositoryList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Expand All @@ -86,3 +86,8 @@ type GitRepositoryList struct {
func init() {
SchemeBuilder.Register(&GitRepository{}, &GitRepositoryList{})
}

const (
GitOperationSucceedReason string = "GitOperationSucceed"
GitOperationFailedReason string = "GitOperationFailed"
)
7 changes: 4 additions & 3 deletions api/v1alpha1/helmrepository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import (
type HelmRepositorySpec struct {
// The repository address
// +kubebuilder:validation:MinLength=4
// +required
URL string `json:"url"`

// The interval at which to check for repository updates
// +required
Interval metav1.Duration `json:"interval"`
}

Expand Down Expand Up @@ -61,9 +63,8 @@ type HelmRepository struct {
Status HelmRepositoryStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// HelmRepositoryList contains a list of HelmRepository
// +kubebuilder:object:root=true
type HelmRepositoryList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Expand All @@ -76,6 +77,6 @@ func init() {

const (
InvalidHelmRepositoryURLReason string = "InvalidHelmRepositoryURL"
IndexFetchFailedReason string = "IndexFetchFailedReason"
IndexFetchFailedReason string = "IndexFetchFailed"
IndexFetchSucceededReason string = "IndexFetchSucceed"
)
44 changes: 44 additions & 0 deletions controllers/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
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 (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
)

func ReadyCondition(reason, message string) sourcev1.SourceCondition {
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: reason,
Message: message,
}
}

func NotReadyCondition(reason, message string) sourcev1.SourceCondition {
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: reason,
Message: message,
}
}
108 changes: 31 additions & 77 deletions controllers/gitrepository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,56 +138,36 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
// create tmp dir
dir, err := ioutil.TempDir("", repository.Name)
if err != nil {
ex := fmt.Errorf("tmp dir error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "ExecFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("tmp dir error %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
}
defer os.RemoveAll(dir)

// clone to tmp
repo, err := git.PlainClone(dir, false, &git.CloneOptions{
URL: repository.Spec.Url,
URL: repository.Spec.URL,
Depth: 2,
ReferenceName: refName,
SingleBranch: true,
Tags: git.AllTags,
})
if err != nil {
ex := fmt.Errorf("git clone error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCloneFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("git clone error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}

// checkout tag based on semver expression
if repository.Spec.SemVer != "" {
rng, err := semver.ParseRange(repository.Spec.SemVer)
if err != nil {
ex := fmt.Errorf("semver parse range error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCloneFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("semver parse range error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}

repoTags, err := repo.Tags()
if err != nil {
ex := fmt.Errorf("git list tags error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCloneFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("git list tags error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}

tags := make(map[string]string)
Expand All @@ -214,48 +194,28 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc

w, err := repo.Worktree()
if err != nil {
ex := fmt.Errorf("git worktree error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCheckoutFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("git worktree error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}

err = w.Checkout(&git.CheckoutOptions{
Hash: plumbing.NewHash(commit),
})
if err != nil {
ex := fmt.Errorf("git checkout error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCheckoutFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("git checkout error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}
} else {
ex := fmt.Errorf("no match found for semver %s", repository.Spec.SemVer)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitCheckoutFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("no match found for semver %s", repository.Spec.SemVer)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}
}

// read commit hash
ref, err := repo.Head()
if err != nil {
ex := fmt.Errorf("git resolve HEAD error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "GitHeadFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("git resolve HEAD error %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
}

artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(),
Expand All @@ -264,33 +224,27 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
// create artifact dir
err = r.Storage.MkdirAll(artifact)
if err != nil {
ex := fmt.Errorf("mkdir dir error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "ExecFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("mkdir dir error %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
}

// acquire lock
unlock, err := r.Storage.Lock(artifact)
if err != nil {
err = fmt.Errorf("unable to acquire lock: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
}
defer unlock()

// archive artifact
err = r.Storage.Archive(artifact, dir, "")
if err != nil {
ex := fmt.Errorf("storage error %w", err)
return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionFalse,
Reason: "ExecFailed",
Message: ex.Error(),
}, "", ex
err = fmt.Errorf("storage error %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
}

return sourcev1.SourceCondition{
Type: sourcev1.ReadyCondition,
Status: corev1.ConditionTrue,
Reason: "GitCloneSucceed",
Message: fmt.Sprintf("Artifact is available at %s", artifact.Path),
}, artifact.URL, nil
message := fmt.Sprintf("Artifact is available at %s", artifact.Path)
return ReadyCondition(sourcev1.GitOperationSucceedReason, message), artifact.URL, nil
}

func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepository) (bool, sourcev1.GitRepositoryStatus) {
Expand Down
Loading

0 comments on commit e7ff6b2

Please sign in to comment.