diff --git a/controllers/assignment_controller.go b/controllers/assignment_controller.go index e125ebd..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 { @@ -590,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 { @@ -701,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 70b6ee5..f65733f 100644 --- a/scheduler/templater.go +++ b/scheduler/templater.go @@ -45,8 +45,10 @@ type templater struct { var _ Templater = (*templater)(nil) var funcMap = template.FuncMap{ - "toYaml": toYAML, - "hash": hash, + "toYaml": toYAML, + "stringify": stringify, + "hash": hash, + "unquote": unquote, } type dataType struct { @@ -104,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 } @@ -155,3 +163,30 @@ func hash(v interface{}) string { } return strconv.FormatUint(hashValue, 10) } + +func stringify(v interface{}) 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 "" + } + newMap[key] = string(data) + } + } + 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 "" +}