From 08efdb77ec250a79416ad9ae5df19989d36bbc23 Mon Sep 17 00:00:00 2001 From: Eugene Fedorenko Date: Mon, 22 Jul 2024 14:41:19 -0700 Subject: [PATCH 1/4] array string --- controllers/assignment_controller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/controllers/assignment_controller.go b/controllers/assignment_controller.go index e125ebd..ca27ffb 100644 --- a/controllers/assignment_controller.go +++ b/controllers/assignment_controller.go @@ -436,6 +436,9 @@ func (r *AssignmentReconciler) getObjectFromConfigValue(configValue string) inte return object } + // remove leading and trailing ' from the configValue + configValue = strings.Trim(configValue, "'") + return configValue } From d5c58294028f010949a84d3d9d21a9443818ddc9 Mon Sep 17 00:00:00 2001 From: Eugene Fedorenko Date: Mon, 22 Jul 2024 14:58:25 -0700 Subject: [PATCH 2/4] trim space --- controllers/assignment_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/assignment_controller.go b/controllers/assignment_controller.go index ca27ffb..f49a723 100644 --- a/controllers/assignment_controller.go +++ b/controllers/assignment_controller.go @@ -436,8 +436,8 @@ func (r *AssignmentReconciler) getObjectFromConfigValue(configValue string) inte return object } - // remove leading and trailing ' from the configValue - configValue = strings.Trim(configValue, "'") + // remove leading and trailing ' including end of line from the configValue + configValue = strings.Trim(strings.TrimSpace(configValue), "'") return configValue From 4d35b6bd2eafcf9214025b25a6a228a017625aec Mon Sep 17 00:00:00 2001 From: Eugene Fedorenko Date: Tue, 30 Jul 2024 10:42:42 -0700 Subject: [PATCH 3/4] templater --- scheduler/templater.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/scheduler/templater.go b/scheduler/templater.go index 70b6ee5..df0dd2a 100644 --- a/scheduler/templater.go +++ b/scheduler/templater.go @@ -45,8 +45,9 @@ type templater struct { var _ Templater = (*templater)(nil) var funcMap = template.FuncMap{ - "toYaml": toYAML, - "hash": hash, + "toYaml": toYAML, + "stringify": stringify, + "hash": hash, } type dataType struct { @@ -155,3 +156,21 @@ func hash(v interface{}) string { } return strconv.FormatUint(hashValue, 10) } + +func stringify(v interface{}) string { + // if v is a a map, iteratte over keys, if a key is an array or a map, marshal it into string + if m, ok := v.(map[string]interface{}); ok { + for key, value := range m { + switch value.(type) { + case map[string]interface{}, []interface{}: + data, err := yaml.Marshal(value) + if err != nil { + return "" + } + m[key] = string(data) + } + } + return toYAML(m) + } + return toYAML(v) +} From e6520966ab911eabad9f98d605c04467162735cd Mon Sep 17 00:00:00 2001 From: Eugene Fedorenko Date: Thu, 1 Aug 2024 19:43:26 -0700 Subject: [PATCH 4/4] updates --- controllers/assignment_controller.go | 114 ++++++++++++++------------- scheduler/templater.go | 22 +++++- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/controllers/assignment_controller.go b/controllers/assignment_controller.go index f49a723..cf73bf5 100644 --- a/controllers/assignment_controller.go +++ b/controllers/assignment_controller.go @@ -330,6 +330,9 @@ func (r *AssignmentReconciler) getConfigManifests(ctx context.Context, clusterTy } manifests, err := templater.ProcessTemplate(ctx, template) + if err != nil { + return nil, nil, err + } return manifests, &contentType, nil } @@ -421,6 +424,12 @@ func (r *AssignmentReconciler) mergeObjects(existingObject interface{}, newObjec } func (r *AssignmentReconciler) getObjectFromConfigValue(configValue string) interface{} { + trimmedConfigValue := strings.TrimSpace(configValue) + if strings.HasPrefix(trimmedConfigValue, "'") && strings.HasSuffix(trimmedConfigValue, "'") { + trimmedConfigValue = strings.Trim(trimmedConfigValue, "'") + return trimmedConfigValue + } + var object interface{} err := yaml.Unmarshal([]byte(configValue), &object) if err != nil { @@ -436,9 +445,6 @@ func (r *AssignmentReconciler) getObjectFromConfigValue(configValue string) inte return object } - // remove leading and trailing ' including end of line from the configValue - configValue = strings.Trim(strings.TrimSpace(configValue), "'") - return configValue } @@ -593,56 +599,56 @@ func (r *AssignmentReconciler) deleteGitHubIssue(ctx context.Context, logger log return &schedulerv1alpha1.GitIssueStatus{}, nil } -func (r *AssignmentReconciler) findAssignmentsForTemplate(ctx context.Context, object client.Object) []reconcile.Request { - //get template - template := &schedulerv1alpha1.Template{} - err := r.Get(ctx, client.ObjectKey{ - Name: object.GetName(), - Namespace: object.GetNamespace(), - }, template) - if err != nil { - return []reconcile.Request{} - } - - //get cluster types that use this template as a reconciler - clusterTypes := &schedulerv1alpha1.ClusterTypeList{} - err = r.List(ctx, clusterTypes, client.InNamespace(object.GetNamespace()), client.MatchingFields{ReconcilerField: template.Name}) - if err != nil { - return []reconcile.Request{} - } - - //get cluster types that use this template as a namespace service - clusterTypesNameSpace := &schedulerv1alpha1.ClusterTypeList{} - err = r.List(ctx, clusterTypesNameSpace, client.InNamespace(object.GetNamespace()), client.MatchingFields{NamespaceServiceField: template.Name}) - if err != nil { - return []reconcile.Request{} - } - - //append the two lists - clusterTypes.Items = append(clusterTypes.Items, clusterTypesNameSpace.Items...) - - var requests []reconcile.Request - // iterate over the cluster types and find the assignments - for _, clusterType := range clusterTypes.Items { - assignments := &schedulerv1alpha1.AssignmentList{} - err = r.List(ctx, assignments, client.InNamespace(object.GetNamespace()), client.MatchingFields{ClusterTypeField: clusterType.Name}) - if err != nil { - return []reconcile.Request{} - } - - for _, item := range assignments.Items { - request := reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: item.GetName(), - Namespace: item.GetNamespace(), - }, - } - requests = append(requests, request) - } - } - - return requests -} +// func (r *AssignmentReconciler) findAssignmentsForTemplate(ctx context.Context, object client.Object) []reconcile.Request { +// //get template +// template := &schedulerv1alpha1.Template{} +// err := r.Get(ctx, client.ObjectKey{ +// Name: object.GetName(), +// Namespace: object.GetNamespace(), +// }, template) +// if err != nil { +// return []reconcile.Request{} +// } + +// //get cluster types that use this template as a reconciler +// clusterTypes := &schedulerv1alpha1.ClusterTypeList{} +// err = r.List(ctx, clusterTypes, client.InNamespace(object.GetNamespace()), client.MatchingFields{ReconcilerField: template.Name}) +// if err != nil { +// return []reconcile.Request{} +// } + +// //get cluster types that use this template as a namespace service +// clusterTypesNameSpace := &schedulerv1alpha1.ClusterTypeList{} +// err = r.List(ctx, clusterTypesNameSpace, client.InNamespace(object.GetNamespace()), client.MatchingFields{NamespaceServiceField: template.Name}) +// if err != nil { +// return []reconcile.Request{} +// } + +// //append the two lists +// clusterTypes.Items = append(clusterTypes.Items, clusterTypesNameSpace.Items...) + +// var requests []reconcile.Request +// // iterate over the cluster types and find the assignments +// for _, clusterType := range clusterTypes.Items { +// assignments := &schedulerv1alpha1.AssignmentList{} +// err = r.List(ctx, assignments, client.InNamespace(object.GetNamespace()), client.MatchingFields{ClusterTypeField: clusterType.Name}) +// if err != nil { +// return []reconcile.Request{} +// } + +// for _, item := range assignments.Items { +// request := reconcile.Request{ +// NamespacedName: types.NamespacedName{ +// Name: item.GetName(), +// Namespace: item.GetNamespace(), +// }, +// } +// requests = append(requests, request) +// } +// } + +// return requests +// } func (r *AssignmentReconciler) findAssignmentsInObjectNamespace(ctx context.Context, object client.Object) []reconcile.Request { @@ -704,7 +710,7 @@ func (r *AssignmentReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&schedulerv1alpha1.AssignmentPackage{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches( &schedulerv1alpha1.Template{}, - handler.EnqueueRequestsFromMapFunc(r.findAssignmentsForTemplate)). + handler.EnqueueRequestsFromMapFunc(r.findAssignmentsInObjectNamespace)). Watches( &corev1.ConfigMap{}, handler.EnqueueRequestsFromMapFunc(r.findAssignmentsInObjectNamespace)). diff --git a/scheduler/templater.go b/scheduler/templater.go index df0dd2a..f65733f 100644 --- a/scheduler/templater.go +++ b/scheduler/templater.go @@ -48,6 +48,7 @@ var funcMap = template.FuncMap{ "toYaml": toYAML, "stringify": stringify, "hash": hash, + "unquote": unquote, } type dataType struct { @@ -105,6 +106,12 @@ func (h *templater) replaceTemplateVariables(s string) (*string, error) { return nil, err } rs := buf.String() + + // handle nested templates + if strings.Contains(rs, "{{") { + return h.replaceTemplateVariables(rs) + } + return &rs, nil } @@ -158,19 +165,28 @@ func hash(v interface{}) string { } func stringify(v interface{}) string { - // if v is a a map, iteratte over keys, if a key is an array or a map, marshal it into string + // if v is a a map, iterate over keys, if a key is an array or a map, marshal it into string if m, ok := v.(map[string]interface{}); ok { + newMap := make(map[string]interface{}, len(v.(map[string]interface{}))) for key, value := range m { + newMap[key] = value switch value.(type) { case map[string]interface{}, []interface{}: data, err := yaml.Marshal(value) if err != nil { return "" } - m[key] = string(data) + newMap[key] = string(data) } } - return toYAML(m) + return toYAML(newMap) } return toYAML(v) } + +func unquote(v interface{}) string { + if s, ok := v.(string); ok { + return strings.Trim(strings.Trim(strings.TrimSpace(s), "\""), "'") + } + return "" +}