argo-cd
158 строк · 4.7 Кб
1package controller
2
3import (
4"context"
5
6"github.com/argoproj/gitops-engine/pkg/health"
7"github.com/argoproj/gitops-engine/pkg/sync/common"
8"github.com/argoproj/gitops-engine/pkg/sync/hook"
9"github.com/argoproj/gitops-engine/pkg/utils/kube"
10log "github.com/sirupsen/logrus"
11v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
13"k8s.io/client-go/rest"
14
15"github.com/argoproj/argo-cd/v2/util/lua"
16
17"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
18)
19
20var (
21postDeleteHook = "PostDelete"
22postDeleteHooks = map[string]string{
23"argocd.argoproj.io/hook": postDeleteHook,
24"helm.sh/hook": "post-delete",
25}
26)
27
28func isHook(obj *unstructured.Unstructured) bool {
29return hook.IsHook(obj) || isPostDeleteHook(obj)
30}
31
32func isPostDeleteHook(obj *unstructured.Unstructured) bool {
33if obj == nil || obj.GetAnnotations() == nil {
34return false
35}
36for k, v := range postDeleteHooks {
37if val, ok := obj.GetAnnotations()[k]; ok && val == v {
38return true
39}
40}
41return false
42}
43
44func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Application, proj *v1alpha1.AppProject, liveObjs map[kube.ResourceKey]*unstructured.Unstructured, config *rest.Config, logCtx *log.Entry) (bool, error) {
45appLabelKey, err := ctrl.settingsMgr.GetAppInstanceLabelKey()
46if err != nil {
47return false, err
48}
49var revisions []string
50for _, src := range app.Spec.GetSources() {
51revisions = append(revisions, src.TargetRevision)
52}
53
54targets, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj)
55if err != nil {
56return false, err
57}
58runningHooks := map[kube.ResourceKey]*unstructured.Unstructured{}
59for key, obj := range liveObjs {
60if isPostDeleteHook(obj) {
61runningHooks[key] = obj
62}
63}
64
65expectedHook := map[kube.ResourceKey]*unstructured.Unstructured{}
66for _, obj := range targets {
67if obj.GetNamespace() == "" {
68obj.SetNamespace(app.Spec.Destination.Namespace)
69}
70if !isPostDeleteHook(obj) {
71continue
72}
73if runningHook := runningHooks[kube.GetResourceKey(obj)]; runningHook == nil {
74expectedHook[kube.GetResourceKey(obj)] = obj
75}
76}
77createdCnt := 0
78for _, obj := range expectedHook {
79_, err = ctrl.kubectl.CreateResource(context.Background(), config, obj.GroupVersionKind(), obj.GetName(), obj.GetNamespace(), obj, v1.CreateOptions{})
80if err != nil {
81return false, err
82}
83createdCnt++
84}
85if createdCnt > 0 {
86logCtx.Infof("Created %d post-delete hooks", createdCnt)
87return false, nil
88}
89resourceOverrides, err := ctrl.settingsMgr.GetResourceOverrides()
90if err != nil {
91return false, err
92}
93healthOverrides := lua.ResourceHealthOverrides(resourceOverrides)
94
95progressingHooksCnt := 0
96for _, obj := range runningHooks {
97hookHealth, err := health.GetResourceHealth(obj, healthOverrides)
98if err != nil {
99return false, err
100}
101if hookHealth.Status == health.HealthStatusProgressing {
102progressingHooksCnt++
103}
104}
105if progressingHooksCnt > 0 {
106logCtx.Infof("Waiting for %d post-delete hooks to complete", progressingHooksCnt)
107return false, nil
108}
109
110return true, nil
111}
112
113func (ctrl *ApplicationController) cleanupPostDeleteHooks(liveObjs map[kube.ResourceKey]*unstructured.Unstructured, config *rest.Config, logCtx *log.Entry) (bool, error) {
114resourceOverrides, err := ctrl.settingsMgr.GetResourceOverrides()
115if err != nil {
116return false, err
117}
118healthOverrides := lua.ResourceHealthOverrides(resourceOverrides)
119
120pendingDeletionCount := 0
121aggregatedHealth := health.HealthStatusHealthy
122var hooks []*unstructured.Unstructured
123for _, obj := range liveObjs {
124if !isPostDeleteHook(obj) {
125continue
126}
127hookHealth, err := health.GetResourceHealth(obj, healthOverrides)
128if err != nil {
129return false, err
130}
131if health.IsWorse(aggregatedHealth, hookHealth.Status) {
132aggregatedHealth = hookHealth.Status
133}
134hooks = append(hooks, obj)
135}
136
137for _, obj := range hooks {
138for _, policy := range hook.DeletePolicies(obj) {
139if policy == common.HookDeletePolicyHookFailed && aggregatedHealth == health.HealthStatusDegraded || policy == common.HookDeletePolicyHookSucceeded && aggregatedHealth == health.HealthStatusHealthy {
140pendingDeletionCount++
141if obj.GetDeletionTimestamp() != nil {
142continue
143}
144logCtx.Infof("Deleting post-delete hook %s/%s", obj.GetNamespace(), obj.GetName())
145err = ctrl.kubectl.DeleteResource(context.Background(), config, obj.GroupVersionKind(), obj.GetName(), obj.GetNamespace(), v1.DeleteOptions{})
146if err != nil {
147return false, err
148}
149}
150}
151
152}
153if pendingDeletionCount > 0 {
154logCtx.Infof("Waiting for %d post-delete hooks to be deleted", pendingDeletionCount)
155return false, nil
156}
157return true, nil
158}
159