add karmadactl interpret subcommand
Signed-off-by: yingjinhui <yingjinhui@didiglobal.com>
This commit is contained in:
parent
594ad9f44b
commit
81b2596ec1
|
@ -0,0 +1,93 @@
|
|||
package interpret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/cli-runtime/pkg/printers"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
|
||||
"github.com/karmada-io/karmada/pkg/resourceinterpreter/configurableinterpreter/luavm"
|
||||
)
|
||||
|
||||
func (o *Options) runCheck() error {
|
||||
w := printers.GetNewTabWriter(o.Out)
|
||||
defer w.Flush()
|
||||
|
||||
failed := false
|
||||
|
||||
err := o.CustomizationResult.Visit(func(info *resource.Info, _ error) error {
|
||||
var visitErr error
|
||||
fmt.Fprintln(w, "-----------------------------------")
|
||||
|
||||
source := info.Source
|
||||
if info.Name != "" {
|
||||
source = info.Name
|
||||
}
|
||||
fmt.Fprintf(w, "SOURCE: %s\n", source)
|
||||
|
||||
customization, visitErr := asResourceInterpreterCustomization(info.Object)
|
||||
if visitErr != nil {
|
||||
failed = true
|
||||
fmt.Fprintf(w, "%v\n", visitErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
kind := customization.Spec.Target.Kind
|
||||
if kind == "" {
|
||||
failed = true
|
||||
fmt.Fprintln(w, "target.kind no set")
|
||||
return nil
|
||||
}
|
||||
apiVersion := customization.Spec.Target.APIVersion
|
||||
if apiVersion == "" {
|
||||
failed = true
|
||||
fmt.Fprintln(w, "target.apiVersion no set")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "TARGET: %s %s\t\n", apiVersion, kind)
|
||||
fmt.Fprintf(w, "RULERS:\n")
|
||||
for _, r := range o.Rules {
|
||||
fmt.Fprintf(w, " %s:\t", r.Name())
|
||||
|
||||
script := r.GetScript(customization)
|
||||
if script == "" {
|
||||
fmt.Fprintln(w, "UNSET")
|
||||
continue
|
||||
}
|
||||
checkErr := checkScrip(script)
|
||||
if checkErr != nil {
|
||||
failed = true
|
||||
fmt.Fprintf(w, "%s: %s\t\n", "ERROR", strings.TrimSpace(checkErr.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, "PASS")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if failed {
|
||||
// As failed infos are printed above. So don't print it again.
|
||||
return cmdutil.ErrExit
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkScrip(script string) error {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
||||
defer cancel()
|
||||
l, err := luavm.NewWithContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.Close()
|
||||
_, err = l.LoadString(script)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package interpret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
|
||||
func (o *Options) completeExecute(_ util.Factory, _ *cobra.Command, _ []string) []error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Options) runExecute() error {
|
||||
return fmt.Errorf("not implement")
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package interpret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
|
||||
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/options"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/util"
|
||||
"github.com/karmada-io/karmada/pkg/util/gclient"
|
||||
)
|
||||
|
||||
var (
|
||||
interpretLong = templates.LongDesc(`
|
||||
Validate and test interpreter customization before applying it to the control plane.
|
||||
|
||||
1. Validate the ResourceInterpreterCustomization configuration as per API schema
|
||||
and try to load the scripts for syntax check.
|
||||
|
||||
2. Run the rules locally and test if the result is expected. Similar to the dry run.
|
||||
|
||||
`)
|
||||
|
||||
interpretExample = templates.Examples(`
|
||||
# Check the customizations in file
|
||||
%[1]s interpret -f customization.json --check
|
||||
# Execute the retention rule for
|
||||
%[1]s interpret -f customization.yml --operation retain --desired-file desired.yml --observed-file observed.yml
|
||||
# Execute the replicaRevision rule for
|
||||
%[1]s interpret -f customization.yml --operation reviseReplica --observed-file observed.yml --desired-replica 2
|
||||
# Execute the statusReflection rule for
|
||||
%[1]s interpret -f customization.yml --operation interpretStatus --observed-file observed.yml
|
||||
# Execute the healthInterpretation rule
|
||||
%[1]s interpret -f customization.yml --operation interpretHealth --observed-file observed.yml
|
||||
# Execute the dependencyInterpretation rule
|
||||
%[1]s interpret -f customization.yml --operation interpretDependency --observed-file observed.yml
|
||||
# Execute the statusAggregation rule
|
||||
%[1]s interpret -f customization.yml --operation aggregateStatus --status-file status1.yml --status-file status2.yml
|
||||
|
||||
`)
|
||||
)
|
||||
|
||||
const (
|
||||
customizationResourceName = "resourceinterpretercustomizations"
|
||||
)
|
||||
|
||||
// NewCmdInterpret new interpret command.
|
||||
func NewCmdInterpret(f util.Factory, parentCommand string, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &Options{
|
||||
IOStreams: streams,
|
||||
Rules: allRules,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "interpret (-f FILENAME) (--operation OPERATION) [--ARGS VALUE]... ",
|
||||
Short: "Validate and test interpreter customization before applying it to the control plane",
|
||||
Long: interpretLong,
|
||||
SilenceUsage: true,
|
||||
DisableFlagsInUseLine: true,
|
||||
Example: fmt.Sprintf(interpretExample, parentCommand),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
util.TagCommandGroup: util.GroupClusterTroubleshootingAndDebugging,
|
||||
},
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
options.AddKubeConfigFlags(flags)
|
||||
flags.StringVar(&o.Operation, "operation", o.Operation, "The interpret operation to use. One of: ("+strings.Join(o.Rules.Names(), ",")+")")
|
||||
flags.BoolVar(&o.Check, "check", false, "Validates the given ResourceInterpreterCustomization configuration(s)")
|
||||
flags.StringVar(&o.DesiredFile, "desired-file", o.DesiredFile, "Filename, directory, or URL to files identifying the resource to use as desiredObj argument in rule script.")
|
||||
flags.StringVar(&o.ObservedFile, "observed-file", o.ObservedFile, "Filename, directory, or URL to files identifying the resource to use as observedObj argument in rule script.")
|
||||
flags.StringSliceVar(&o.StatusFile, "status-file", o.StatusFile, "Filename, directory, or URL to files identifying the resource to use as statusItems argument in rule script.")
|
||||
flags.Int32Var(&o.DesiredReplica, "desired-replica", o.DesiredReplica, "The desiredReplica argument in rule script.")
|
||||
cmdutil.AddJsonFilenameFlag(flags, &o.FilenameOptions.Filenames, "Filename, directory, or URL to files containing the customizations")
|
||||
flags.BoolVarP(&o.FilenameOptions.Recursive, "recursive", "R", false, "Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Options contains the input to the interpret command.
|
||||
type Options struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
Operation string
|
||||
Check bool
|
||||
|
||||
// args
|
||||
DesiredFile string
|
||||
ObservedFile string
|
||||
StatusFile []string
|
||||
DesiredReplica int32
|
||||
|
||||
CustomizationResult *resource.Result
|
||||
|
||||
Rules Rules
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// Complete ensures that options are valid and marshals them if necessary
|
||||
func (o *Options) Complete(f util.Factory, cmd *cobra.Command, args []string) error {
|
||||
scheme := gclient.NewSchema()
|
||||
o.CustomizationResult = f.NewBuilder().
|
||||
WithScheme(scheme, scheme.PrioritizedVersionsAllGroups()...).
|
||||
FilenameParam(false, &o.FilenameOptions).
|
||||
ResourceNames(customizationResourceName, args...).
|
||||
RequireObject(true).
|
||||
Local().
|
||||
Do()
|
||||
|
||||
var errs []error
|
||||
errs = append(errs, o.CustomizationResult.Err())
|
||||
errs = append(errs, o.completeExecute(f, cmd, args)...)
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// Validate checks the EditOptions to see if there is sufficient information to run the command.
|
||||
func (o *Options) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run describe information of resources
|
||||
func (o *Options) Run() error {
|
||||
switch {
|
||||
case o.Check:
|
||||
return o.runCheck()
|
||||
default:
|
||||
return o.runExecute()
|
||||
}
|
||||
}
|
||||
|
||||
func asResourceInterpreterCustomization(o runtime.Object) (*configv1alpha1.ResourceInterpreterCustomization, error) {
|
||||
c, ok := o.(*configv1alpha1.ResourceInterpreterCustomization)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a ResourceInterpreterCustomization: %#v", o)
|
||||
}
|
||||
return c, nil
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
package interpret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||
"github.com/karmada-io/karmada/pkg/resourceinterpreter/configurableinterpreter"
|
||||
)
|
||||
|
||||
var allRules = []Rule{
|
||||
&retentionRule{},
|
||||
&replicaResourceRule{},
|
||||
&replicaRevisionRule{},
|
||||
&statusReflectionRule{},
|
||||
&statusAggregationRule{},
|
||||
&healthInterpretationRule{},
|
||||
&dependencyInterpretationRule{},
|
||||
}
|
||||
|
||||
type retentionRule struct{}
|
||||
|
||||
func (r *retentionRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationRetain)
|
||||
}
|
||||
|
||||
func (r *retentionRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.Retention != nil {
|
||||
return c.Spec.Customizations.Retention.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *retentionRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.Retention = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.Retention == nil {
|
||||
c.Spec.Customizations.Retention = &configv1alpha1.LocalValueRetention{}
|
||||
}
|
||||
c.Spec.Customizations.Retention.LuaScript = script
|
||||
}
|
||||
|
||||
func (r *retentionRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
desired, err := args.getDesiredObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
observed, err := args.getObservedObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
retained, enabled, err := interpreter.Retain(desired, observed)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("retained", retained)
|
||||
}
|
||||
|
||||
type replicaResourceRule struct {
|
||||
}
|
||||
|
||||
func (r *replicaResourceRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationInterpretReplica)
|
||||
}
|
||||
|
||||
func (r *replicaResourceRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.ReplicaResource != nil {
|
||||
return c.Spec.Customizations.ReplicaResource.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *replicaResourceRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.ReplicaResource = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.ReplicaResource == nil {
|
||||
c.Spec.Customizations.ReplicaResource = &configv1alpha1.ReplicaResourceRequirement{}
|
||||
}
|
||||
c.Spec.Customizations.ReplicaResource.LuaScript = script
|
||||
}
|
||||
|
||||
func (r *replicaResourceRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
replica, requires, enabled, err := interpreter.GetReplicas(obj)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("replica", replica).add("requires", requires)
|
||||
}
|
||||
|
||||
type replicaRevisionRule struct {
|
||||
}
|
||||
|
||||
func (r *replicaRevisionRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationReviseReplica)
|
||||
}
|
||||
|
||||
func (r *replicaRevisionRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.ReplicaRevision != nil {
|
||||
return c.Spec.Customizations.ReplicaRevision.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *replicaRevisionRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.ReplicaRevision = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.ReplicaRevision == nil {
|
||||
c.Spec.Customizations.ReplicaRevision = &configv1alpha1.ReplicaRevision{}
|
||||
}
|
||||
c.Spec.Customizations.ReplicaRevision.LuaScript = script
|
||||
}
|
||||
|
||||
func (r *replicaRevisionRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
revised, enabled, err := interpreter.ReviseReplica(obj, args.Replica)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("revised", revised)
|
||||
}
|
||||
|
||||
type statusReflectionRule struct {
|
||||
}
|
||||
|
||||
func (s *statusReflectionRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationInterpretStatus)
|
||||
}
|
||||
|
||||
func (s *statusReflectionRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.StatusReflection != nil {
|
||||
return c.Spec.Customizations.StatusReflection.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *statusReflectionRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.StatusReflection = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.StatusReflection == nil {
|
||||
c.Spec.Customizations.StatusReflection = &configv1alpha1.StatusReflection{}
|
||||
}
|
||||
c.Spec.Customizations.StatusReflection.LuaScript = script
|
||||
}
|
||||
|
||||
func (s *statusReflectionRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
status, enabled, err := interpreter.ReflectStatus(obj)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("status", status)
|
||||
}
|
||||
|
||||
type statusAggregationRule struct {
|
||||
}
|
||||
|
||||
func (s *statusAggregationRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationAggregateStatus)
|
||||
}
|
||||
|
||||
func (s *statusAggregationRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.StatusAggregation != nil {
|
||||
return c.Spec.Customizations.StatusAggregation.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *statusAggregationRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.StatusAggregation = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.StatusAggregation == nil {
|
||||
c.Spec.Customizations.StatusAggregation = &configv1alpha1.StatusAggregation{}
|
||||
}
|
||||
c.Spec.Customizations.StatusAggregation.LuaScript = script
|
||||
}
|
||||
|
||||
func (s *statusAggregationRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
aggregateStatus, enabled, err := interpreter.AggregateStatus(obj, args.Status)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("aggregateStatus", aggregateStatus)
|
||||
}
|
||||
|
||||
type healthInterpretationRule struct {
|
||||
}
|
||||
|
||||
func (h *healthInterpretationRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationInterpretHealth)
|
||||
}
|
||||
|
||||
func (h *healthInterpretationRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.HealthInterpretation != nil {
|
||||
return c.Spec.Customizations.Retention.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (h *healthInterpretationRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.HealthInterpretation = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.HealthInterpretation == nil {
|
||||
c.Spec.Customizations.HealthInterpretation = &configv1alpha1.HealthInterpretation{}
|
||||
}
|
||||
c.Spec.Customizations.HealthInterpretation.LuaScript = script
|
||||
}
|
||||
|
||||
func (h *healthInterpretationRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
healthy, enabled, err := interpreter.InterpretHealth(obj)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("healthy", healthy)
|
||||
}
|
||||
|
||||
type dependencyInterpretationRule struct {
|
||||
}
|
||||
|
||||
func (d *dependencyInterpretationRule) Name() string {
|
||||
return string(configv1alpha1.InterpreterOperationInterpretDependency)
|
||||
}
|
||||
|
||||
func (d *dependencyInterpretationRule) GetScript(c *configv1alpha1.ResourceInterpreterCustomization) string {
|
||||
if c.Spec.Customizations.DependencyInterpretation != nil {
|
||||
return c.Spec.Customizations.Retention.LuaScript
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d *dependencyInterpretationRule) SetScript(c *configv1alpha1.ResourceInterpreterCustomization, script string) {
|
||||
if script == "" {
|
||||
c.Spec.Customizations.DependencyInterpretation = nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.Spec.Customizations.DependencyInterpretation == nil {
|
||||
c.Spec.Customizations.DependencyInterpretation = &configv1alpha1.DependencyInterpretation{}
|
||||
}
|
||||
c.Spec.Customizations.DependencyInterpretation.LuaScript = script
|
||||
}
|
||||
|
||||
func (d *dependencyInterpretationRule) Run(interpreter *configurableinterpreter.ConfigurableInterpreter, args ruleArgs) *ruleResult {
|
||||
obj, err := args.getObjectOrError()
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
dependencies, enabled, err := interpreter.GetDependencies(obj)
|
||||
if err != nil {
|
||||
return newRuleResultWithError(err)
|
||||
}
|
||||
if !enabled {
|
||||
return newRuleResultWithError(fmt.Errorf("rule is not enabled"))
|
||||
}
|
||||
return newRuleResult().add("dependencies", dependencies)
|
||||
}
|
||||
|
||||
// Rule known how to get and set script for interpretation rule, and can execute the rule with given args.
|
||||
type Rule interface {
|
||||
// Name returns the name of the rule.
|
||||
Name() string
|
||||
// GetScript returns the script for the rule from customization. If not enabled, return empty
|
||||
GetScript(*configv1alpha1.ResourceInterpreterCustomization) string
|
||||
// SetScript set the script for the rule. If script is empty, disable the rule.
|
||||
SetScript(*configv1alpha1.ResourceInterpreterCustomization, string)
|
||||
// Run execute the rule with given args, and return the result.
|
||||
Run(*configurableinterpreter.ConfigurableInterpreter, ruleArgs) *ruleResult
|
||||
}
|
||||
|
||||
// Rules is a series of rules.
|
||||
type Rules []Rule
|
||||
|
||||
// Names returns the names of containing rules.
|
||||
func (r Rules) Names() []string {
|
||||
names := make([]string, len(r))
|
||||
for i, rr := range r {
|
||||
names[i] = rr.Name()
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// Get returns the rule with the name. If not found, return nil.
|
||||
func (r Rules) Get(name string) Rule {
|
||||
for _, rr := range r {
|
||||
if rr.Name() == name {
|
||||
return rr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ruleArgs struct {
|
||||
Desired *unstructured.Unstructured
|
||||
Observed *unstructured.Unstructured
|
||||
Status []workv1alpha2.AggregatedStatusItem
|
||||
Replica int64
|
||||
}
|
||||
|
||||
func (r ruleArgs) getDesiredObjectOrError() (*unstructured.Unstructured, error) {
|
||||
if r.Desired == nil {
|
||||
return nil, fmt.Errorf("desired, desired-file options are not set")
|
||||
}
|
||||
return r.Desired, nil
|
||||
}
|
||||
|
||||
func (r ruleArgs) getObservedObjectOrError() (*unstructured.Unstructured, error) {
|
||||
if r.Observed == nil {
|
||||
return nil, fmt.Errorf("observed, observed-file options are not set")
|
||||
}
|
||||
return r.Observed, nil
|
||||
}
|
||||
|
||||
func (r ruleArgs) getObjectOrError() (*unstructured.Unstructured, error) {
|
||||
if r.Desired == nil && r.Observed == nil {
|
||||
return nil, fmt.Errorf("desired, desired-file, observed, observed-file options are not set")
|
||||
}
|
||||
if r.Desired != nil && r.Observed != nil {
|
||||
return nil, fmt.Errorf("you can not specify multiple object by desired, desired-file, observed, observed-file options")
|
||||
}
|
||||
if r.Desired != nil {
|
||||
return r.Desired, nil
|
||||
}
|
||||
return r.Observed, nil
|
||||
}
|
||||
|
||||
type nameValue struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type ruleResult struct {
|
||||
Results []nameValue
|
||||
Err error
|
||||
}
|
||||
|
||||
func newRuleResult() *ruleResult {
|
||||
return &ruleResult{}
|
||||
}
|
||||
|
||||
func newRuleResultWithError(err error) *ruleResult {
|
||||
return &ruleResult{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ruleResult) add(name string, value interface{}) *ruleResult {
|
||||
r.Results = append(r.Results, nameValue{Name: name, Value: value})
|
||||
return r
|
||||
}
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/karmada-io/karmada/pkg/karmadactl/describe"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/exec"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/get"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/interpret"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/join"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/logs"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/options"
|
||||
|
@ -97,6 +98,7 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command {
|
|||
logs.NewCmdLogs(f, parentCommand, ioStreams),
|
||||
exec.NewCmdExec(f, parentCommand, ioStreams),
|
||||
describe.NewCmdDescribe(f, parentCommand, ioStreams),
|
||||
interpret.NewCmdInterpret(f, parentCommand, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -404,6 +404,25 @@ func (vm VM) GetDependencies(object *unstructured.Unstructured, script string) (
|
|||
return
|
||||
}
|
||||
|
||||
// NewWithContext creates a lua VM with the given context.
|
||||
func NewWithContext(ctx context.Context) (*lua.LState, error) {
|
||||
vm := VM{}
|
||||
l := lua.NewState(lua.Options{
|
||||
SkipOpenLibs: !vm.UseOpenLibs,
|
||||
})
|
||||
// Opens table library to allow access to functions to manipulate tables
|
||||
err := vm.setLib(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// preload our 'safe' version of the OS library. Allows the 'local os = require("os")' to work
|
||||
l.PreloadModule(lua.OsLibName, lifted.SafeOsLoader)
|
||||
if ctx != nil {
|
||||
l.SetContext(ctx)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func decodeValue(L *lua.LState, value interface{}) (lua.LValue, error) {
|
||||
// We handle simple type without json for better performance.
|
||||
|
|
Loading…
Reference in New Issue