Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ var (

// AnnotationHook contains the hook type of a resource
AnnotationHook = MetadataPrefix + "/hook"
// AnnotationHookDeletePolicy is the policy of deleting a hook
AnnotationHookDeletePolicy = MetadataPrefix + "/hook-delete-policy"

// LabelKeyApplicationControllerInstanceID is the label which allows to separate application among multiple running application controllers.
LabelKeyApplicationControllerInstanceID = application.ApplicationFullName + "/controller-instanceid"
Expand Down
39 changes: 34 additions & 5 deletions controller/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ func (sc *syncContext) runHooks(hooks []*unstructured.Unstructured, hookType app
return false
}
if !successful {
sc.setOperationPhase(appv1.OperationFailed, fmt.Sprintf("%s hook failed", appv1.HookTypePreSync))
sc.setOperationPhase(appv1.OperationFailed, fmt.Sprintf("%s hook failed", hookType))
return false
}
return true
Expand All @@ -519,7 +519,7 @@ func (sc *syncContext) runHook(hook *unstructured.Unstructured, hookType appv1.H
// or formulated at the time of the operation (metadata.generateName). If user specifies
// metadata.generateName, then we will generate a formulated metadata.name before submission.
if hook.GetName() == "" {
postfix := strings.ToLower(fmt.Sprintf("%s-%s-%d", hookType, sc.syncRes.Revision[0:7], sc.opState.StartedAt.UTC().Unix()))
postfix := strings.ToLower(fmt.Sprintf("%s-%s-%d", sc.syncRes.Revision[0:7], hookType, sc.opState.StartedAt.UTC().Unix()))
generatedName := hook.GetGenerateName()
hook = hook.DeepCopy()
hook.SetName(fmt.Sprintf("%s%s", generatedName, postfix))
Expand Down Expand Up @@ -568,9 +568,37 @@ func (sc *syncContext) runHook(hook *unstructured.Unstructured, hookType appv1.H
liveObj = existing
}
hookStatus := newHookStatus(liveObj, hookType)
if hookStatus.Status.Completed() {
if enforceDeletePolicy(hook, hookStatus.Status) {
err = sc.deleteHook(hook.GetName(), hook.GetKind(), hook.GetAPIVersion())
if err != nil {
hookStatus.Status = appv1.OperationFailed
hookStatus.Message = fmt.Sprintf("failed to delete %s hook: %v", hookStatus.Status, err)
}
}
}
return sc.updateHookStatus(hookStatus), nil
}

// enforceDeletePolicy examines the hook deletion policy of a object and deletes it based on the status
func enforceDeletePolicy(hook *unstructured.Unstructured, phase appv1.OperationPhase) bool {
annotations := hook.GetAnnotations()
if annotations == nil {
return false
}
deletePolicies := strings.Split(annotations[common.AnnotationHookDeletePolicy], ",")
for _, dp := range deletePolicies {
policy := appv1.HookDeletePolicy(strings.TrimSpace(dp))
if policy == appv1.HookDeletePolicyHookSucceeded && phase == appv1.OperationSucceeded {
return true
}
if policy == appv1.HookDeletePolicyHookFailed && phase == appv1.OperationFailed {
return true
}
}
return false
}

// isHookType tells whether or not the supplied object is a hook of the specified type
func isHookType(hook *unstructured.Unstructured, hookType appv1.HookType) bool {
annotations := hook.GetAnnotations()
Expand Down Expand Up @@ -678,6 +706,7 @@ func newHookStatus(hook *unstructured.Unstructured, hookType appv1.HookType) app
switch condition.Type {
case batch.JobFailed:
failed = true
complete = true
failMsg = condition.Message
case batch.JobComplete:
complete = true
Expand Down Expand Up @@ -721,7 +750,7 @@ func newHookStatus(hook *unstructured.Unstructured, hookType appv1.HookType) app
return hookStatus
}

// updateHookStatus updates the status of a hook. Returns whether or not the hook was changed or not
// updateHookStatus updates the status of a hook. Returns true if the hook was modified
func (sc *syncContext) updateHookStatus(hookStatus appv1.HookStatus) bool {
sc.lock.Lock()
defer sc.lock.Unlock()
Expand Down Expand Up @@ -783,9 +812,9 @@ func (sc *syncContext) terminate() {
}
}
if terminateSuccessful {
sc.setOperationPhase(appv1.OperationFailed, "Application terminated")
sc.setOperationPhase(appv1.OperationFailed, "Operation terminated")
} else {
sc.setOperationPhase(appv1.OperationError, "Termination had errors")
sc.setOperationPhase(appv1.OperationError, "Operation termination had errors")
}
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/application/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ const (
//HookTypeSyncFail HookType = "SyncFail"
)

type HookDeletePolicy string

const (
HookDeletePolicyHookSucceeded HookDeletePolicy = "HookSucceeded"
HookDeletePolicyHookFailed HookDeletePolicy = "HookFailed"
)

// HookStatus contains status about a hook invocation
type HookStatus struct {
// Name is the resource name
Expand Down
2 changes: 1 addition & 1 deletion reposerver/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani

params, err := ksApp.ListEnvParams(q.Environment)
if err != nil {
return nil, err
return nil, fmt.Errorf("Failed to list ksonnet app params: %v", err)
}

if q.ComponentParameterOverrides != nil {
Expand Down
14 changes: 8 additions & 6 deletions util/ksonnet/ksonnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import (
"strconv"
"strings"

"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/diff"
"github.com/ghodss/yaml"
"github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/component"
Expand All @@ -22,6 +19,10 @@ import (
corev1 "k8s.io/api/core/v1"
v1ExtBeta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/diff"
)

var (
Expand Down Expand Up @@ -127,7 +128,7 @@ func (k *ksonnetApp) Spec() *app.Spec {
func (k *ksonnetApp) Show(environment string) ([]*unstructured.Unstructured, error) {
out, err := k.ksCmd("show", environment)
if err != nil {
return nil, err
return nil, fmt.Errorf("`ks show` failed: %v", err)
}
parts := diffSeparator.Split(out, -1)
objs := make([]*unstructured.Unstructured, 0)
Expand All @@ -150,8 +151,9 @@ func (k *ksonnetApp) Show(environment string) ([]*unstructured.Unstructured, err
return objs, nil
}

// remarshal checks resource kind and version and re-marshal using corresponding struct custom marshaller. This ensures that expected resource state is formatter same as actual
// resource state in kubernetes and allows to find differences between actual and target states more accurate.
// remarshal checks resource kind and version and re-marshal using corresponding struct custom marshaller.
// This ensures that expected resource state is formatter same as actualresource state in kubernetes
// and allows to find differences between actual and target states more accurately.
func remarshal(obj *unstructured.Unstructured) error {
var newObj interface{}
switch obj.GetAPIVersion() + ":" + obj.GetKind() {
Expand Down