diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index f9e19aec5ae3f..a6b40f06c5a6f 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -774,7 +774,7 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest for _, target := range targets { if q.AppLabelKey != "" && q.AppName != "" && !kube.IsCRD(target) { - err = resourceTracking.SetAppInstance(target, q.AppLabelKey, q.AppName, v1alpha1.TrackingMethod(q.TrackingMethod)) + err = resourceTracking.SetAppInstance(target, q.AppLabelKey, q.AppName, q.Namespace, v1alpha1.TrackingMethod(q.TrackingMethod)) if err != nil { return nil, err } diff --git a/test/e2e/deployment_test.go b/test/e2e/deployment_test.go index dee795f8facae..d8e6871712e21 100644 --- a/test/e2e/deployment_test.go +++ b/test/e2e/deployment_test.go @@ -57,7 +57,8 @@ func TestDeploymentWithAnnotationTrackingMode(t *testing.T) { out, err := RunCli("app", "manifests", app.Name) assert.NoError(t, err) assert.Contains(t, out, fmt.Sprintf(`annotations: - app.kubernetes.io/instance: %s`, Name())) + app.kubernetes.io/instance: %s;apps/Deployment/%s/nginx-deployment +`, Name(), DeploymentNamespace())) }) } @@ -80,7 +81,8 @@ func TestDeploymentWithLabelTrackingMode(t *testing.T) { assert.NoError(t, err) assert.Contains(t, out, fmt.Sprintf(`labels: app: nginx - app.kubernetes.io/instance: %s`, Name())) + app.kubernetes.io/instance: %s +`, Name())) }) } @@ -101,6 +103,7 @@ func TestDeploymentWithoutTrackingMode(t *testing.T) { assert.NoError(t, err) assert.Contains(t, out, fmt.Sprintf(`labels: app: nginx - app.kubernetes.io/instance: %s`, Name())) + app.kubernetes.io/instance: %s +`, Name())) }) } diff --git a/util/argo/resource_tracking.go b/util/argo/resource_tracking.go index 2c09560c78fe8..bf1bf374a11a9 100644 --- a/util/argo/resource_tracking.go +++ b/util/argo/resource_tracking.go @@ -1,6 +1,9 @@ package argo import ( + "fmt" + "strings" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/argoproj/argo-cd/v2/util/settings" @@ -16,10 +19,23 @@ const ( TrackingMethodAnnotationAndLabel v1alpha1.TrackingMethod = "annotation+label" ) +var WrongResourceTrackingFormat = fmt.Errorf("wrong resource tracking format, should be ;///") + // ResourceTracking defines methods which allow setup and retrieve tracking information to resource type ResourceTracking interface { GetAppName(un *unstructured.Unstructured, key string, trackingMethod v1alpha1.TrackingMethod) string - SetAppInstance(un *unstructured.Unstructured, key, val string, trackingMethod v1alpha1.TrackingMethod) error + SetAppInstance(un *unstructured.Unstructured, key, val, namespace string, trackingMethod v1alpha1.TrackingMethod) error + BuildAppInstanceValue(value AppInstanceValue) string + ParseAppInstanceValue(value string) (*AppInstanceValue, error) +} + +//AppInstanceValue store information about resource tracking info +type AppInstanceValue struct { + ApplicationName string + Group string + Kind string + Namespace string + Name string } type resourceTracking struct { @@ -44,20 +60,61 @@ func (rt *resourceTracking) GetAppName(un *unstructured.Unstructured, key string case TrackingMethodLabel: return argokube.GetAppInstanceLabel(un, key) case TrackingMethodAnnotation: - return argokube.GetAppInstanceAnnotation(un, key) + appInstanceAnnotation := argokube.GetAppInstanceAnnotation(un, key) + value, err := rt.ParseAppInstanceValue(appInstanceAnnotation) + if err != nil { + return "" + } + return value.ApplicationName default: return argokube.GetAppInstanceLabel(un, key) } } // SetAppInstance set label/annotation base on tracking method -func (rt *resourceTracking) SetAppInstance(un *unstructured.Unstructured, key, val string, trackingMethod v1alpha1.TrackingMethod) error { +func (rt *resourceTracking) SetAppInstance(un *unstructured.Unstructured, key, val, namespace string, trackingMethod v1alpha1.TrackingMethod) error { switch trackingMethod { case TrackingMethodLabel: return argokube.SetAppInstanceLabel(un, key, val) case TrackingMethodAnnotation: - return argokube.SetAppInstanceAnnotation(un, key, val) + ns := un.GetNamespace() + if ns == "" { + ns = namespace + } + gvk := un.GetObjectKind().GroupVersionKind() + appInstanceValue := AppInstanceValue{ + ApplicationName: val, + Group: gvk.Group, + Kind: gvk.Kind, + Namespace: ns, + Name: un.GetName(), + } + return argokube.SetAppInstanceAnnotation(un, key, rt.BuildAppInstanceValue(appInstanceValue)) default: return argokube.SetAppInstanceLabel(un, key, val) } } + +//BuildAppInstanceValue build resource tracking id in format ;/// +func (rt *resourceTracking) BuildAppInstanceValue(value AppInstanceValue) string { + return fmt.Sprintf("%s;%s/%s/%s/%s", value.ApplicationName, value.Group, value.Kind, value.Namespace, value.Name) +} + +//ParseAppInstanceValue parse resource tracking id from format ;/// to struct +func (rt *resourceTracking) ParseAppInstanceValue(value string) (*AppInstanceValue, error) { + var appInstanceValue AppInstanceValue + parts := strings.Split(value, ";") + appInstanceValue.ApplicationName = parts[0] + if len(parts) == 1 { + return nil, WrongResourceTrackingFormat + } + newParts := strings.Split(parts[1], "/") + if len(newParts) != 4 { + return nil, WrongResourceTrackingFormat + } + appInstanceValue.Group = newParts[0] + appInstanceValue.Kind = newParts[1] + appInstanceValue.Namespace = newParts[2] + appInstanceValue.Name = newParts[3] + return &appInstanceValue, nil +} diff --git a/util/argo/resource_tracking_test.go b/util/argo/resource_tracking_test.go index 354e87c186891..aeec61fe1911a 100644 --- a/util/argo/resource_tracking_test.go +++ b/util/argo/resource_tracking_test.go @@ -21,7 +21,7 @@ func TestSetAppInstanceLabel(t *testing.T) { resourceTracking := NewResourceTracking() - err = resourceTracking.SetAppInstance(&obj, common.LabelKeyAppInstance, "my-app", TrackingMethodLabel) + err = resourceTracking.SetAppInstance(&obj, common.LabelKeyAppInstance, "my-app", "", TrackingMethodLabel) assert.Nil(t, err) app := resourceTracking.GetAppName(&obj, common.LabelKeyAppInstance, TrackingMethodLabel) @@ -38,7 +38,7 @@ func TestSetAppInstanceAnnotation(t *testing.T) { resourceTracking := NewResourceTracking() - err = resourceTracking.SetAppInstance(&obj, common.LabelKeyAppInstance, "my-app", TrackingMethodAnnotation) + err = resourceTracking.SetAppInstance(&obj, common.LabelKeyAppInstance, "my-app", "", TrackingMethodAnnotation) assert.Nil(t, err) app := resourceTracking.GetAppName(&obj, common.LabelKeyAppInstance, TrackingMethodAnnotation) @@ -58,3 +58,26 @@ func TestSetAppInstanceAnnotationNotFound(t *testing.T) { app := resourceTracking.GetAppName(&obj, common.LabelKeyAppInstance, TrackingMethodAnnotation) assert.Equal(t, "", app) } + +func TestParseAppInstanceValue(t *testing.T) { + resourceTracking := NewResourceTracking() + appInstanceValue, err := resourceTracking.ParseAppInstanceValue("app;///") + assert.NoError(t, err) + assert.Equal(t, appInstanceValue.ApplicationName, "app") + assert.Equal(t, appInstanceValue.Group, "") + assert.Equal(t, appInstanceValue.Kind, "") + assert.Equal(t, appInstanceValue.Namespace, "") + assert.Equal(t, appInstanceValue.Name, "") +} + +func TestParseAppInstanceValueWrongFormat1(t *testing.T) { + resourceTracking := NewResourceTracking() + _, err := resourceTracking.ParseAppInstanceValue("app") + assert.Error(t, err, WrongResourceTrackingFormat) +} + +func TestParseAppInstanceValueWrongFormat2(t *testing.T) { + resourceTracking := NewResourceTracking() + _, err := resourceTracking.ParseAppInstanceValue("app;group/kind/ns") + assert.Error(t, err, WrongResourceTrackingFormat) +}