Files
kubevela/references/common/workload.go

126 lines
3.6 KiB
Go

package common
import (
"fmt"
"strconv"
"strings"
"cuelang.org/go/cue"
"github.com/spf13/pflag"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/appfile"
"github.com/oam-dev/kubevela/references/appfile/api"
"github.com/oam-dev/kubevela/references/plugins"
)
// RunOptions include all options for run
type RunOptions struct {
Env *types.EnvMeta
WorkloadName string
KubeClient client.Client
App *api.Application
AppName string
Staging bool
util.IOStreams
}
// InitApplication will load Application from cluster
func InitApplication(env *types.EnvMeta, c types.Args, workloadName string, appGroup string) (*api.Application, error) {
var appName string
if appGroup != "" {
appName = appGroup
} else {
appName = workloadName
}
// TODO(wonderflow): we should load the existing application from cluster and convert to appfile
// app, err := appfile.LoadApplication(env.Namespace, appName, c)
// compatible application not found
app, err := appfile.NewEmptyApplication(env.Namespace, c)
if err != nil {
return nil, err
}
app.Name = appName
return app, nil
}
// BaseComplete will construct an Application from cli parameters.
func BaseComplete(env *types.EnvMeta, c types.Args, workloadName string, appName string, flagSet *pflag.FlagSet, workloadType string) (*api.Application, error) {
app, err := InitApplication(env, c, workloadName, appName)
if err != nil {
return nil, err
}
tp, workloadData := appfile.GetWorkload(app, workloadName)
if tp == "" {
if workloadType == "" {
return nil, fmt.Errorf("must specify workload type for application %s", workloadName)
}
// Not exist
tp = workloadType
}
template, err := plugins.LoadCapabilityByName(tp, env.Namespace, c)
if err != nil {
return nil, err
}
for _, v := range template.Parameters {
name := v.Name
if v.Alias != "" {
name = v.Alias
}
// Cli can check required flag before make a request to backend, but API itself could not, so validate flags here
flag := flagSet.Lookup(name)
if name == "name" {
continue
}
if flag == nil || flag.Value.String() == "" {
if v.Required {
return nil, fmt.Errorf("required flag(s) \"%s\" not set", name)
}
continue
}
// nolint:exhaustive
switch v.Type {
case cue.IntKind:
workloadData[v.Name], err = flagSet.GetInt64(name)
case cue.StringKind:
workloadData[v.Name], err = flagSet.GetString(name)
case cue.BoolKind:
workloadData[v.Name], err = flagSet.GetBool(name)
case cue.NumberKind, cue.FloatKind:
workloadData[v.Name], err = flagSet.GetFloat64(name)
default:
// Currently we don't support get value from complex type
continue
}
if err != nil {
if strings.Contains(err.Error(), "of flag of type string") {
data, _ := flagSet.GetString(name)
// nolint:exhaustive
switch v.Type {
case cue.IntKind:
workloadData[v.Name], err = strconv.ParseInt(data, 10, 64)
case cue.BoolKind:
workloadData[v.Name], err = strconv.ParseBool(data)
case cue.NumberKind, cue.FloatKind:
workloadData[v.Name], err = strconv.ParseFloat(data, 64)
default:
return nil, fmt.Errorf("should not get string from type(%s) for parameter \"%s\"", v.Type.String(), name)
}
if err != nil {
return nil, fmt.Errorf("get flag(s) \"%s\" err %w", v.Name, err)
}
continue
}
return nil, fmt.Errorf("get flag(s) \"%s\" err %w", v.Name, err)
}
}
if err = appfile.SetWorkload(app, workloadName, tp, workloadData); err != nil {
return app, err
}
return app, appfile.Save(app, env.Name)
}