template-operator
template-operator copied to clipboard
Feature request: adding an object as a value
This is really a great project! However i'm missing a feature: It would be really nice, if i could embedd whole objects as values.
I created a generic CRD that uses a json.RawMessage in my Spec (see details for spec) to take all kinds of values no matter what the struct is. This way i can template whatever i want.
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"encoding/json"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// MyCRDOverriderSpec defines the desired state of MyCRDOverrider
type MyCRDOverriderSpec struct {
// Foo is an example field of MyCRDOverrider. Edit MyCRDoverrider_types.go to remove/update
// +kubebuilder:validation:Schemaless
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Type=object
Values json.RawMessage `json:"values"`
}
// MyCRDOverriderStatus defines the observed state of MyCRDOverrider
type MyCRDOverriderStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// MyCRDOverrider is the Schema for the MyCRDoverriders API
type MyCRDOverrider struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MyCRDOverriderSpec `json:"spec,omitempty"`
Status MyCRDOverriderStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// MyCRDOverriderList contains a list of MyCRDOverrider
type MyCRDOverriderList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MyCRDOverrider `json:"items"`
}
func init() {
SchemeBuilder.Register(&MyCRDOverrider{}, &MyCRDOverriderList{})
}
This works great for simple values, e.g.
kind: MyCRDOverrider
apiVersion: mygroup.mydomain/v1alpha1
metadata:
name: unicorn
namespace: template
spec:
values:
name: unicorn
With this template
apiVersion: templating.flanksource.com/v1
kind: Template
metadata:
name: bash
namespace: template
spec:
source:
apiVersion: mygroup.mydomain/v1alpha1
kind: MyCRDOverrider
resources:
- kind: Deployment
apiVersion: apps/v1
metadata:
name: bash
namespace: template
spec:
replicas: 1
selector:
matchLabels:
app: bash
template:
metadata:
labels:
app: bash
spec:
containers:
- image: bash
imagePullPolicy: IfNotPresent
command: ["bash", "-c", "sleep 99999999"]
name: "{{.spec.values.name}}"
However, what doesn't work is putting a whole object into values, like adding the resources object.
Values:
kind: EdgeApplicationOverrider
apiVersion: edgeapplication.kubeedge/v1alpha1
metadata:
name: unicorn
namespace: template
spec:
values:
name: unicorn
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
and the template like above
...
spec:
containers:
- image: bash
imagePullPolicy: IfNotPresent
command: ["bash", "-c", "sleep 99999999"]
name: "{{.spec.values.name}}"
resources: "{{.spec.values.resources}}"
The error log from template-operator is
ts=2022-11-16T10:58:58.880200737Z level=info logger=controllers.Template msg=Reconciling template=/bash template=bash
ts=2022-11-16T10:58:58.883745874Z level=info logger=controllers.Template msg="Found resources for template" template=/bash template=bash count=1
ts=2022-11-16T10:58:58.884844986Z level=error logger=controllers.Template msg="failed to ducktype object" template=/bash error="failed to duck type object: field: spec.template.spec.containers.0.resources failed to transform string to type &{[object] }: failed to transform string value to object: invalid character 'm' looking for beginning of value: invalid character 'm' looking for beginning of value" errorVerbose="invalid character 'm' looking for beginning of value\nfailed to transform string value to object: invalid character 'm' looking for beginning of value\ngithub.com/flanksource/template-operator/k8s.transformStringToType\n\t/workspace/k8s/schema_manager.go:466\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:170\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:141\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).DuckType\n\t/workspace/k8s/schema_manager.go:111\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResultObject\n\t/workspace/k8s/template_manager.go:396\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResult\n\t/workspace/k8s/template_manager.go:380\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Template\n\t/workspace/k8s/template_manager.go:372\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjects\n\t/workspace/k8s/template_manager.go:440\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjectsFromResources\n\t/workspace/k8s/template_manager.go:813\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).HandleSource\n\t/workspace/k8s/template_manager.go:249\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Run\n\t/workspace/k8s/template_manager.go:209\ngithub.com/flanksource/template-operator/controllers.(*TemplateReconciler).Reconcile\n\t/workspace/controllers/template_controller.go:92\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:298\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:253\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:216\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.UntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:1371\nfield: spec.template.spec.containers.0.resources failed to transform string to type &{[object] }\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:172\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:141\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).duckType\n\t/workspace/k8s/schema_manager.go:156\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).DuckType\n\t/workspace/k8s/schema_manager.go:111\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResultObject\n\t/workspace/k8s/template_manager.go:396\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResult\n\t/workspace/k8s/template_manager.go:380\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Template\n\t/workspace/k8s/template_manager.go:372\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjects\n\t/workspace/k8s/template_manager.go:440\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjectsFromResources\n\t/workspace/k8s/template_manager.go:813\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).HandleSource\n\t/workspace/k8s/template_manager.go:249\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Run\n\t/workspace/k8s/template_manager.go:209\ngithub.com/flanksource/template-operator/controllers.(*TemplateReconciler).Reconcile\n\t/workspace/controllers/template_controller.go:92\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:298\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:253\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:216\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.UntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:1371\nfailed to duck type object\ngithub.com/flanksource/template-operator/k8s.(*SchemaManager).DuckType\n\t/workspace/k8s/schema_manager.go:113\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResultObject\n\t/workspace/k8s/template_manager.go:396\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResult\n\t/workspace/k8s/template_manager.go:380\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Template\n\t/workspace/k8s/template_manager.go:372\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjects\n\t/workspace/k8s/template_manager.go:440\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjectsFromResources\n\t/workspace/k8s/template_manager.go:813\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).HandleSource\n\t/workspace/k8s/template_manager.go:249\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Run\n\t/workspace/k8s/template_manager.go:209\ngithub.com/flanksource/template-operator/controllers.(*TemplateReconciler).Reconcile\n\t/workspace/controllers/template_controller.go:92\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:298\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:253\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:216\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.UntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:1371" stacktrace="github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/pkg/mod/github.com/go-logr/[email protected]/zapr.go:132\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResultObject\n\t/workspace/k8s/template_manager.go:397\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).duckTypeTemplateResult\n\t/workspace/k8s/template_manager.go:380\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Template\n\t/workspace/k8s/template_manager.go:372\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjects\n\t/workspace/k8s/template_manager.go:440\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).getObjectsFromResources\n\t/workspace/k8s/template_manager.go:813\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).HandleSource\n\t/workspace/k8s/template_manager.go:249\ngithub.com/flanksource/template-operator/k8s.(*TemplateManager).Run\n\t/workspace/k8s/template_manager.go:209\ngithub.com/flanksource/template-operator/controllers.(*TemplateReconciler).Reconcile\n\t/workspace/controllers/template_controller.go:92\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:298\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:253\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:216\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.UntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99"
ts=2022-11-16T10:58:58.886327813Z level=info logger=controllers.Template msg=Applying template=/bash kind=Deployment namespace=template name=bash
ts=2022-11-16T10:58:58.886450736Z level=error logger=controller-runtime.manager.controller.template msg="Reconciler error" reconcilergroup=templating.flanksource.com reconcilerkind=Template name=bash namespace= error="cannot restore struct from: string" stacktrace="github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/pkg/mod/github.com/go-logr/[email protected]/zapr.go:132\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:302\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:253\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:216\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185\nk8s.io/apimachinery/pkg/util/wait.UntilWithContext\n\t/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99"