Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:CR-22172-parent-app-ns #274

Merged
merged 1 commit into from
Jan 16, 2024
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
3 changes: 3 additions & 0 deletions changelog/CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Bugfixes
1. [event-reporter]: apps not in controller ns not reported.
2. [event-reporter]: source object payload doesn't include correct gitSourceNamespace if resource ns != application ns
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&codefreshUrl, "codefresh-url", env.StringFromEnv("CODEFRESH_URL", "https://g.codefresh.io"), "Codefresh API url")
command.Flags().StringVar(&codefreshToken, "codefresh-token", env.StringFromEnv("CODEFRESH_TOKEN", ""), "Codefresh token")
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvEventReporterShardingAlgorithm, common.DefaultEventReporterShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy] ")
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
command.Flags().BoolVar(&useGrpc, "grpc", env.ParseBoolFromEnv("USE_GRPC", true), "Use grpc for interact with argocd server")
cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) {
redisClient = client
Expand Down
61 changes: 49 additions & 12 deletions event_reporter/reporter/application_event_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ var (
resourceEventCacheExpiration = time.Minute * time.Duration(env.ParseNumFromEnv(argocommon.EnvResourceEventCacheDuration, 20, 0, math.MaxInt32))
)

type AppIdentity struct {
name string
namespace string
}

type applicationEventReporter struct {
cache *servercache.Cache
codefreshClient codefresh.CodefreshClient
Expand Down Expand Up @@ -93,15 +98,43 @@ func (s *applicationEventReporter) shouldSendResourceEvent(a *appv1.Application,
return true
}

func getParentAppName(a *appv1.Application, appInstanceLabelKey string, trackingMethod appv1.TrackingMethod) string {
const appInstanceNameDelimeter = "_"

// logic connected to /argo-cd/pkg/apis/application/v1alpha1/types.go - InstanceName
func instanceNameIncludesNs(instanceName string) bool {
return strings.Contains(instanceName, appInstanceNameDelimeter)
}

// logic connected to /argo-cd/pkg/apis/application/v1alpha1/types.go - InstanceName
func parseInstanceName(appNameString string) AppIdentity {
parts := strings.Split(appNameString, appInstanceNameDelimeter)
namespace := parts[0]
app := parts[1]

return AppIdentity{
name: app,
namespace: namespace,
}
}

func getParentAppIdentity(a *appv1.Application, appInstanceLabelKey string, trackingMethod appv1.TrackingMethod) AppIdentity {
resourceTracking := argo.NewResourceTracking()
unApp := kube.MustToUnstructured(&a)

return resourceTracking.GetAppName(unApp, appInstanceLabelKey, trackingMethod)
instanceName := resourceTracking.GetAppName(unApp, appInstanceLabelKey, trackingMethod)

if instanceNameIncludesNs(instanceName) {
return parseInstanceName(instanceName)
} else {
return AppIdentity{
name: instanceName,
namespace: "",
}
}
}

func isChildApp(parentAppName string) bool {
return parentAppName != ""
func isChildApp(parentApp AppIdentity) bool {
return parentApp.name != ""
}

func getAppAsResource(a *appv1.Application) *appv1.ResourceStatus {
Expand All @@ -120,8 +153,9 @@ func getAppAsResource(a *appv1.Application) *appv1.ResourceStatus {
func (r *applicationEventReporter) getDesiredManifests(ctx context.Context, a *appv1.Application, logCtx *log.Entry) (*apiclient.ManifestResponse, error, bool) {
// get the desired state manifests of the application
desiredManifests, err := r.applicationServiceClient.GetManifests(ctx, &application.ApplicationManifestQuery{
Name: &a.Name,
Revision: &a.Status.Sync.Revision,
Name: &a.Name,
AppNamespace: &a.Namespace,
Revision: &a.Status.Sync.Revision,
})
if err != nil {
notManifestGenerationError := !strings.Contains(err.Error(), "Manifest generation error")
Expand Down Expand Up @@ -164,7 +198,7 @@ func (s *applicationEventReporter) StreamApplicationEvents(
appTree, err := s.applicationServiceClient.ResourceTree(ctx, &application.ResourcesQuery{
ApplicationName: &a.Name,
Project: &a.Spec.Project,
Namespace: &a.Namespace,
AppNamespace: &a.Namespace,
})
if err != nil {
if strings.Contains(err.Error(), "context deadline exceeded") {
Expand All @@ -185,12 +219,13 @@ func (s *applicationEventReporter) StreamApplicationEvents(

logCtx.Info("getting parent application name")

parentAppName := getParentAppName(a, appInstanceLabelKey, trackingMethod)
parentAppIdentity := getParentAppIdentity(a, appInstanceLabelKey, trackingMethod)

if isChildApp(parentAppName) {
if isChildApp(parentAppIdentity) {
logCtx.Info("processing as child application")
parentApplicationEntity, err := s.applicationServiceClient.Get(ctx, &application.ApplicationQuery{
Name: &parentAppName,
Name: &parentAppIdentity.name,
AppNamespace: &parentAppIdentity.namespace,
})
if err != nil {
return fmt.Errorf("failed to get parent application entity: %w", err)
Expand Down Expand Up @@ -330,6 +365,7 @@ func (s *applicationEventReporter) processResource(
// get resource actual state
actualState, err := s.applicationServiceClient.GetResource(ctx, &application.ApplicationResourceRequest{
Name: &parentApplication.Name,
AppNamespace: &parentApplication.Namespace,
Namespace: &rs.Namespace,
ResourceName: &rs.Name,
Version: &rs.Version,
Expand Down Expand Up @@ -500,8 +536,9 @@ func getOperationRevision(a *appv1.Application) string {

func (s *applicationEventReporter) getApplicationRevisionDetails(ctx context.Context, a *appv1.Application, revision string) (*appv1.RevisionMetadata, error) {
return s.applicationServiceClient.RevisionMetadata(ctx, &application.RevisionMetadataQuery{
Name: &a.Name,
Revision: &revision,
Name: &a.Name,
AppNamespace: &a.Namespace,
Revision: &revision,
})
}

Expand Down
64 changes: 64 additions & 0 deletions event_reporter/reporter/application_event_reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,67 @@ func TestSetHealthStatusIfMissing(t *testing.T) {
setHealthStatusIfMissing(&resource)
assert.Equal(t, resource.Health.Status, health.HealthStatusHealthy)
}

func TestGetParentAppIdentityWithinNonControllerNs(t *testing.T) {
resourceTracking := argo.NewResourceTracking()
annotations := make(map[string]string)
constrollerNs := "runtime"
expectedName := "guestbook"
expectedNamespace := "test-apps"

guestbookApp := appsv1.Application{
TypeMeta: metav1.TypeMeta{
Kind: "Application",
APIVersion: "argoproj.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: expectedName,
Namespace: expectedNamespace,
},
}
annotations[common.AnnotationKeyAppInstance] = resourceTracking.BuildAppInstanceValue(argo.AppInstanceValue{
Name: "test",
ApplicationName: guestbookApp.InstanceName(constrollerNs),
Group: "group",
Kind: "Rollout",
Namespace: "test-resources",
})
guestbookApp.Annotations = annotations

res := getParentAppIdentity(&guestbookApp, common.LabelKeyAppInstance, "annotation")

assert.Equal(t, expectedName, res.name)
assert.Equal(t, expectedNamespace, res.namespace)
}

func TestGetParentAppIdentityWithinControllerNs(t *testing.T) {
resourceTracking := argo.NewResourceTracking()
annotations := make(map[string]string)
constrollerNs := "runtime"
expectedName := "guestbook"
expectedNamespace := ""

guestbookApp := appsv1.Application{
TypeMeta: metav1.TypeMeta{
Kind: "Application",
APIVersion: "argoproj.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: expectedName,
Namespace: constrollerNs,
},
}
annotations[common.AnnotationKeyAppInstance] = resourceTracking.BuildAppInstanceValue(argo.AppInstanceValue{
Name: "test",
ApplicationName: guestbookApp.InstanceName(constrollerNs),
Group: "group",
Kind: "Rollout",
Namespace: "test-resources",
})
guestbookApp.Annotations = annotations

res := getParentAppIdentity(&guestbookApp, common.LabelKeyAppInstance, "annotation")

assert.Equal(t, expectedName, res.name)
assert.Equal(t, expectedNamespace, res.namespace)
}
6 changes: 6 additions & 0 deletions manifests/base/event-reporter/event-reporter-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ spec:
secretKeyRef:
key: token
name: argocd-token
- name: ARGOCD_APPLICATION_NAMESPACES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: application.namespaces
optional: true
- name: CODEFRESH_URL
valueFrom:
configMapKeyRef:
Expand Down
Loading