Skip to content

Commit

Permalink
event-reporter: added support of non-controller namespace for parent …
Browse files Browse the repository at this point in the history
…apps. Added `application-namespaces` to run parameter of event-reporter (#274)
  • Loading branch information
oleksandr-codefresh authored Jan 16, 2024
1 parent 526896d commit f663c78
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 12 deletions.
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 {
// if it's manifest generation error we need to still report the actual state
Expand Down Expand Up @@ -150,7 +184,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 @@ -171,12 +205,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 @@ -316,6 +351,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 @@ -486,8 +522,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

0 comments on commit f663c78

Please sign in to comment.