mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-20 16:23:24 +00:00
* Feat: add MapVariant operation and support for OneOf parameters with default variant Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance string parameter output to include optional prefix in CUE generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add ConditionalOrFieldRef for fallback handling and support inline array values Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: update CUE generation to support inline arrays with conditional wrapping Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: update CUE generation to support inline arrays with conditional wrapping Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add support for compound optional fields and enhance array builder with guarded filtering Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add comprehensive tests for ArrayBuilder functionality Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: implement field grouping in StatusBuilder for consolidated CUE output Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance CUE decomposition to support condValues and improve filtering logic Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add metadata labels to ComponentDefinition and update CUE generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: clean up comments and formatting in cuegen and param files Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance CUE generation, trait definitions, and PatchContainer logic CUE Generation: - Simplify condition decomposition logic and rename GetDirective method - Add condition decomposition and lifting logic to improve generated CUE output - Refactor cueTypeForParamType to use a standalone cueTypeStr function for reusability Collections: - Enhance MapVariant operation to merge variant mappings and preserve non-matching items Trait Definitions: - Enhance TraitDefinition and PatchContainerConfig with new attributes (MultiContainerCheckField, MultiContainerErrMsg) - Update emission logic in TraitCUEGenerator for multi-container support PatchContainer: - Update error messages to use camelCase for consistency with KubeVela conventions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance test descriptions for clarity and accuracy in array_builder, collections, and status tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance handling of optional fields in collections and improve test descriptions for clarity Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: improve ConditionalOrFieldRef tests for clarity and accuracy in handling primary and fallback fields Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance test descriptions for clarity and accuracy in array_builder and expr tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: improve formatting of test data in collections tests for better readability Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>
275 lines
9.2 KiB
Go
275 lines
9.2 KiB
Go
/*
|
|
Copyright 2025 The KubeVela Authors.
|
|
|
|
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 defkit
|
|
|
|
import (
|
|
"sigs.k8s.io/yaml"
|
|
|
|
"github.com/oam-dev/kubevela/pkg/definition/defkit/placement"
|
|
)
|
|
|
|
// ComponentDefinition represents a KubeVela ComponentDefinition.
|
|
//
|
|
// ComponentDefinition embeds baseDefinition for common fields and methods shared
|
|
// with TraitDefinition and other definition types.
|
|
type ComponentDefinition struct {
|
|
baseDefinition // embedded common fields (name, description, params, template, etc.)
|
|
workload WorkloadType
|
|
labels map[string]string // metadata labels for the component definition
|
|
}
|
|
|
|
// WorkloadType represents the workload type for a component.
|
|
type WorkloadType struct {
|
|
apiVersion string
|
|
kind string
|
|
autodetect bool // when true, uses "autodetects.core.oam.dev" without definition block
|
|
}
|
|
|
|
// NewComponent creates a new ComponentDefinition builder.
|
|
func NewComponent(name string) *ComponentDefinition {
|
|
return &ComponentDefinition{
|
|
baseDefinition: baseDefinition{
|
|
name: name,
|
|
params: make([]Param, 0),
|
|
},
|
|
}
|
|
}
|
|
|
|
// Description sets the component description.
|
|
func (c *ComponentDefinition) Description(desc string) *ComponentDefinition {
|
|
c.setDescription(desc)
|
|
return c
|
|
}
|
|
|
|
// Workload sets the workload type for this component.
|
|
func (c *ComponentDefinition) Workload(apiVersion, kind string) *ComponentDefinition {
|
|
c.workload = WorkloadType{apiVersion: apiVersion, kind: kind}
|
|
return c
|
|
}
|
|
|
|
// AutodetectWorkload sets the workload type to "autodetects.core.oam.dev".
|
|
// This is used for components where the workload type is auto-detected at runtime
|
|
// rather than being statically defined.
|
|
func (c *ComponentDefinition) AutodetectWorkload() *ComponentDefinition {
|
|
c.workload = WorkloadType{autodetect: true}
|
|
return c
|
|
}
|
|
|
|
// Params adds multiple parameter definitions to the component.
|
|
func (c *ComponentDefinition) Params(params ...Param) *ComponentDefinition {
|
|
c.addParams(params...)
|
|
return c
|
|
}
|
|
|
|
// Param adds a single parameter definition to the component.
|
|
// This provides a more fluent API when adding parameters one at a time.
|
|
func (c *ComponentDefinition) Param(param Param) *ComponentDefinition {
|
|
c.addParams(param)
|
|
return c
|
|
}
|
|
|
|
// Template sets the template function for the component.
|
|
func (c *ComponentDefinition) Template(fn func(tpl *Template)) *ComponentDefinition {
|
|
c.setTemplate(fn)
|
|
return c
|
|
}
|
|
|
|
// CustomStatus sets the custom status CUE expression for the component.
|
|
// This expression is used to compute a human-readable status message.
|
|
func (c *ComponentDefinition) CustomStatus(expr string) *ComponentDefinition {
|
|
c.setCustomStatus(expr)
|
|
return c
|
|
}
|
|
|
|
// HealthPolicy sets the health policy CUE expression for the component.
|
|
// This expression determines whether the component is healthy.
|
|
// For raw CUE strings, use this method directly.
|
|
// For composable health expressions, use HealthPolicyExpr with Health().
|
|
func (c *ComponentDefinition) HealthPolicy(expr string) *ComponentDefinition {
|
|
c.setHealthPolicy(expr)
|
|
return c
|
|
}
|
|
|
|
// HealthPolicyExpr sets the health policy using a composable HealthExpression.
|
|
// This allows building health checks programmatically using primitives like
|
|
// Condition, Field, Phase, Exists, And, Or, Not via Health().
|
|
//
|
|
// Example:
|
|
//
|
|
// h := defkit.Health()
|
|
// def.HealthPolicyExpr(h.Condition("Ready").IsTrue())
|
|
// def.HealthPolicyExpr(h.AllTrue("Ready", "Synced"))
|
|
// def.HealthPolicyExpr(h.And(
|
|
// h.Condition("Ready").IsTrue(),
|
|
// h.Field("status.replicas").Gt(0),
|
|
// ))
|
|
func (c *ComponentDefinition) HealthPolicyExpr(expr HealthExpression) *ComponentDefinition {
|
|
c.setHealthPolicyExpr(expr)
|
|
return c
|
|
}
|
|
|
|
// DefName implements Definition.DefName - returns the definition name.
|
|
func (c *ComponentDefinition) DefName() string { return c.name }
|
|
|
|
// DefType implements Definition.DefType - returns the definition type.
|
|
func (c *ComponentDefinition) DefType() DefinitionType { return DefinitionTypeComponent }
|
|
|
|
// GetWorkload returns the workload type.
|
|
func (c *ComponentDefinition) GetWorkload() WorkloadType { return c.workload }
|
|
|
|
// Helper adds a helper type definition using fluent API.
|
|
// The param defines the schema for the helper type.
|
|
// Example:
|
|
//
|
|
// Helper("HealthProbe", defkit.Object("probe").WithFields(...))
|
|
func (c *ComponentDefinition) Helper(name string, param Param) *ComponentDefinition {
|
|
c.addHelper(name, param)
|
|
return c
|
|
}
|
|
|
|
// Labels sets metadata labels on the component definition.
|
|
// Usage: component.Labels(map[string]string{"ui-hidden": "true"})
|
|
func (c *ComponentDefinition) Labels(labels map[string]string) *ComponentDefinition {
|
|
c.labels = labels
|
|
return c
|
|
}
|
|
|
|
// GetLabels returns the component's metadata labels.
|
|
func (c *ComponentDefinition) GetLabels() map[string]string { return c.labels }
|
|
|
|
// RawCUE sets raw CUE for complex component definitions that don't fit the builder pattern.
|
|
// When set, this bypasses all other template settings and outputs the raw CUE directly.
|
|
func (c *ComponentDefinition) RawCUE(cue string) *ComponentDefinition {
|
|
c.setRawCUE(cue)
|
|
return c
|
|
}
|
|
|
|
// WithImports adds CUE imports to the component definition.
|
|
// Usage: component.WithImports("strconv", "strings", "list")
|
|
func (c *ComponentDefinition) WithImports(imports ...string) *ComponentDefinition {
|
|
c.addImports(imports...)
|
|
return c
|
|
}
|
|
|
|
// RunOn adds placement conditions specifying which clusters this definition should run on.
|
|
// Use the placement package's fluent API to build conditions.
|
|
//
|
|
// Example:
|
|
//
|
|
// defkit.NewComponent("eks-only").
|
|
// RunOn(placement.Label("provider").Eq("aws")).
|
|
// RunOn(placement.Label("cluster-type").NotEq("vcluster"))
|
|
//
|
|
// Multiple RunOn calls are combined with AND semantics (all conditions must match).
|
|
func (c *ComponentDefinition) RunOn(conditions ...placement.Condition) *ComponentDefinition {
|
|
c.addRunOn(conditions...)
|
|
return c
|
|
}
|
|
|
|
// NotRunOn adds placement conditions specifying which clusters this definition should NOT run on.
|
|
// Use the placement package's fluent API to build conditions.
|
|
//
|
|
// Example:
|
|
//
|
|
// defkit.NewComponent("no-vclusters").
|
|
// NotRunOn(placement.Label("cluster-type").Eq("vcluster"))
|
|
//
|
|
// If any NotRunOn condition matches, the definition is ineligible for that cluster.
|
|
func (c *ComponentDefinition) NotRunOn(conditions ...placement.Condition) *ComponentDefinition {
|
|
c.addNotRunOn(conditions...)
|
|
return c
|
|
}
|
|
|
|
// ToCue generates the complete CUE definition string for this component.
|
|
// This is a convenience method that creates a CUEGenerator and calls GenerateFullDefinition.
|
|
func (c *ComponentDefinition) ToCue() string {
|
|
// If raw CUE is set, use it with the name from NewComponent() taking precedence
|
|
if c.HasRawCUE() {
|
|
return c.GetRawCUEWithName()
|
|
}
|
|
gen := NewCUEGenerator()
|
|
if len(c.GetImports()) > 0 {
|
|
gen.WithImports(c.GetImports()...)
|
|
}
|
|
return gen.GenerateFullDefinition(c)
|
|
}
|
|
|
|
// ToCueWithImports generates the CUE definition with the specified imports.
|
|
// Use this when the definition requires CUE standard library imports.
|
|
// Example: component.ToCueWithImports(CUEImports.Strconv, CUEImports.List)
|
|
func (c *ComponentDefinition) ToCueWithImports(imports ...string) string {
|
|
gen := NewCUEGenerator().WithImports(imports...)
|
|
return gen.GenerateFullDefinition(c)
|
|
}
|
|
|
|
// ToParameterSchema generates only the parameter schema block.
|
|
// This is useful for testing or comparing parameter schemas.
|
|
func (c *ComponentDefinition) ToParameterSchema() string {
|
|
gen := NewCUEGenerator()
|
|
return gen.GenerateParameterSchema(c)
|
|
}
|
|
|
|
// ToYAML generates the Kubernetes YAML representation of the ComponentDefinition.
|
|
// This produces a ComponentDefinition custom resource that can be applied to a cluster.
|
|
// Note: The CUE template is embedded in the spec.schematic.cue field.
|
|
func (c *ComponentDefinition) ToYAML() ([]byte, error) {
|
|
cueStr := c.ToCue()
|
|
|
|
// Build the ComponentDefinition CR structure
|
|
cr := map[string]any{
|
|
"apiVersion": "core.oam.dev/v1beta1",
|
|
"kind": "ComponentDefinition",
|
|
"metadata": map[string]any{
|
|
"name": c.GetName(),
|
|
"annotations": map[string]any{
|
|
"definition.oam.dev/description": c.GetDescription(),
|
|
},
|
|
},
|
|
"spec": map[string]any{
|
|
"workload": map[string]any{
|
|
"definition": map[string]any{
|
|
"apiVersion": c.workload.apiVersion,
|
|
"kind": c.workload.kind,
|
|
},
|
|
},
|
|
"schematic": map[string]any{
|
|
"cue": map[string]any{
|
|
"template": cueStr,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Handle autodetect workload type
|
|
if c.workload.autodetect {
|
|
cr["spec"].(map[string]any)["workload"] = map[string]any{
|
|
"type": "autodetects.core.oam.dev",
|
|
}
|
|
}
|
|
|
|
return yaml.Marshal(cr)
|
|
}
|
|
|
|
// APIVersion returns the workload API version.
|
|
func (w WorkloadType) APIVersion() string { return w.apiVersion }
|
|
|
|
// Kind returns the workload kind.
|
|
func (w WorkloadType) Kind() string { return w.kind }
|
|
|
|
// IsAutodetect returns true if the workload type is auto-detected at runtime.
|
|
func (w WorkloadType) IsAutodetect() bool { return w.autodetect }
|