mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: add uischema manage command (#3021)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
@@ -82,6 +82,8 @@ const (
|
||||
TypeDefinition = "Managing Definitions"
|
||||
// TypePlugin defines one category used in Kubectl Plugin
|
||||
TypePlugin = "Plugin Command"
|
||||
// TypeUISchema defines one category
|
||||
TypeUISchema = "Managing UISchema"
|
||||
)
|
||||
|
||||
// LabelArg is the argument `label` of a definition
|
||||
|
||||
@@ -263,6 +263,9 @@ func patchSchema(defaultSchema, customSchema []*utils.UIParameter) []*utils.UIPa
|
||||
for i, custom := range customSchema {
|
||||
customSchemaMap[custom.JSONKey] = customSchema[i]
|
||||
}
|
||||
if len(defaultSchema) == 0 {
|
||||
return customSchema
|
||||
}
|
||||
for i := range defaultSchema {
|
||||
dSchema := defaultSchema[i]
|
||||
if cusSchema, exist := customSchemaMap[dSchema.JSONKey]; exist {
|
||||
|
||||
@@ -90,7 +90,6 @@ func NewCommand() *cobra.Command {
|
||||
|
||||
// Workflows
|
||||
NewWorkflowCommand(commandArgs, ioStream),
|
||||
|
||||
NewRegistryCommand(ioStream),
|
||||
NewTemplateCommand(ioStream),
|
||||
NewTraitCommand(commandArgs, ioStream),
|
||||
@@ -113,6 +112,9 @@ func NewCommand() *cobra.Command {
|
||||
// cluster
|
||||
ClusterCommandGroup(commandArgs, ioStream),
|
||||
|
||||
// ui schema
|
||||
NewUISchemaCommand(commandArgs, ioStream),
|
||||
|
||||
// Helper
|
||||
SystemCommandGroup(commandArgs, ioStream),
|
||||
NewCompletionCommand(),
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
- jsonKey: objects
|
||||
uiType: K8sObjectsCode
|
||||
@@ -0,0 +1,23 @@
|
||||
- jsonKey: writeConnectionSecretToRef
|
||||
disable: true
|
||||
- jsonKey: providerRef
|
||||
disable: true
|
||||
- jsonKey: region
|
||||
disable: true
|
||||
- jsonKey: instance_name
|
||||
label: InstanceName
|
||||
sort: 1
|
||||
- jsonKey: database_name
|
||||
label: DatabaseName
|
||||
sort: 2
|
||||
- jsonKey: account_name
|
||||
label: AccountName
|
||||
sort: 3
|
||||
- jsonKey: password
|
||||
sort: 4
|
||||
- jsonKey: allocate_public_connection
|
||||
label: AllocatePublicConnection
|
||||
sort: 5
|
||||
- jsonKey: deleteResource
|
||||
label: DeleteResource
|
||||
sort: 10
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
Copyright 2021 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 cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
// NewUISchemaCommand creates `uischema` command
|
||||
func NewUISchemaCommand(c common.Args, ioStreams util.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "uischema",
|
||||
Aliases: []string{"ui"},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeUISchema,
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(&cobra.Command{
|
||||
Use: "apply",
|
||||
Short: "apply <ui schema file/dir path>",
|
||||
Args: cobra.ExactValidArgs(1),
|
||||
Long: "apply uischema from a file or dir",
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeUISchema,
|
||||
},
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("please provider the uischema file or dir path")
|
||||
}
|
||||
allUISchemaFiles, err := loadUISchemaFiles(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range allUISchemaFiles {
|
||||
if err := applyUISchemaFile(client, file); err != nil {
|
||||
ioStreams.Errorf("apply %s failure %s \n", file, err.Error())
|
||||
continue
|
||||
}
|
||||
ioStreams.Infof("apply %s success \n", file)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func loadUISchemaFiles(setpath string) ([]string, error) {
|
||||
schema, err := os.Stat(setpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var readDir func(string) ([]string, error)
|
||||
readDir = func(filepath string) ([]string, error) {
|
||||
files, err := os.ReadDir(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var subFiles []string
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
files, err := readDir(path.Join(filepath, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subFiles = append(subFiles, files...)
|
||||
} else if strings.HasSuffix(f.Name(), ".yaml") {
|
||||
subFiles = append(subFiles, path.Join(filepath, f.Name()))
|
||||
}
|
||||
}
|
||||
return subFiles, nil
|
||||
}
|
||||
var allUISchemaFiles = []string{}
|
||||
if schema.IsDir() {
|
||||
allUISchemaFiles, err = readDir(setpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
allUISchemaFiles = append(allUISchemaFiles, setpath)
|
||||
}
|
||||
return allUISchemaFiles, nil
|
||||
}
|
||||
|
||||
func applyUISchemaFile(client client.Client, uischemaFile string) error {
|
||||
cdata, err := ioutil.ReadFile(filepath.Clean(uischemaFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileBaseName := path.Base(uischemaFile)
|
||||
fileBaseNameWithoutExt := fileBaseName[:strings.Index(fileBaseName, ".")]
|
||||
|
||||
infos := strings.SplitN(fileBaseNameWithoutExt, "-", func() int {
|
||||
if strings.Contains(fileBaseNameWithoutExt, "uischema") {
|
||||
return 3
|
||||
}
|
||||
return 2
|
||||
}())
|
||||
if len(infos) == 2 || len(infos) == 3 && infos[1] == "uischema" {
|
||||
name := infos[1]
|
||||
if len(infos) == 3 {
|
||||
name = infos[2]
|
||||
}
|
||||
err = addDefinitionUISchema(context.Background(), client, name, infos[0], string(cdata))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("file name is invalid")
|
||||
}
|
||||
|
||||
func addDefinitionUISchema(ctx context.Context, client client.Client, name, defType, configRaw string) error {
|
||||
var uiParameters []*utils.UIParameter
|
||||
err := yaml.Unmarshal([]byte(configRaw), &uiParameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dataBate, err := json.Marshal(uiParameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cm v1.ConfigMap
|
||||
if err := client.Get(ctx, k8stypes.NamespacedName{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: fmt.Sprintf("%s-uischema-%s", defType, name),
|
||||
}, &cm); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
err = client.Create(ctx, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: fmt.Sprintf("%s-uischema-%s", defType, name),
|
||||
},
|
||||
Data: map[string]string{
|
||||
types.UISchema: string(dataBate),
|
||||
},
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cm.Data[types.UISchema] = string(dataBate)
|
||||
err := client.Update(ctx, &cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright 2021 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 cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestLoadUISchemaFiles(t *testing.T) {
|
||||
files, err := loadUISchemaFiles("test-data/uischema")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, len(files) == 2)
|
||||
}
|
||||
|
||||
func TestNewUISchemaCommand(t *testing.T) {
|
||||
cmd := NewUISchemaCommand(common2.Args{}, util.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
|
||||
initCommand(cmd)
|
||||
cmd.SetArgs([]string{"apply", "test-data/uischema"})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("failed to execute definition command: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user