mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-14 05:16:49 +00:00
Implement Workload Run API
implemented workload run api and write e2e test cases for workload run cli and API
This commit is contained in:
@@ -3,15 +3,13 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/oam"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/api/types"
|
||||
"github.com/cloud-native-application/rudrx/pkg/application"
|
||||
"github.com/cloud-native-application/rudrx/pkg/cmd/util"
|
||||
"github.com/cloud-native-application/rudrx/pkg/plugins"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
@@ -19,16 +17,7 @@ import (
|
||||
const Staging = "staging"
|
||||
const App = "app"
|
||||
|
||||
type runOptions struct {
|
||||
Template types.Capability
|
||||
Env *types.EnvMeta
|
||||
workloadName string
|
||||
client client.Client
|
||||
app *application.Application
|
||||
appName string
|
||||
staging bool
|
||||
util.IOStreams
|
||||
}
|
||||
type runOptions oam.RunOptions
|
||||
|
||||
func newRunOptions(ioStreams util.IOStreams) *runOptions {
|
||||
return &runOptions{IOStreams: ioStreams}
|
||||
@@ -53,11 +42,12 @@ func AddWorkloadCommands(parentCmd *cobra.Command, c types.Args, ioStreams util.
|
||||
Example: "vela " + name + ":run frontend",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
o := newRunOptions(ioStreams)
|
||||
o.WorkloadType = name
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.client = newClient
|
||||
o.KubeClient = newClient
|
||||
o.Env, err = GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -89,48 +79,15 @@ func (o *runOptions) Complete(cmd *cobra.Command, args []string, ctx context.Con
|
||||
if argsLength < 1 {
|
||||
return errors.New("must specify name for workload")
|
||||
}
|
||||
o.workloadName = args[0]
|
||||
if app := cmd.Flag(App).Value.String(); app != "" {
|
||||
o.appName = app
|
||||
} else {
|
||||
o.appName = o.workloadName
|
||||
}
|
||||
app, err := application.Load(o.Env.Name, o.appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.Name = o.appName
|
||||
workloadName := args[0]
|
||||
template := o.Template
|
||||
appGroup := cmd.Flag(App).Value.String()
|
||||
|
||||
if app.Components == nil {
|
||||
app.Components = make(map[string]map[string]interface{})
|
||||
}
|
||||
tp, workloadData := app.GetWorkload(o.workloadName)
|
||||
if tp == "" {
|
||||
// Not exist
|
||||
tp = o.Template.Name
|
||||
}
|
||||
|
||||
for _, v := range o.Template.Parameters {
|
||||
flagSet := cmd.Flag(v.Name)
|
||||
switch v.Type {
|
||||
case cue.IntKind:
|
||||
d, _ := strconv.ParseInt(flagSet.Value.String(), 10, 64)
|
||||
workloadData[v.Name] = d
|
||||
case cue.StringKind:
|
||||
workloadData[v.Name] = flagSet.Value.String()
|
||||
case cue.BoolKind:
|
||||
d, _ := strconv.ParseBool(flagSet.Value.String())
|
||||
workloadData[v.Name] = d
|
||||
case cue.NumberKind, cue.FloatKind:
|
||||
d, _ := strconv.ParseFloat(flagSet.Value.String(), 64)
|
||||
workloadData[v.Name] = d
|
||||
}
|
||||
}
|
||||
if err = app.SetWorkload(o.workloadName, tp, workloadData); err != nil {
|
||||
return err
|
||||
}
|
||||
o.app = app
|
||||
return app.Save(o.Env.Name, o.appName)
|
||||
envName := o.Env.Name
|
||||
var flagSet = cmd.Flags()
|
||||
app, err := oam.BaseComplete(envName, workloadName, appGroup, flagSet, template)
|
||||
o.App = app
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *runOptions) Run(cmd *cobra.Command) error {
|
||||
@@ -138,14 +95,10 @@ func (o *runOptions) Run(cmd *cobra.Command) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if staging {
|
||||
o.Info("Staging saved")
|
||||
return nil
|
||||
msg, err := oam.BaseRun(staging, o.App, o.KubeClient, o.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Infof("Creating App %s\n", o.app.Name)
|
||||
if err := o.app.Run(context.Background(), o.client, o.Env); err != nil {
|
||||
return fmt.Errorf("create app err: %s", err)
|
||||
}
|
||||
o.Info("SUCCEED")
|
||||
o.Info(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package oam
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -74,7 +73,7 @@ func ListEnvs(envName string) ([]*types.EnvMeta, error) {
|
||||
env, err := GetEnvByName(envName)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.New(fmt.Sprintf("env %s not exist", envName))
|
||||
err = fmt.Errorf("env %s not exist", envName)
|
||||
}
|
||||
return envList, err
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package oam
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -80,5 +79,5 @@ func GetTraitDefinitionByKind(ctx context.Context, c client.Client, traitKind st
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return traitDefinition, errors.New(fmt.Sprintf("Could not find TraitDefinition by kind %s", traitKind))
|
||||
return traitDefinition, fmt.Errorf("could not find TraitDefinition by kind %s", traitKind)
|
||||
}
|
||||
|
||||
90
pkg/oam/workload.go
Normal file
90
pkg/oam/workload.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package oam
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/api/types"
|
||||
"github.com/cloud-native-application/rudrx/pkg/cmd/util"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/cloud-native-application/rudrx/pkg/application"
|
||||
)
|
||||
|
||||
type RunOptions struct {
|
||||
Template types.Capability
|
||||
Env *types.EnvMeta
|
||||
WorkloadType string
|
||||
WorkloadName string
|
||||
KubeClient client.Client
|
||||
App *application.Application
|
||||
AppName string
|
||||
Staging bool
|
||||
util.IOStreams
|
||||
}
|
||||
|
||||
func BaseComplete(envName string, workloadName string, appGroup string, flagSet *pflag.FlagSet, template types.Capability) (*application.Application, error) {
|
||||
var appName string
|
||||
if appGroup != "" {
|
||||
appName = appGroup
|
||||
} else {
|
||||
appName = workloadName
|
||||
}
|
||||
app, err := application.Load(envName, appName)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
app.Name = appName
|
||||
|
||||
if app.Components == nil {
|
||||
app.Components = make(map[string]map[string]interface{})
|
||||
}
|
||||
tp, workloadData := app.GetWorkload(workloadName)
|
||||
if tp == "" {
|
||||
// Not exist
|
||||
tp = template.Name
|
||||
}
|
||||
|
||||
for _, v := range template.Parameters {
|
||||
flagValue, _ := flagSet.GetString(v.Name)
|
||||
// Cli can check required flag before make a request to backend, but API itself could not, so validate flags here
|
||||
if v.Required && v.Name != "name" && flagValue == "" {
|
||||
return app, fmt.Errorf("required flag(s) \"%s\" not set", v.Name)
|
||||
}
|
||||
switch v.Type {
|
||||
case cue.IntKind:
|
||||
d, _ := strconv.ParseInt(flagValue, 10, 64)
|
||||
workloadData[v.Name] = d
|
||||
case cue.StringKind:
|
||||
workloadData[v.Name] = flagValue
|
||||
case cue.BoolKind:
|
||||
d, _ := strconv.ParseBool(flagValue)
|
||||
workloadData[v.Name] = d
|
||||
case cue.NumberKind, cue.FloatKind:
|
||||
d, _ := strconv.ParseFloat(flagValue, 64)
|
||||
workloadData[v.Name] = d
|
||||
}
|
||||
}
|
||||
if err = app.SetWorkload(workloadName, tp, workloadData); err != nil {
|
||||
return app, err
|
||||
}
|
||||
return app, app.Save(envName, appName)
|
||||
}
|
||||
|
||||
func BaseRun(staging bool, App *application.Application, kubeClient client.Client, Env *types.EnvMeta) (string, error) {
|
||||
if staging {
|
||||
return "Staging saved", nil
|
||||
}
|
||||
var msg string
|
||||
msg = fmt.Sprintf("Creating App %s\n", App.Name)
|
||||
if err := App.Run(context.Background(), kubeClient, Env); err != nil {
|
||||
err = fmt.Errorf("create app err: %s", err)
|
||||
return "", err
|
||||
}
|
||||
msg += "SUCCEED"
|
||||
return msg, nil
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package apis
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime"
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type Environment struct {
|
||||
EnvironmentName string `json:"environmentName" binding:"required,min=1,max=32"`
|
||||
@@ -18,3 +20,15 @@ type Response struct {
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
type WorkloadFlag struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
type WorkloadRunBody struct {
|
||||
EnvName string `json:"env_name"`
|
||||
WorkloadType string `json:"workload_type"`
|
||||
WorkloadName string `json:"workload_name"`
|
||||
AppGroup string `json:"app_group"`
|
||||
Flags []WorkloadFlag `json:"flags"`
|
||||
Staging bool `json:"staging"`
|
||||
}
|
||||
|
||||
@@ -1,9 +1,49 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
import (
|
||||
"github.com/cloud-native-application/rudrx/api/types"
|
||||
"github.com/cloud-native-application/rudrx/pkg/oam"
|
||||
"github.com/cloud-native-application/rudrx/pkg/plugins"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/server/apis"
|
||||
"github.com/cloud-native-application/rudrx/pkg/server/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Workload related handlers
|
||||
func CreateWorkload(c *gin.Context) {
|
||||
kubeClient := c.MustGet("KubeClient")
|
||||
var body apis.WorkloadRunBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
util.HandleError(c, util.InvalidArgument, "the workload run request body is invalid")
|
||||
return
|
||||
}
|
||||
fs := pflag.NewFlagSet("workload", pflag.ContinueOnError)
|
||||
for _, f := range body.Flags {
|
||||
fs.String(f.Name, f.Value, "")
|
||||
}
|
||||
evnName := body.EnvName
|
||||
var template types.Capability
|
||||
|
||||
template, err := plugins.LoadCapabilityByName(body.WorkloadType)
|
||||
appObj, err := oam.BaseComplete(evnName, body.WorkloadName, body.AppGroup, fs, template)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
env, err := oam.GetEnvByName(evnName)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
msg, err := oam.BaseRun(body.Staging, appObj, kubeClient.(client.Client), env)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
util.AssembleResponse(c, msg, err)
|
||||
}
|
||||
|
||||
func UpdateWorkload(c *gin.Context) {
|
||||
|
||||
Reference in New Issue
Block a user