mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Refactor(cli): Refactor vela env, deprecate vela config (#2037)
* Refactor(cli): cut env to namespace, use application to save Signed-off-by: qiaozp <chivalry.pp@gmail.com> * Fix: test * Fix: typo
This commit is contained in:
@@ -47,12 +47,13 @@ const (
|
||||
StatusStaging = "Staging"
|
||||
)
|
||||
|
||||
// EnvMeta stores the info for app environment
|
||||
// Config contains key/value pairs
|
||||
type Config map[string]string
|
||||
|
||||
// EnvMeta stores the namespace for app environment
|
||||
type EnvMeta struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
|
||||
Current string `json:"current,omitempty"`
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ var ApplicationExecContext = func(context string, appName string) bool {
|
||||
|
||||
var ApplicationPortForwardContext = func(context string, appName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get output of portward successfully", func() {
|
||||
ginkgo.It("should get output of port-forward successfully", func() {
|
||||
cli := fmt.Sprintf("vela port-forward %s 80:80 ", appName)
|
||||
output, err := e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
@@ -128,14 +128,6 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
|
||||
data := []struct {
|
||||
q, a string
|
||||
}{
|
||||
{
|
||||
q: "What is the domain of your application service (optional): ",
|
||||
a: "testdomain",
|
||||
},
|
||||
{
|
||||
q: "What is your email (optional, used to generate certification): ",
|
||||
a: "test@mail",
|
||||
},
|
||||
{
|
||||
q: "What would you like to name your application (required): ",
|
||||
a: appName,
|
||||
|
||||
@@ -33,7 +33,7 @@ var (
|
||||
cli := fmt.Sprintf("vela env init %s", envName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
expectedOutput := fmt.Sprintf("environment %s created,", envName)
|
||||
expectedOutput := fmt.Sprintf("environment %s created", envName)
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput))
|
||||
})
|
||||
})
|
||||
@@ -45,7 +45,7 @@ var (
|
||||
cli := fmt.Sprintf("vela env init %s --namespace %s", envName, namespace)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
expectedOutput := fmt.Sprintf("environment %s created,", envName)
|
||||
expectedOutput := fmt.Sprintf("environment %s created", envName)
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput))
|
||||
})
|
||||
})
|
||||
|
||||
2
e2e/env/env_test.go
vendored
2
e2e/env/env_test.go
vendored
@@ -32,7 +32,7 @@ var _ = ginkgo.Describe("Env", func() {
|
||||
e2e.EnvInitContext("env init", envName)
|
||||
e2e.EnvInitContext("env init another one", envName2)
|
||||
e2e.EnvShowContext("env show", envName)
|
||||
e2e.EnvSetContext("env sw", envName)
|
||||
e2e.EnvSetContext("env set", envName)
|
||||
|
||||
ginkgo.Context("env list", func() {
|
||||
ginkgo.It("should list all envs", func() {
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
// Splitter is a splitter for configmap name generation
|
||||
Splitter = "-"
|
||||
|
||||
// TypeConfigMap defines the type of Configmap
|
||||
TypeConfigMap = "configmap"
|
||||
)
|
||||
|
||||
// ToConfigMap will get the data of the store and upload to configmap.
|
||||
// Serverside Application controller can only use the config in appfile context by configmap.
|
||||
func ToConfigMap(s Store, name, envName string, configData map[string]string) (*v1.ConfigMap, error) {
|
||||
namespace, err := s.Namespace(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cm = v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
}
|
||||
cm.SetName(name)
|
||||
cm.SetNamespace(namespace)
|
||||
cm.Data = configData
|
||||
return &cm, nil
|
||||
}
|
||||
|
||||
// GenConfigMapName is a fixed way to name the configmap name for appfile config
|
||||
func GenConfigMapName(appName, serviceName, configName string) string {
|
||||
return strings.Join([]string{"kubevela", appName, serviceName, configName}, Splitter)
|
||||
}
|
||||
|
||||
var _ Store = &Configmap{}
|
||||
|
||||
// Configmap is the configmap implementation of config store
|
||||
type Configmap struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// GetConfigData will get config data from configmap
|
||||
func (f *Configmap) GetConfigData(name, envName string) ([]map[string]string, error) {
|
||||
|
||||
namespace, err := f.Namespace(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cm v1.ConfigMap
|
||||
err = f.Client.Get(context.Background(), client.ObjectKey{Name: name, Namespace: namespace}, &cm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data []map[string]string
|
||||
for k, v := range cm.Data {
|
||||
data = append(data, EncodeConfigFormat(k, v))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Namespace returns the namespace of the config store from env
|
||||
func (f *Configmap) Namespace(envName string) (string, error) {
|
||||
// TODO(wonderflow): now we regard env as namespace, it should be fixed when env is store serverside as configmap
|
||||
return envName, nil
|
||||
}
|
||||
|
||||
// Type returns the type of the config store
|
||||
func (Configmap) Type() string {
|
||||
return TypeConfigMap
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/config"
|
||||
env2 "github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
)
|
||||
|
||||
// TypeLocal defines the local config store type
|
||||
const TypeLocal = "local"
|
||||
|
||||
// Local is the local implementation of config store
|
||||
type Local struct{}
|
||||
|
||||
var _ Store = &Local{}
|
||||
|
||||
// GetConfigData will return config data from local
|
||||
func (l *Local) GetConfigData(configName, envName string) ([]map[string]string, error) {
|
||||
cfgData, err := config.ReadConfig(envName, configName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
|
||||
var data []map[string]string
|
||||
for scanner.Scan() {
|
||||
k, v, err := config.ReadConfigLine(scanner.Text())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = append(data, EncodeConfigFormat(k, v))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Namespace return namespace from env
|
||||
func (l *Local) Namespace(envName string) (string, error) {
|
||||
env, err := env2.GetEnvByName(envName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return env.Namespace, nil
|
||||
}
|
||||
|
||||
// Type returns the type of this config store implementation
|
||||
func (l *Local) Type() string {
|
||||
return TypeLocal
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import "errors"
|
||||
|
||||
// Store will get config data
|
||||
type Store interface {
|
||||
GetConfigData(configName, envName string) ([]map[string]string, error)
|
||||
Type() string
|
||||
Namespace(envName string) (string, error)
|
||||
}
|
||||
|
||||
// TypeFake is a fake type
|
||||
const TypeFake = "fake"
|
||||
|
||||
var _ Store = &Fake{}
|
||||
|
||||
// Fake is a fake implementation of config store, help for test
|
||||
type Fake struct {
|
||||
Data []map[string]string
|
||||
}
|
||||
|
||||
// GetConfigData get data
|
||||
func (f *Fake) GetConfigData(_ string, _ string) ([]map[string]string, error) {
|
||||
return f.Data, nil
|
||||
}
|
||||
|
||||
// Type return the type
|
||||
func (Fake) Type() string {
|
||||
return TypeFake
|
||||
}
|
||||
|
||||
// Namespace return the Namespace
|
||||
func (Fake) Namespace(_ string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// EncodeConfigFormat will encode key-value to config{name: key, value: value} format
|
||||
func EncodeConfigFormat(key, value string) map[string]string {
|
||||
return map[string]string{
|
||||
"name": key,
|
||||
"value": value,
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeConfigFormat will decode config{name: key, value: value} format to key-value mode.
|
||||
func DecodeConfigFormat(data []map[string]string) (map[string]string, error) {
|
||||
var res = make(map[string]string)
|
||||
for _, d := range data {
|
||||
key, ok := d["name"]
|
||||
if !ok {
|
||||
return nil, errors.New("invalid data format, no 'name' found")
|
||||
}
|
||||
value, ok := d["value"]
|
||||
if !ok {
|
||||
return nil, errors.New("invalid data format, no 'value' found")
|
||||
}
|
||||
res[key] = value
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -91,6 +91,23 @@ func InitBaseRestConfig() (Args, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// globalClient will be a client for whole command lifecycle
|
||||
var globalClient client.Client
|
||||
|
||||
// SetGlobalClient will set a client for one cli command
|
||||
func SetGlobalClient(clt client.Client) error {
|
||||
globalClient = clt
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClient will K8s client in args
|
||||
func GetClient() (client.Client, error) {
|
||||
if globalClient != nil {
|
||||
return globalClient, nil
|
||||
}
|
||||
return nil, errors.New("client not set, call SetGlobalClient first")
|
||||
}
|
||||
|
||||
// HTTPGet will send GET http request with context
|
||||
func HTTPGet(ctx context.Context, url string) ([]byte, error) {
|
||||
// Change NewRequest to NewRequestWithContext and pass context it
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
)
|
||||
|
||||
// ReadConfigLine will read config from line
|
||||
func ReadConfigLine(line string) (string, string, error) {
|
||||
ss := strings.SplitN(line, ":", 2)
|
||||
if len(ss) != 2 {
|
||||
return "", "", fmt.Errorf("config data is malformed: %s", line)
|
||||
}
|
||||
for i := range ss {
|
||||
ss[i] = strings.TrimSpace(ss[i])
|
||||
}
|
||||
vDec, err := b64.StdEncoding.DecodeString(ss[1])
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return ss[0], string(vDec), nil
|
||||
}
|
||||
|
||||
// GetConfigsDir will get config from dir
|
||||
func GetConfigsDir(envName string) (string, error) {
|
||||
cfgDir := filepath.Join(env.GetEnvDirByName(envName), "configs")
|
||||
err := os.MkdirAll(cfgDir, 0700)
|
||||
return cfgDir, err
|
||||
}
|
||||
|
||||
// DeleteConfig will delete local config file
|
||||
func DeleteConfig(envName, configName string) error {
|
||||
d, err := GetConfigsDir(envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfgFile := filepath.Join(d, configName)
|
||||
return os.RemoveAll(cfgFile)
|
||||
}
|
||||
|
||||
// ReadConfig will read the config data from local
|
||||
func ReadConfig(envName, configName string) ([]byte, error) {
|
||||
d, err := GetConfigsDir(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgFile := filepath.Join(d, configName)
|
||||
b, err := os.ReadFile(filepath.Clean(cfgFile))
|
||||
if os.IsNotExist(err) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
|
||||
// WriteConfig will write data into local config
|
||||
func WriteConfig(envName, configName string, data []byte) error {
|
||||
d, err := GetConfigsDir(envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfgFile := filepath.Join(d, configName)
|
||||
return os.WriteFile(cfgFile, data, 0600)
|
||||
}
|
||||
374
pkg/utils/env/env.go
vendored
374
pkg/utils/env/env.go
vendored
@@ -18,151 +18,150 @@ package env
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"cuelang.org/go/pkg/strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
)
|
||||
|
||||
// GetEnvDirByName will get env dir from name
|
||||
func GetEnvDirByName(name string) string {
|
||||
envdir, _ := system.GetEnvDir()
|
||||
return filepath.Join(envdir, name)
|
||||
const (
|
||||
// IndicatingLabel is label key indicating application is an env
|
||||
IndicatingLabel = "cli.env.oam.dev/name"
|
||||
// RawType is component type of raw
|
||||
RawType = "raw"
|
||||
// DefaultEnvName is name of default env
|
||||
DefaultEnvName = "default"
|
||||
// DefaultEnvNamespace is namespace of default env
|
||||
DefaultEnvNamespace = "default"
|
||||
// AppNameSchema is used to generate env app name
|
||||
AppNameSchema = "vela-env-%s"
|
||||
// AppNamePrefix is prefix of AppNameSchema
|
||||
AppNamePrefix = "vela-env-"
|
||||
)
|
||||
|
||||
// app2Env and env2App are helper convert functions
|
||||
func app2Env(app *v1beta1.Application) (*types.EnvMeta, error) {
|
||||
namespace := getEnvNamespace(app)
|
||||
env := types.EnvMeta{
|
||||
Name: strings.Replace(app.Name, AppNamePrefix, "", 1),
|
||||
Namespace: namespace,
|
||||
Current: "",
|
||||
}
|
||||
return &env, nil
|
||||
}
|
||||
|
||||
func env2App(meta *types.EnvMeta) *v1beta1.Application {
|
||||
app := v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: v1beta1.ApplicationKind,
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf(AppNameSchema, meta.Name),
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common2.ApplicationComponent{},
|
||||
},
|
||||
}
|
||||
|
||||
addNamespaceObjectIfNeeded(meta, &app)
|
||||
labels := map[string]string{
|
||||
IndicatingLabel: meta.Name,
|
||||
}
|
||||
app.SetLabels(labels)
|
||||
|
||||
return &app
|
||||
}
|
||||
|
||||
// getEnvAppByName and deleteAppByName are application operation helper functions
|
||||
func getEnvAppByName(envName string) (*v1beta1.Application, error) {
|
||||
list, err := getEnvAppList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// match envName
|
||||
for _, app := range list {
|
||||
if app.Name == fmt.Sprintf(AppNameSchema, envName) {
|
||||
return &app, nil
|
||||
}
|
||||
}
|
||||
if envName == DefaultEnvName {
|
||||
_ = initDefaultEnv()
|
||||
return getEnvAppByName(envName)
|
||||
}
|
||||
return nil, errors.Errorf("application %s not found", envName)
|
||||
}
|
||||
|
||||
func deleteAppByName(name string) error {
|
||||
clt, err := common.GetClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get client fail")
|
||||
}
|
||||
app, err := getEnvAppByName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = clt.Delete(context.Background(), app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// following functions are CRUD of env
|
||||
|
||||
// CreateEnv will create e env.
|
||||
// Because Env equals to namespace, one env should not be updated
|
||||
func CreateEnv(envName string, envArgs *types.EnvMeta) error {
|
||||
c, err := common.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e := envArgs
|
||||
nowEnv, err := GetEnvByName(envName)
|
||||
if err == nil {
|
||||
if nowEnv.Namespace != envArgs.Namespace {
|
||||
return errors.Errorf("env %s has existed", envName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if e.Namespace == "" {
|
||||
e.Namespace = "default"
|
||||
}
|
||||
|
||||
app := env2App(envArgs)
|
||||
err = applyApp(context.TODO(), app, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// GetEnvByName will get env info by name
|
||||
func GetEnvByName(name string) (*types.EnvMeta, error) {
|
||||
data, err := os.ReadFile(filepath.Join(GetEnvDirByName(name), system.EnvConfigName))
|
||||
init, err := getEnvAppByName(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("env %s not exist", name)
|
||||
}
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "Env not exist")
|
||||
}
|
||||
var meta types.EnvMeta
|
||||
if err = json.Unmarshal(data, &meta); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &meta, nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateEnv will create or update env.
|
||||
// If it does not exist, create it and set to the new env.
|
||||
// If it exists, update it and set to the new env.
|
||||
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
|
||||
|
||||
createOrUpdated := "created"
|
||||
old, err := GetEnvByName(envName)
|
||||
if err == nil {
|
||||
createOrUpdated = "updated"
|
||||
if envArgs.Domain == "" {
|
||||
envArgs.Domain = old.Domain
|
||||
}
|
||||
if envArgs.Email == "" {
|
||||
envArgs.Email = old.Email
|
||||
}
|
||||
if envArgs.Namespace == "" {
|
||||
envArgs.Namespace = old.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
if envArgs.Namespace == "" {
|
||||
envArgs.Namespace = "default"
|
||||
}
|
||||
|
||||
var message = ""
|
||||
// Check If Namespace Exists
|
||||
if err := c.Get(ctx, k8stypes.NamespacedName{Name: envArgs.Namespace}, &corev1.Namespace{}); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return message, err
|
||||
}
|
||||
// Create Namespace if not found
|
||||
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil {
|
||||
return message, err
|
||||
}
|
||||
}
|
||||
|
||||
data, err := json.Marshal(envArgs)
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
envdir, err := system.GetEnvDir()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
subEnvDir := filepath.Join(envdir, envName)
|
||||
if _, err = system.CreateIfNotExist(subEnvDir); err != nil {
|
||||
return message, err
|
||||
}
|
||||
// nolint:gosec
|
||||
if err = os.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil {
|
||||
return message, err
|
||||
}
|
||||
curEnvPath, err := system.GetCurrentEnvPath()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
// nolint:gosec
|
||||
if err = os.WriteFile(curEnvPath, []byte(envName), 0644); err != nil {
|
||||
return message, err
|
||||
}
|
||||
|
||||
message = fmt.Sprintf("environment %s %s, Namespace: %s", envName, createOrUpdated, envArgs.Namespace)
|
||||
if envArgs.Email != "" {
|
||||
message += fmt.Sprintf(", Email: %s", envArgs.Email)
|
||||
}
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// CreateEnv will only create. If env already exists, return error
|
||||
func CreateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
|
||||
_, err := GetEnvByName(envName)
|
||||
if err == nil {
|
||||
message := fmt.Sprintf("Env %s already exist", envName)
|
||||
return message, errors.New(message)
|
||||
}
|
||||
return CreateOrUpdateEnv(ctx, c, envName, envArgs)
|
||||
}
|
||||
|
||||
// UpdateEnv will update Env, if env does not exist, return error
|
||||
func UpdateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) {
|
||||
var message = ""
|
||||
envMeta, err := GetEnvByName(envName)
|
||||
if err != nil {
|
||||
return err.Error(), err
|
||||
}
|
||||
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envMeta.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return message, err
|
||||
}
|
||||
envMeta.Namespace = namespace
|
||||
data, err := json.Marshal(envMeta)
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
envdir, err := system.GetEnvDir()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
subEnvDir := filepath.Join(envdir, envName)
|
||||
// nolint:gosec
|
||||
if err = os.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil {
|
||||
return message, err
|
||||
}
|
||||
message = "Update env succeed"
|
||||
return message, err
|
||||
return app2Env(init)
|
||||
}
|
||||
|
||||
// ListEnvs will list all envs
|
||||
// if envName specified, return list that only contains one env
|
||||
func ListEnvs(envName string) ([]*types.EnvMeta, error) {
|
||||
var envList []*types.EnvMeta
|
||||
if envName != "" {
|
||||
@@ -176,40 +175,59 @@ func ListEnvs(envName string) ([]*types.EnvMeta, error) {
|
||||
envList = append(envList, env)
|
||||
return envList, err
|
||||
}
|
||||
envDir, err := system.GetEnvDir()
|
||||
apps, err := getEnvAppList()
|
||||
if err != nil {
|
||||
return envList, err
|
||||
return nil, err
|
||||
}
|
||||
files, err := os.ReadDir(envDir)
|
||||
if err != nil {
|
||||
return envList, err
|
||||
// if even one env is not exist, create a default env
|
||||
if len(apps) == 0 {
|
||||
err := initDefaultEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ListEnvs(envName)
|
||||
}
|
||||
curEnv, err := GetCurrentEnvName()
|
||||
|
||||
curEnv, err := getCurrentEnvName()
|
||||
if err != nil {
|
||||
curEnv = types.DefaultEnvName
|
||||
}
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
continue
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Clean(filepath.Join(envDir, f.Name(), system.EnvConfigName)))
|
||||
for i := range apps {
|
||||
env, err := app2Env(&apps[i])
|
||||
if err != nil {
|
||||
fmt.Printf("error occurred while listing env:" + err.Error())
|
||||
continue
|
||||
}
|
||||
var envMeta types.EnvMeta
|
||||
if err = json.Unmarshal(data, &envMeta); err != nil {
|
||||
continue
|
||||
if curEnv == env.Name {
|
||||
env.Current = "*"
|
||||
}
|
||||
if curEnv == f.Name() {
|
||||
envMeta.Current = "*"
|
||||
}
|
||||
envList = append(envList, &envMeta)
|
||||
envList = append(envList, env)
|
||||
}
|
||||
return envList, nil
|
||||
}
|
||||
|
||||
// GetCurrentEnvName will get current env name
|
||||
func GetCurrentEnvName() (string, error) {
|
||||
// DeleteEnv will delete env and its application
|
||||
func DeleteEnv(envName string) (string, error) {
|
||||
var message string
|
||||
var err error
|
||||
curEnv, err := getCurrentEnvName()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
if envName == curEnv {
|
||||
err = fmt.Errorf("you can't delete current using environment %s", curEnv)
|
||||
return message, err
|
||||
}
|
||||
err = deleteAppByName(envName)
|
||||
if err != nil {
|
||||
return message, errors.Wrap(err, fmt.Sprintf("error deleting env %s", envName))
|
||||
}
|
||||
message = "env" + envName + " deleted"
|
||||
return message, err
|
||||
}
|
||||
|
||||
// getCurrentEnvName will get current env name
|
||||
func getCurrentEnvName() (string, error) {
|
||||
currentEnvPath, err := system.GetCurrentEnvPath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -221,34 +239,19 @@ func GetCurrentEnvName() (string, error) {
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// DeleteEnv will delete env locally
|
||||
func DeleteEnv(envName string) (string, error) {
|
||||
var message string
|
||||
var err error
|
||||
curEnv, err := GetCurrentEnvName()
|
||||
// GetCurrentEnv will get current env, create default env if not exist
|
||||
func GetCurrentEnv() (*types.EnvMeta, error) {
|
||||
envName, err := getCurrentEnvName()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
if envName == curEnv {
|
||||
err = fmt.Errorf("you can't delete current using environment %s", curEnv)
|
||||
return message, err
|
||||
}
|
||||
envdir, err := system.GetEnvDir()
|
||||
if err != nil {
|
||||
return message, err
|
||||
}
|
||||
envPath := filepath.Join(envdir, envName)
|
||||
if _, err := os.Stat(envPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = fmt.Errorf("%s does not exist", envName)
|
||||
return message, err
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if err = initDefaultEnv(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
envName = types.DefaultEnvName
|
||||
}
|
||||
if err = os.RemoveAll(envPath); err != nil {
|
||||
return message, err
|
||||
}
|
||||
message = envName + " deleted"
|
||||
return message, err
|
||||
return GetEnvByName(envName)
|
||||
}
|
||||
|
||||
// SetEnv will set the current env to the specified one
|
||||
@@ -269,3 +272,34 @@ func SetEnv(envName string) (string, error) {
|
||||
msg = fmt.Sprintf("Set environment succeed, current environment is " + envName + ", namespace is " + envMeta.Namespace)
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// applyApp helps apply app
|
||||
func applyApp(ctx context.Context, app *v1beta1.Application, c client.Client) error {
|
||||
applicator := apply.NewAPIApplicator(c)
|
||||
err := applicator.Apply(ctx, app)
|
||||
return err
|
||||
}
|
||||
|
||||
// initDefaultEnv create default env if not exist
|
||||
func initDefaultEnv() error {
|
||||
fmt.Println("Initializing default vela env...")
|
||||
defaultEnv := &types.EnvMeta{Name: DefaultEnvName, Namespace: DefaultEnvNamespace}
|
||||
app := env2App(defaultEnv)
|
||||
clt, err := common.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = applyApp(context.Background(), app, clt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentEnvPath, err := system.GetCurrentEnvPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:gosec
|
||||
if err = os.WriteFile(currentEnvPath, []byte(DefaultEnvName), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
92
pkg/utils/env/env_test.go
vendored
Normal file
92
pkg/utils/env/env_test.go
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
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 env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
)
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
testCases := []struct {
|
||||
envName string
|
||||
namespace string
|
||||
wantComponents []common2.ApplicationComponent
|
||||
labels map[string]string
|
||||
}{
|
||||
{
|
||||
envName: "test-env",
|
||||
namespace: "test-env-ns",
|
||||
wantComponents: []common2.ApplicationComponent{
|
||||
{
|
||||
Name: "test-env-ns",
|
||||
Type: RawType,
|
||||
Properties: util.Object2RawExtension(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": map[string]string{"name": "test-env-ns"},
|
||||
})},
|
||||
},
|
||||
labels: map[string]string{IndicatingLabel: "test-env"},
|
||||
},
|
||||
|
||||
{
|
||||
envName: "test-env-default",
|
||||
namespace: "default",
|
||||
wantComponents: []common2.ApplicationComponent{},
|
||||
labels: map[string]string{IndicatingLabel: "test-env-default"},
|
||||
},
|
||||
}
|
||||
baseApp := v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: v1beta1.ApplicationKind,
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common2.ApplicationComponent{}}}
|
||||
for _, c := range testCases {
|
||||
env := &types.EnvMeta{
|
||||
Name: c.envName,
|
||||
Namespace: c.namespace,
|
||||
}
|
||||
rightApp := baseApp.DeepCopy()
|
||||
rightApp.ObjectMeta.Name = fmt.Sprintf(AppNameSchema, c.envName)
|
||||
rightApp.ObjectMeta.Labels = c.labels
|
||||
rightApp.Spec.Components = c.wantComponents
|
||||
|
||||
generatedApp := env2App(env)
|
||||
assert.DeepEqual(t, generatedApp, rightApp)
|
||||
|
||||
generatedEnv, err := app2Env(rightApp)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, generatedEnv, env)
|
||||
}
|
||||
}
|
||||
87
pkg/utils/env/helper.go
vendored
Normal file
87
pkg/utils/env/helper.go
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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 env
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
// getEnvAppList will filter application that represent an env
|
||||
func getEnvAppList() ([]v1beta1.Application, error) {
|
||||
list := v1beta1.ApplicationList{}
|
||||
clt, err := common.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := context.Background()
|
||||
matchLabels := metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: IndicatingLabel,
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
}},
|
||||
}
|
||||
selector, err := metav1.LabelSelectorAsSelector(&matchLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = clt.List(ctx, &list, &client.ListOptions{LabelSelector: selector})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list.Items, nil
|
||||
}
|
||||
|
||||
func getEnvNamespace(application *v1beta1.Application) string {
|
||||
namespace := DefaultEnvNamespace
|
||||
for _, comp := range application.Spec.Components {
|
||||
if comp.Type == RawType {
|
||||
obj, err := util.RawExtension2Unstructured(&comp.Properties)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return obj.GetName()
|
||||
}
|
||||
}
|
||||
return namespace
|
||||
}
|
||||
|
||||
// add namespace object if env namespace is not default
|
||||
func addNamespaceObjectIfNeeded(meta *types.EnvMeta, app *v1beta1.Application) {
|
||||
if meta.Namespace != DefaultEnvNamespace {
|
||||
app.Spec.Components = append(app.Spec.Components, common2.ApplicationComponent{
|
||||
Name: meta.Namespace,
|
||||
Type: RawType,
|
||||
Properties: util.Object2RawExtension(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": map[string]string{
|
||||
"name": meta.Namespace,
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,10 @@ limitations under the License.
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const defaultVelaHome = ".vela"
|
||||
@@ -35,14 +34,23 @@ const (
|
||||
|
||||
// GetVelaHomeDir return vela home dir
|
||||
func GetVelaHomeDir() (string, error) {
|
||||
var velaHome string
|
||||
if custom := os.Getenv(VelaHomeEnv); custom != "" {
|
||||
return custom, nil
|
||||
velaHome = custom
|
||||
} else {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
velaHome = filepath.Join(home, defaultVelaHome)
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
if _, err := os.Stat(velaHome); err != nil && os.IsNotExist(err) {
|
||||
err := os.MkdirAll(velaHome, 0750)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error when create vela home directory")
|
||||
}
|
||||
}
|
||||
return filepath.Join(home, defaultVelaHome), nil
|
||||
return velaHome, nil
|
||||
}
|
||||
|
||||
// GetDefaultFrontendDir return default vela frontend dir
|
||||
@@ -81,22 +89,14 @@ func GetCapabilityDir() (string, error) {
|
||||
return filepath.Join(home, "capabilities"), nil
|
||||
}
|
||||
|
||||
// GetEnvDir return KubeVela environments dir
|
||||
func GetEnvDir() (string, error) {
|
||||
homedir, err := GetVelaHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(homedir, "envs"), nil
|
||||
}
|
||||
|
||||
// GetCurrentEnvPath return current env config
|
||||
func GetCurrentEnvPath() (string, error) {
|
||||
homedir, err := GetVelaHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(homedir, "curenv"), nil
|
||||
envPath := filepath.Join(homedir, "curenv")
|
||||
return envPath, nil
|
||||
}
|
||||
|
||||
// InitDirs create dir if not exits
|
||||
@@ -107,9 +107,6 @@ func InitDirs() error {
|
||||
if err := InitCapCenterDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := InitDefaultEnv(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -133,39 +130,6 @@ func InitCapabilityDir() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// EnvConfigName defines config
|
||||
const EnvConfigName = "config.json"
|
||||
|
||||
// InitDefaultEnv create dir if not exits
|
||||
func InitDefaultEnv() error {
|
||||
envDir, err := GetEnvDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultEnvDir := filepath.Join(envDir, types.DefaultEnvName)
|
||||
exist, err := CreateIfNotExist(defaultEnvDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist {
|
||||
return nil
|
||||
}
|
||||
data, _ := json.Marshal(&types.EnvMeta{Namespace: types.DefaultAppNamespace, Name: types.DefaultEnvName})
|
||||
//nolint:gosec
|
||||
if err = os.WriteFile(filepath.Join(defaultEnvDir, EnvConfigName), data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
curEnvPath, err := GetCurrentEnvPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:gosec
|
||||
if err = os.WriteFile(curEnvPath, []byte(types.DefaultEnvName), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateIfNotExist create dir if not exist
|
||||
func CreateIfNotExist(dir string) (bool, error) {
|
||||
_, err := os.Stat(dir)
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/config"
|
||||
"github.com/oam-dev/kubevela/pkg/builtin"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -64,16 +63,14 @@ type AppFile struct {
|
||||
Services map[string]Service `json:"services"`
|
||||
Secrets map[string]string `json:"secrets,omitempty"`
|
||||
|
||||
configGetter config.Store
|
||||
initialized bool
|
||||
initialized bool
|
||||
}
|
||||
|
||||
// NewAppFile init an empty AppFile struct
|
||||
func NewAppFile() *AppFile {
|
||||
return &AppFile{
|
||||
Services: make(map[string]Service),
|
||||
Secrets: make(map[string]string),
|
||||
configGetter: &config.Local{},
|
||||
Services: make(map[string]Service),
|
||||
Secrets: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,26 +155,10 @@ func (app *AppFile) BuildOAMApplication(env *types.EnvMeta, io cmdutil.IOStreams
|
||||
servApp.SetNamespace(env.Namespace)
|
||||
servApp.SetName(app.Name)
|
||||
servApp.Spec.Components = []common.ApplicationComponent{}
|
||||
if !silence {
|
||||
io.Infof("parsing application components")
|
||||
}
|
||||
for serviceName, svc := range app.GetServices() {
|
||||
if !silence {
|
||||
io.Infof("\nRendering configs for service (%s)...\n", serviceName)
|
||||
}
|
||||
configname := svc.GetUserConfigName()
|
||||
if configname != "" {
|
||||
configData, err := app.configGetter.GetConfigData(configname, env.Name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
decodedData, err := config.DecodeConfigFormat(configData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cm, err := config.ToConfigMap(app.configGetter, config.GenConfigMapName(app.Name, serviceName, configname), env.Name, decodedData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
auxiliaryObjects = append(auxiliaryObjects, cm)
|
||||
}
|
||||
comp, err := svc.RenderServiceToApplicationComponent(tm, serviceName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/config"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -137,7 +136,7 @@ func TestBuildOAMApplication2(t *testing.T) {
|
||||
In: os.Stdin,
|
||||
Out: os.Stdout,
|
||||
}, tm, false)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tcase.expectApp, o)
|
||||
}
|
||||
}
|
||||
@@ -168,19 +167,6 @@ services:
|
||||
cmd: ["node", "server.js"]
|
||||
`
|
||||
|
||||
yamlWithConfig := `name: myapp
|
||||
services:
|
||||
express-server:
|
||||
type: withconfig
|
||||
image: oamdev/testapp:v1
|
||||
cmd: ["node", "server.js"]
|
||||
route:
|
||||
domain: example.com
|
||||
http:
|
||||
"/": 8080
|
||||
config: test
|
||||
`
|
||||
|
||||
templateWebservice := `parameter: #webservice
|
||||
#webservice: {
|
||||
cmd: [...string]
|
||||
@@ -216,25 +202,6 @@ output: {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}`
|
||||
templateWithConfig := `parameter: #withconfig
|
||||
#withconfig: {
|
||||
cmd: [...string]
|
||||
image: string
|
||||
}
|
||||
|
||||
output: {
|
||||
apiVersion: "test.oam.dev/v1"
|
||||
kind: "WebService"
|
||||
metadata: {
|
||||
name: context.name
|
||||
}
|
||||
spec: {
|
||||
image: parameter.image
|
||||
command: parameter.cmd
|
||||
env: context.config
|
||||
}
|
||||
}
|
||||
`
|
||||
templateRoute := `parameter: #route
|
||||
#route: {
|
||||
domain: string
|
||||
@@ -324,22 +291,6 @@ outputs: ingress: {
|
||||
// TODO application 那边补测试:
|
||||
// 2. 1对多的情况,多对1 的情况
|
||||
|
||||
fakeConfigData2 := []map[string]string{{
|
||||
"name": "test",
|
||||
"value": "test-value",
|
||||
}}
|
||||
|
||||
ac3cm := &corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"test": "test-value",
|
||||
},
|
||||
}
|
||||
ac3cm.SetName("kubevela-myapp-express-server-test")
|
||||
|
||||
health := &v1alpha2.HealthScope{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: v1alpha2.HealthScopeGroupVersionKind.GroupVersion().String(),
|
||||
@@ -402,21 +353,6 @@ outputs: ingress: {
|
||||
err: ErrImageNotDefined,
|
||||
},
|
||||
},
|
||||
"config data should be set, add return configmap objects": {
|
||||
args: args{
|
||||
appfileData: yamlWithConfig,
|
||||
workloadTemplates: map[string]string{
|
||||
"withconfig": templateWithConfig,
|
||||
},
|
||||
traitTemplates: map[string]string{
|
||||
"route": templateRoute,
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
app: ac3,
|
||||
objs: []oam.Object{ac3cm, health},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
@@ -424,9 +360,6 @@ outputs: ingress: {
|
||||
t.Run(caseName, func(t *testing.T) {
|
||||
|
||||
app := NewAppFile()
|
||||
app.configGetter = &config.Fake{
|
||||
Data: fakeConfigData2,
|
||||
}
|
||||
err := yaml.Unmarshal([]byte(c.args.appfileData), app)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -84,16 +84,6 @@ func LoadApplication(namespace, appName string, c common.Args) (*v1beta1.Applica
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// Delete will delete an app along with it's appfile.
|
||||
func Delete(envName, appName string) error {
|
||||
return GetStorage().Delete(envName, appName)
|
||||
}
|
||||
|
||||
// Save will save appfile into default dir.
|
||||
func Save(app *api.Application, envName string) error {
|
||||
return GetStorage().Save(app, envName)
|
||||
}
|
||||
|
||||
// GetComponents will get oam components from Appfile.
|
||||
func GetComponents(app *v1beta1.Application) []string {
|
||||
var components []string
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
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 driver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// ConfigMapDriverName is local storage driver name
|
||||
const ConfigMapDriverName = "ConfigMap"
|
||||
|
||||
// ConfigMap Storage
|
||||
type ConfigMap struct {
|
||||
api.Driver
|
||||
}
|
||||
|
||||
// NewConfigMapStorage get storage client of ConfigMap type
|
||||
func NewConfigMapStorage() *ConfigMap {
|
||||
return &ConfigMap{}
|
||||
}
|
||||
|
||||
// Name of local storage
|
||||
func (c *ConfigMap) Name() string {
|
||||
return ConfigMapDriverName
|
||||
}
|
||||
|
||||
// List applications from configmap storage
|
||||
func (c *ConfigMap) List(envName string) ([]*api.Application, error) {
|
||||
// TODO support configmap storage
|
||||
return nil, errors.New("not implement")
|
||||
}
|
||||
|
||||
// Save applications from configmap storage
|
||||
func (c *ConfigMap) Save(app *api.Application, envName string) error {
|
||||
// TODO support configmap storage
|
||||
return errors.New("not implement")
|
||||
}
|
||||
|
||||
// Delete applications from configmap storage
|
||||
func (c *ConfigMap) Delete(envName, appName string) error {
|
||||
// TODO support configmap storage
|
||||
return errors.New("not implement")
|
||||
}
|
||||
|
||||
// Get applications from configmap storage
|
||||
func (c *ConfigMap) Get(envName, appName string) (*api.Application, error) {
|
||||
// TODO support configmap storage
|
||||
return nil, errors.New("not implement")
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
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 driver
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
func TestConfigMapDelete(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
appName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &ConfigMap{}
|
||||
if err := c.Delete(tt.args.envName, tt.args.appName); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMapGet(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
appName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *api.Application
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &ConfigMap{}
|
||||
got, err := c.Get(tt.args.envName, tt.args.appName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Get() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMapList(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*api.Application
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &ConfigMap{}
|
||||
got, err := c.List(tt.args.envName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("List() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("List() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMapName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &ConfigMap{}
|
||||
if got := c.Name(); got != tt.want {
|
||||
t.Errorf("Name() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMapSave(t *testing.T) {
|
||||
type args struct {
|
||||
app *api.Application
|
||||
envName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &ConfigMap{}
|
||||
if err := c.Save(tt.args.app, tt.args.envName); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Save() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
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 driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// LocalDriverName is local storage driver name
|
||||
const LocalDriverName = "Local"
|
||||
|
||||
// Local Storage
|
||||
type Local struct {
|
||||
api.Driver
|
||||
}
|
||||
|
||||
// NewLocalStorage get storage client of Local type
|
||||
func NewLocalStorage() *Local {
|
||||
return &Local{}
|
||||
}
|
||||
|
||||
// Name is local storage driver name
|
||||
func (l *Local) Name() string {
|
||||
return LocalDriverName
|
||||
}
|
||||
|
||||
// Save application from local storage
|
||||
func (l *Local) Save(app *api.Application, envName string) error {
|
||||
appDir, err := getApplicationDir(envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if app.CreateTime.IsZero() {
|
||||
app.CreateTime = time.Now()
|
||||
}
|
||||
app.UpdateTime = time.Now()
|
||||
out, err := yaml.Marshal(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:gosec
|
||||
return os.WriteFile(filepath.Join(appDir, app.Name+".yaml"), out, 0644)
|
||||
}
|
||||
|
||||
// Delete application from local storage
|
||||
func (l *Local) Delete(envName, appName string) error {
|
||||
appDir, err := getApplicationDir(envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(filepath.Join(appDir, appName+".yaml"))
|
||||
}
|
||||
|
||||
func getApplicationDir(envName string) (string, error) {
|
||||
appDir := filepath.Join(env.GetEnvDirByName(envName), "applications")
|
||||
_, err := system.CreateIfNotExist(appDir)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("getting application directory from env %s failed, error: %w ", envName, err)
|
||||
}
|
||||
return appDir, err
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
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 driver
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
var dir string
|
||||
var afile *api.AppFile
|
||||
var appName = "testsvc"
|
||||
var envName = "default"
|
||||
|
||||
func init() {
|
||||
dir, _ = getApplicationDir(envName)
|
||||
afile = api.NewAppFile()
|
||||
afile.Name = appName
|
||||
svcs := make(map[string]api.Service)
|
||||
svcs["wordpress"] = map[string]interface{}{
|
||||
"type": "webservice",
|
||||
"image": "wordpress:php7.4-apache",
|
||||
"port": "80",
|
||||
"cpu": "1",
|
||||
"route": "",
|
||||
}
|
||||
afile.Services = svcs
|
||||
out, _ := yaml.Marshal(afile)
|
||||
_ = os.WriteFile(filepath.Join(dir, appName+".yaml"), out, 0644)
|
||||
}
|
||||
|
||||
func TestLocalDelete(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
appName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"testLocalDelete1", args{envName: envName, appName: appName}, false},
|
||||
{"testLocalDelete2", args{envName: envName, appName: "test"}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
l := &Local{}
|
||||
if err := l.Delete(tt.args.envName, tt.args.appName); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalSave(t *testing.T) {
|
||||
type args struct {
|
||||
app *api.Application
|
||||
envName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"TestLocal_Save1", args{&api.Application{AppFile: afile, Tm: nil}, envName}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
l := &Local{}
|
||||
if err := l.Save(tt.args.app, tt.args.envName); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Save() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{"testDriverName", "Local"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
l := &Local{}
|
||||
if got := l.Name(); got != tt.want {
|
||||
t.Errorf("Name() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLocalStorage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want *Local
|
||||
}{
|
||||
{"testNewLocal", &Local{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := NewLocalStorage(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("NewLocalStorage() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetApplicationDir(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{"testGetApplicationDir", args{envName: envName}, "/envs/default/applications", false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := getApplicationDir(tt.args.envName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("getApplicationDir() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !strings.Contains(got, tt.want) {
|
||||
t.Errorf("getApplicationDir() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
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 appfile
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
"github.com/oam-dev/kubevela/references/appfile/driver"
|
||||
)
|
||||
|
||||
// Store application store client
|
||||
var store *Storage
|
||||
|
||||
// Storage is common storage client,use it to get app and others resource
|
||||
type Storage struct {
|
||||
api.Driver
|
||||
}
|
||||
|
||||
// GetStorage will create storage driver from the system environment of "STORAGE_DRIVER"
|
||||
func GetStorage() *Storage {
|
||||
driverName := os.Getenv(system.StorageDriverEnv)
|
||||
if store == nil || store.Name() != driverName {
|
||||
switch driverName {
|
||||
// TODO mutli implement Storage
|
||||
case driver.ConfigMapDriverName:
|
||||
store = &Storage{driver.NewConfigMapStorage()}
|
||||
case driver.LocalDriverName:
|
||||
store = &Storage{driver.NewLocalStorage()}
|
||||
default:
|
||||
store = &Storage{driver.NewLocalStorage()}
|
||||
}
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
// Save application storage common implement
|
||||
func (s *Storage) Save(app *api.Application, envName string) error {
|
||||
return s.Driver.Save(app, envName)
|
||||
}
|
||||
|
||||
// Delete application storage common implement
|
||||
func (s *Storage) Delete(envName, appName string) error {
|
||||
return s.Driver.Delete(envName, appName)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
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 appfile
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/references/appfile/driver"
|
||||
)
|
||||
|
||||
func TestGetStorage(t *testing.T) {
|
||||
_ = os.Setenv(system.StorageDriverEnv, driver.ConfigMapDriverName)
|
||||
|
||||
store := &Storage{driver.NewConfigMapStorage()}
|
||||
tests := []struct {
|
||||
name string
|
||||
want *Storage
|
||||
}{
|
||||
{name: "TestGetStorage_ConfigMap", want: store},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetStorage(); got.Name() != tt.want.Name() {
|
||||
t.Errorf("GetStorage() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func NewCapUninstallCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.
|
||||
}
|
||||
name = l[1]
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func NewCapListCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
if len(args) > 0 {
|
||||
repoName = args[0]
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ func NewCommand() *cobra.Command {
|
||||
NewPortForwardCommand(commandArgs, ioStream),
|
||||
NewLogsCommand(commandArgs, ioStream),
|
||||
NewEnvCommand(commandArgs, ioStream),
|
||||
NewConfigCommand(ioStream),
|
||||
|
||||
// Workflows
|
||||
NewWorkflowCommand(commandArgs, ioStream),
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewComponentsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Co
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
isDiscover, _ := cmd.Flags().GetBool("discover")
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/config"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
// Notes about config dir layout:
|
||||
// Under each env dir, there are individual files for each config.
|
||||
// The format is the same as k8s Secret.Data field with value base64 encoded.
|
||||
|
||||
// NewConfigCommand will create command for config management for AppFile
|
||||
func NewConfigCommand(io cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "config",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Manage configurations",
|
||||
Long: "Manage configurations",
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(io.Out)
|
||||
cmd.AddCommand(
|
||||
NewConfigListCommand(io),
|
||||
NewConfigGetCommand(io),
|
||||
NewConfigSetCommand(io),
|
||||
NewConfigDeleteCommand(io),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewConfigListCommand list all created configs
|
||||
func NewConfigListCommand(io cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Aliases: []string{"list"},
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "List configs",
|
||||
Long: "List all configs",
|
||||
Example: `vela config ls`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return ListConfigs(io, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(io.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getConfigDir(cmd *cobra.Command) (string, error) {
|
||||
e, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config.GetConfigsDir(e.Name)
|
||||
}
|
||||
|
||||
// ListConfigs will list all configs
|
||||
func ListConfigs(ioStreams cmdutil.IOStreams, cmd *cobra.Command) error {
|
||||
d, err := getConfigDir(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
table := newUITable()
|
||||
table.AddRow("NAME")
|
||||
cfgList, err := listConfigs(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range cfgList {
|
||||
table.AddRow(name)
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func listConfigs(dir string) ([]string, error) {
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := []string{}
|
||||
for _, f := range files {
|
||||
l = append(l, f.Name())
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// NewConfigGetCommand get config from local
|
||||
func NewConfigGetCommand(io cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "get",
|
||||
Aliases: []string{"get"},
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Get data for a config",
|
||||
Long: "Get data for a config",
|
||||
Example: `vela config get <config-name>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return getConfig(args, io, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(io.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
|
||||
e, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify config name, vela config get <name>")
|
||||
}
|
||||
configName := args[0]
|
||||
cfgData, err := config.ReadConfig(e.Name, configName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Infof("Data:\n")
|
||||
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
|
||||
for scanner.Scan() {
|
||||
k, v, err := config.ReadConfigLine(scanner.Text())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Infof(" %s: %s\n", k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewConfigSetCommand set a config data in local
|
||||
func NewConfigSetCommand(io cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set",
|
||||
Aliases: []string{"set"},
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Set data for a config",
|
||||
Long: "Set data for a config",
|
||||
Example: `vela config set <config-name> KEY=VALUE K2=V2`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return setConfig(args, io, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(io.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func setConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
|
||||
e, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envName := e.Name
|
||||
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify config name, vela config set <name> KEY=VALUE")
|
||||
}
|
||||
configName := args[0]
|
||||
|
||||
input := map[string]string{}
|
||||
for _, arg := range args[1:] {
|
||||
ss := strings.SplitN(arg, "=", 2)
|
||||
if len(ss) != 2 {
|
||||
return fmt.Errorf("KV argument malformed: %s, should be KEY=VALUE", arg)
|
||||
}
|
||||
k := strings.TrimSpace(ss[0])
|
||||
v := strings.TrimSpace(ss[1])
|
||||
if _, ok := input[k]; ok {
|
||||
return fmt.Errorf("KEY is not unique: %s", arg)
|
||||
}
|
||||
input[k] = v
|
||||
}
|
||||
|
||||
cfgData, err := config.ReadConfig(envName, configName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
io.Infof("reading existing config data and merging with user input\n")
|
||||
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
|
||||
for scanner.Scan() {
|
||||
k, v, err := config.ReadConfigLine(scanner.Text())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input[k] = v
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
for k, v := range input {
|
||||
vEnc := b64.StdEncoding.EncodeToString([]byte(v))
|
||||
out.WriteString(fmt.Sprintf("%s: %s\n", k, vEnc))
|
||||
}
|
||||
err = config.WriteConfig(envName, configName, out.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Infof("config data saved successfully %s\n", emojiSucceed)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewConfigDeleteCommand delete a config from local
|
||||
func NewConfigDeleteCommand(io cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "del",
|
||||
Aliases: []string{"del"},
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Delete config",
|
||||
Long: "Delete config",
|
||||
Example: `vela config del <config-name>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return deleteConfig(args, io, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(io.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func deleteConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
|
||||
e, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify config name, vela config get <name>")
|
||||
}
|
||||
configName := args[0]
|
||||
err = config.DeleteConfig(e.Name, configName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Infof("config (%s) deleted successfully\n", configName)
|
||||
return nil
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestConfigCommand(t *testing.T) {
|
||||
// Set VELA_HOME to local
|
||||
assert.NoError(t, os.Setenv(system.VelaHomeEnv, ".test_vela"))
|
||||
home, err := system.GetVelaHomeDir()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, strings.HasSuffix(home, ".test_vela"))
|
||||
defer os.RemoveAll(home)
|
||||
|
||||
// Create Default Env
|
||||
err = system.InitDefaultEnv()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// vela config set test a=b
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
err = setConfig([]string{"test", "a=b"}, io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// vela config get test
|
||||
var b bytes.Buffer
|
||||
io.Out = &b
|
||||
err = getConfig([]string{"test"}, io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "Data:\n a: b\n", b.String())
|
||||
|
||||
// vela config set test2 c=d
|
||||
io.Out = os.Stdout
|
||||
err = setConfig([]string{"test2", "c=d"}, io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// vela config ls
|
||||
b = bytes.Buffer{}
|
||||
io.Out = &b
|
||||
err = ListConfigs(io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "NAME \ntest \ntest2\n", b.String())
|
||||
|
||||
// vela config del test
|
||||
io.Out = os.Stdout
|
||||
err = deleteConfig([]string{"test"}, io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// vela config ls
|
||||
b = bytes.Buffer{}
|
||||
io.Out = &b
|
||||
err = ListConfigs(io, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "NAME \ntest2\n", b.String())
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func NewDeleteCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
|
||||
C: c,
|
||||
}
|
||||
o.Client = newClient
|
||||
o.Env, err = GetEnv(cmd)
|
||||
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func NewDryRunCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,17 +17,14 @@ limitations under the License.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
@@ -38,17 +35,20 @@ func NewEnvCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Manage environments",
|
||||
Long: "Manage environments",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.SetConfig()
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStream.Out)
|
||||
cmd.AddCommand(NewEnvListCommand(ioStream), NewEnvInitCommand(c, ioStream), NewEnvSetCommand(ioStream), NewEnvDeleteCommand(ioStream))
|
||||
cmd.AddCommand(NewEnvListCommand(c, ioStream), NewEnvInitCommand(c, ioStream), NewEnvSetCommand(c, ioStream), NewEnvDeleteCommand(c, ioStream))
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewEnvListCommand creates `env list` command for listing all environments
|
||||
func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
func NewEnvListCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Aliases: []string{"list"},
|
||||
@@ -57,6 +57,14 @@ func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
Long: "List all environments",
|
||||
Example: `vela env ls [env-name]`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clt, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = common.SetGlobalClient(clt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ListEnvs(args, ioStream)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
@@ -70,23 +78,22 @@ func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
// NewEnvInitCommand creates `env init` command for initializing environments
|
||||
func NewEnvInitCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var envArgs types.EnvMeta
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "init <envName>",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Create environments",
|
||||
Long: "Create environment and set the currently using environment",
|
||||
Example: `vela env init test --namespace test --email my@email.com`,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.SetConfig()
|
||||
},
|
||||
Example: `vela env init test --namespace test`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := c.GetClient()
|
||||
clt, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CreateOrUpdateEnv(ctx, newClient, &envArgs, args, ioStreams)
|
||||
err = common.SetGlobalClient(clt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return CreateEnv(&envArgs, args, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
@@ -94,14 +101,11 @@ func NewEnvInitCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
|
||||
}
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "", "specify K8s namespace for env")
|
||||
cmd.Flags().StringVar(&envArgs.Email, "email", "", "specify email for production TLS Certificate notification")
|
||||
cmd.Flags().StringVar(&envArgs.Domain, "domain", "", "specify domain your applications")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewEnvDeleteCommand creates `env delete` command for deleting environments
|
||||
func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
ctx := context.Background()
|
||||
func NewEnvDeleteCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -109,7 +113,15 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
Long: "Delete environment",
|
||||
Example: `vela env delete test`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return DeleteEnv(ctx, args, ioStreams)
|
||||
clt, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = common.SetGlobalClient(clt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return DeleteEnv(args, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
@@ -120,7 +132,7 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
}
|
||||
|
||||
// NewEnvSetCommand creates `env set` command for setting current environment
|
||||
func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
func NewEnvSetCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set",
|
||||
Aliases: []string{"sw"},
|
||||
@@ -129,6 +141,14 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
Long: "Set an environment as the current using one",
|
||||
Example: `vela env set test`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clt, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = common.SetGlobalClient(clt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return SetEnv(args, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
@@ -142,7 +162,7 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
// ListEnvs shows info of all environments
|
||||
func ListEnvs(args []string, ioStreams cmdutil.IOStreams) error {
|
||||
table := newUITable()
|
||||
table.AddRow("NAME", "CURRENT", "NAMESPACE", "EMAIL", "DOMAIN")
|
||||
table.AddRow("NAME", "NAMESPACE", "CURRENT")
|
||||
var envName = ""
|
||||
if len(args) > 0 {
|
||||
envName = args[0]
|
||||
@@ -152,14 +172,14 @@ func ListEnvs(args []string, ioStreams cmdutil.IOStreams) error {
|
||||
return err
|
||||
}
|
||||
for _, env := range envList {
|
||||
table.AddRow(env.Name, env.Current, env.Namespace, env.Email, env.Domain)
|
||||
table.AddRow(env.Name, env.Namespace, env.Current)
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteEnv deletes an environment
|
||||
func DeleteEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
|
||||
func DeleteEnv(args []string, ioStreams cmdutil.IOStreams) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("you must specify environment name for 'vela env delete' command")
|
||||
}
|
||||
@@ -173,18 +193,18 @@ func DeleteEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateEnv creates or updates an environment
|
||||
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvMeta, args []string, ioStreams cmdutil.IOStreams) error {
|
||||
// CreateEnv creates an environment
|
||||
func CreateEnv(envArgs *types.EnvMeta, args []string, ioStreams cmdutil.IOStreams) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("you must specify environment name for 'vela env init' command")
|
||||
}
|
||||
envName := args[0]
|
||||
envArgs.Name = envName
|
||||
msg, err := env.CreateOrUpdateEnv(ctx, c, envName, envArgs)
|
||||
err := env.CreateEnv(envName, envArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ioStreams.Info(msg)
|
||||
ioStreams.Infof("environment %s created\n", envName)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -202,26 +222,23 @@ func SetEnv(args []string, ioStreams cmdutil.IOStreams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEnv gets environment by name or current environment
|
||||
// GetFlagEnvOrCurrent gets environment by name or current environment
|
||||
// if no env exists, then init default environment
|
||||
func GetEnv(cmd *cobra.Command) (*types.EnvMeta, error) {
|
||||
func GetFlagEnvOrCurrent(cmd *cobra.Command, args common.Args) (*types.EnvMeta, error) {
|
||||
clt, err := args.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = common.SetGlobalClient(clt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get flag env fail")
|
||||
}
|
||||
var envName string
|
||||
var err error
|
||||
if cmd != nil {
|
||||
envName = cmd.Flag("env").Value.String()
|
||||
}
|
||||
if envName != "" {
|
||||
return env.GetEnvByName(envName)
|
||||
}
|
||||
envName, err = env.GetCurrentEnvName()
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if err = system.InitDefaultEnv(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
envName = types.DefaultEnvName
|
||||
}
|
||||
return env.GetEnvByName(envName)
|
||||
return env.GetCurrentEnv()
|
||||
}
|
||||
|
||||
@@ -17,108 +17,19 @@ limitations under the License.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestENV(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
assert.NoError(t, os.Setenv(system.VelaHomeEnv, ".test_vela"))
|
||||
home, err := system.GetVelaHomeDir()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, strings.HasSuffix(home, ".test_vela"))
|
||||
defer os.RemoveAll(home)
|
||||
// Create Default Env
|
||||
err = system.InitDefaultEnv()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check and compare create default env success
|
||||
curEnvName, err := env.GetCurrentEnvName()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "default", curEnvName)
|
||||
gotEnv, err := GetEnv(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &types.EnvMeta{
|
||||
Namespace: "default",
|
||||
Name: "default",
|
||||
}, gotEnv)
|
||||
|
||||
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
exp := &types.EnvMeta{
|
||||
Namespace: "test1",
|
||||
Name: "env1",
|
||||
}
|
||||
client := test.NewMockClient()
|
||||
// Create env1
|
||||
err = CreateOrUpdateEnv(ctx, client, exp, []string{"env1"}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check and compare create env success
|
||||
curEnvName, err = env.GetCurrentEnvName()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "env1", curEnvName)
|
||||
gotEnv, err = GetEnv(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, exp, gotEnv)
|
||||
|
||||
// List all env
|
||||
var b bytes.Buffer
|
||||
ioStream.Out = &b
|
||||
err = ListEnvs([]string{}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "NAME \tCURRENT\tNAMESPACE\tEMAIL\tDOMAIN\ndefault\t \tdefault \t \t \nenv1 \t* \ttest1 \t \t \n", b.String())
|
||||
b.Reset()
|
||||
err = ListEnvs([]string{"env1"}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "NAME\tCURRENT\tNAMESPACE\tEMAIL\tDOMAIN\nenv1\t \ttest1 \t \t \n", b.String())
|
||||
ioStream.Out = os.Stdout
|
||||
|
||||
// can not delete current env
|
||||
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
|
||||
assert.Error(t, err)
|
||||
|
||||
// set as default env
|
||||
err = SetEnv([]string{"default"}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check env set success
|
||||
gotEnv, err = GetEnv(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &types.EnvMeta{
|
||||
Namespace: "default",
|
||||
Name: "default",
|
||||
}, gotEnv)
|
||||
|
||||
// delete env
|
||||
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// can not set as a non-exist env
|
||||
err = SetEnv([]string{"env1"}, ioStream)
|
||||
assert.Error(t, err)
|
||||
|
||||
// set success
|
||||
err = SetEnv([]string{"default"}, ioStream)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestEnvInitCommandPersistentPreRunE(t *testing.T) {
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := common.Args{}
|
||||
cmd := NewEnvInitCommand(fakeC, io)
|
||||
assert.Nil(t, cmd.PersistentPreRunE(new(cobra.Command), []string{}))
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func (o *VelaExecOptions) Init(ctx context.Context, c *cobra.Command, argsIn []s
|
||||
o.Cmd = c
|
||||
o.Args = argsIn
|
||||
|
||||
env, err := GetEnv(o.Cmd)
|
||||
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
// NewExportCommand will create command for exporting deploy manifests from an AppFile
|
||||
func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
appFilePath := new(string)
|
||||
cmd := &cobra.Command{
|
||||
Use: "export",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -36,7 +37,7 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -44,11 +45,7 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
|
||||
IO: ioStream,
|
||||
Env: velaEnv,
|
||||
}
|
||||
filePath, err := cmd.Flags().GetString(appFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, data, err := o.Export(filePath, velaEnv.Namespace, true, c)
|
||||
_, data, err := o.Export(*appFilePath, velaEnv.Namespace, true, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -58,6 +55,6 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
|
||||
}
|
||||
cmd.SetOut(ioStream.Out)
|
||||
|
||||
cmd.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")
|
||||
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/fatih/color"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -72,7 +73,7 @@ func NewInitCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
return err
|
||||
}
|
||||
o.client = newClient
|
||||
o.Env, err = GetEnv(cmd)
|
||||
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -146,27 +147,8 @@ func (o *appInitOptions) CheckEnv() error {
|
||||
if o.Env.Namespace == "" {
|
||||
o.Env.Namespace = "default"
|
||||
}
|
||||
o.Infof("Environment: %s, namespace: %s\n\n", o.Env.Name, o.Env.Namespace)
|
||||
if o.Env.Domain == "" {
|
||||
prompt := &survey.Input{
|
||||
Message: "What is the domain of your application service (optional): ",
|
||||
}
|
||||
err := survey.AskOne(prompt, &o.Env.Domain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read domain err %w", err)
|
||||
}
|
||||
}
|
||||
if o.Env.Email == "" {
|
||||
prompt := &survey.Input{
|
||||
Message: "What is your email (optional, used to generate certification): ",
|
||||
}
|
||||
err := survey.AskOne(prompt, &o.Env.Email)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read email err %w", err)
|
||||
}
|
||||
}
|
||||
if _, err := env.CreateOrUpdateEnv(context.Background(), o.client, o.Env.Name, o.Env); err != nil {
|
||||
return err
|
||||
if err := env.CreateEnv(o.Env.Name, o.Env); err != nil {
|
||||
return errors.Wrap(err, "app init create namespace err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func NewLiveDiffCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func NewLogsCommand(c common.Args, ioStreams util.IOStreams) *cobra.Command {
|
||||
ioStreams.Errorf("please specify app name")
|
||||
return nil
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func NewListCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ func (o *VelaPortForwardOptions) Init(ctx context.Context, cmd *cobra.Command, a
|
||||
o.Cmd = cmd
|
||||
o.Args = argsIn
|
||||
|
||||
env, err := GetEnv(o.Cmd)
|
||||
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func NewCapabilityShowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra
|
||||
}
|
||||
ctx := context.Background()
|
||||
capabilityName := args[0]
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func NewAppStatusCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
ioStreams.Errorf("Error: failed to get Env: %s", err)
|
||||
return err
|
||||
|
||||
@@ -50,7 +50,7 @@ func NewTraitsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
isDiscover, _ := cmd.Flags().GetBool("discover")
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -31,12 +31,9 @@ import (
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
)
|
||||
|
||||
var (
|
||||
appFilePath string
|
||||
)
|
||||
|
||||
// NewUpCommand will create command for applying an AppFile
|
||||
func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
appFilePath := new(string)
|
||||
cmd := &cobra.Command{
|
||||
Use: "up",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -49,7 +46,7 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -57,11 +54,7 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filePath, err := cmd.Flags().GetString(appFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileContent, err := os.ReadFile(filepath.Clean(filePath))
|
||||
fileContent, err := os.ReadFile(filepath.Clean(*appFilePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,12 +74,12 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
IO: ioStream,
|
||||
Env: velaEnv,
|
||||
}
|
||||
return o.Run(filePath, velaEnv.Namespace, c)
|
||||
return o.Run(*appFilePath, velaEnv.Namespace, c)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStream.Out)
|
||||
cmd.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")
|
||||
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify application name")
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify application name")
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -148,7 +148,7 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify application name")
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -187,7 +187,7 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify application name")
|
||||
}
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func NewWorkloadsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Com
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
env, err := GetEnv(cmd)
|
||||
env, err := GetFlagEnvOrCurrent(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -209,9 +209,6 @@ func RetrieveApplicationStatusByName(ctx context.Context, c client.Reader, appli
|
||||
|
||||
// DeleteApp will delete app including server side
|
||||
func (o *DeleteOptions) DeleteApp() (string, error) {
|
||||
if err := appfile.Delete(o.Env.Name, o.AppName); err != nil && !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
ctx := context.Background()
|
||||
var app = new(corev1beta1.Application)
|
||||
err := o.Client.Get(ctx, client.ObjectKey{Name: o.AppName, Namespace: o.Env.Namespace}, app)
|
||||
@@ -443,9 +440,6 @@ func (o *AppfileOptions) Run(filePath, namespace string, c common.Args) error {
|
||||
|
||||
// BaseAppFileRun starts an application according to Appfile
|
||||
func (o *AppfileOptions) BaseAppFileRun(result *BuildResult, args common.Args) error {
|
||||
if err := o.saveToAppDir(result.appFile); err != nil {
|
||||
return errors.Wrap(err, "save to app dir failed")
|
||||
}
|
||||
|
||||
kubernetesComponent, err := appfile.ApplyTerraform(result.application, o.Kubecli, o.IO, o.Env.Namespace, args)
|
||||
if err != nil {
|
||||
@@ -457,11 +451,6 @@ func (o *AppfileOptions) BaseAppFileRun(result *BuildResult, args common.Args) e
|
||||
return o.ApplyApp(result.application, result.scopes)
|
||||
}
|
||||
|
||||
func (o *AppfileOptions) saveToAppDir(f *api.AppFile) error {
|
||||
app := &api.Application{AppFile: f}
|
||||
return appfile.Save(app, o.Env.Name)
|
||||
}
|
||||
|
||||
// ApplyApp applys config resources for the app.
|
||||
// It differs by create and update:
|
||||
// - for create, it displays app status along with information of url, metrics, ssh, logging.
|
||||
|
||||
@@ -139,5 +139,5 @@ func BaseComplete(env *types.EnvMeta, c common.Args, workloadName string, appNam
|
||||
if err = appfile.SetWorkload(app, workloadName, tp, workloadData); err != nil {
|
||||
return app, err
|
||||
}
|
||||
return app, appfile.Save(app, env.Name)
|
||||
return app, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user