mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-18 20:17:04 +00:00
Merge pull request #1174 from wonderflow/cli
align cli to the application object
This commit is contained in:
@@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
)
|
||||
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
type Args struct {
|
||||
Config *rest.Config
|
||||
Schema *runtime.Scheme
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// SetConfig insert kubeconfig into Args
|
||||
@@ -21,3 +23,21 @@ func (a *Args) SetConfig() error {
|
||||
a.Config = restConf
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClient get client if exist
|
||||
func (a *Args) GetClient() (client.Client, error) {
|
||||
if a.Config == nil {
|
||||
if err := a.SetConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if a.Client != nil {
|
||||
return a.Client, nil
|
||||
}
|
||||
newClient, err := client.New(a.Config, client.Options{Scheme: a.Schema})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.Client = newClient
|
||||
return a.Client, nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ type Capability struct {
|
||||
CueTemplate string `json:"template,omitempty"`
|
||||
CueTemplateURI string `json:"templateURI,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
DefinitionPath string `json:"definition"`
|
||||
CrdName string `json:"crdName,omitempty"`
|
||||
Center string `json:"center,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
@@ -52,6 +51,9 @@ type Capability struct {
|
||||
// trait only
|
||||
AppliesTo []string `json:"appliesTo,omitempty"`
|
||||
|
||||
// Namespace represents it's a system-level or user-level capability.
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
|
||||
// Plugin Source
|
||||
Source *Source `json:"source,omitempty"`
|
||||
Install *Installation `json:"install,omitempty"`
|
||||
|
||||
@@ -136,7 +136,7 @@ var (
|
||||
ginkgo.It("should list all applications", func() {
|
||||
output, err := Exec("vela ls")
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("SERVICE"))
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("COMPONENT"))
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(applicationName))
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(workloadType))
|
||||
if traitAlias != "" {
|
||||
|
||||
@@ -83,7 +83,6 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
appParser := appfile.NewApplicationParser(r.Client, r.dm)
|
||||
|
||||
ctx = oamutil.SetNamespaceInCtx(ctx, app.Namespace)
|
||||
|
||||
appfile, err := appParser.GenerateAppFile(ctx, app.Name, app)
|
||||
if err != nil {
|
||||
applog.Error(err, "[Handle Parse]")
|
||||
|
||||
+2
-8
@@ -3,8 +3,6 @@ package cue
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
@@ -16,13 +14,9 @@ import (
|
||||
const specValue = "parameter"
|
||||
|
||||
// GetParameters get parameter from cue template
|
||||
func GetParameters(templatePath string) ([]types.Parameter, error) {
|
||||
func GetParameters(templateStr string) ([]types.Parameter, error) {
|
||||
r := cue.Runtime{}
|
||||
b, err := ioutil.ReadFile(filepath.Clean(templatePath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
template, err := r.Compile("", string(b)+BaseTemplate)
|
||||
template, err := r.Compile("", templateStr+BaseTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cue
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
@@ -10,7 +11,8 @@ import (
|
||||
)
|
||||
|
||||
func TestGetParameter(t *testing.T) {
|
||||
params, err := GetParameters("testdata/workloads/metrics.cue")
|
||||
data, _ := ioutil.ReadFile("testdata/workloads/metrics.cue")
|
||||
params, err := GetParameters(string(data))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, params, []types.Parameter{
|
||||
{Name: "format", Required: false, Default: "prometheus", Usage: "format of the metrics, " +
|
||||
@@ -19,8 +21,8 @@ func TestGetParameter(t *testing.T) {
|
||||
{Name: "port", Required: false, Default: int64(8080), Type: cue.IntKind},
|
||||
{Name: "selector", Required: false, Usage: "the label selector for the pods, default is the workload labels", Type: cue.StructKind},
|
||||
})
|
||||
|
||||
params, err = GetParameters("testdata/workloads/deployment.cue")
|
||||
data, _ = ioutil.ReadFile("testdata/workloads/deployment.cue")
|
||||
params, err = GetParameters(string(data))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.Parameter{
|
||||
{Name: "name", Required: true, Default: "", Type: cue.StringKind},
|
||||
@@ -31,7 +33,8 @@ func TestGetParameter(t *testing.T) {
|
||||
{Name: "cpu", Short: "", Required: false, Usage: "", Default: "", Type: cue.StringKind}},
|
||||
params)
|
||||
|
||||
params, err = GetParameters("testdata/workloads/test-param.cue")
|
||||
data, _ = ioutil.ReadFile("testdata/workloads/test-param.cue")
|
||||
params, err = GetParameters(string(data))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.Parameter{
|
||||
{Name: "name", Required: true, Default: "", Type: cue.StringKind},
|
||||
@@ -41,7 +44,8 @@ func TestGetParameter(t *testing.T) {
|
||||
{Name: "enable", Default: false, Type: cue.BoolKind},
|
||||
{Name: "fval", Default: 64.3, Type: cue.FloatKind},
|
||||
{Name: "nval", Default: float64(0), Required: true, Type: cue.NumberKind}}, params)
|
||||
params, err = GetParameters("testdata/workloads/empty.cue")
|
||||
data, _ = ioutil.ReadFile("testdata/workloads/empty.cue")
|
||||
params, err = GetParameters(string(data))
|
||||
assert.NoError(t, err)
|
||||
var exp []types.Parameter
|
||||
assert.Equal(t, exp, params)
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
@@ -17,9 +15,9 @@ import (
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
@@ -39,7 +37,7 @@ func Install(ioStreams cmdutil.IOStreams, repoName, repoURL, chartName, version,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeClient, err := client.New(args.Config, client.Options{Scheme: args.Schema})
|
||||
kubeClient, err := args.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ type APIServer struct {
|
||||
server *http.Server
|
||||
KubeClient client.Client
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
c types.Args
|
||||
}
|
||||
|
||||
// New will create APIServer
|
||||
func New(c types.Args, port, staticPath string) (*APIServer, error) {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -33,6 +34,7 @@ func New(c types.Args, port, staticPath string) (*APIServer, error) {
|
||||
s := &APIServer{
|
||||
KubeClient: newClient,
|
||||
dm: dm,
|
||||
c: c,
|
||||
}
|
||||
server := &http.Server{
|
||||
Addr: port,
|
||||
|
||||
@@ -107,7 +107,7 @@ func (s *APIServer) CreateApplication(c *gin.Context) {
|
||||
IO: ioStream,
|
||||
Env: env,
|
||||
}
|
||||
buildResult, data, err := o.ExportFromAppFile(&body, false)
|
||||
buildResult, data, err := o.ExportFromAppFile(&body, env.Namespace, false, s.c)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
|
||||
@@ -63,7 +63,8 @@ func (s *APIServer) DeleteCapabilityCenter(c *gin.Context) {
|
||||
// RemoveCapabilityFromCluster remove a specific capability from cluster
|
||||
func (s *APIServer) RemoveCapabilityFromCluster(c *gin.Context) {
|
||||
capabilityCenterName := c.Param("capabilityName")
|
||||
msg, err := common.RemoveCapabilityFromCluster(s.KubeClient, capabilityCenterName)
|
||||
// TODO get namespace from env
|
||||
msg, err := common.RemoveCapabilityFromCluster("default", s.c, s.KubeClient, capabilityCenterName)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
@@ -74,7 +75,7 @@ func (s *APIServer) RemoveCapabilityFromCluster(c *gin.Context) {
|
||||
// ListCapabilities lists capabilities of a capability center
|
||||
func (s *APIServer) ListCapabilities(c *gin.Context) {
|
||||
capabilityCenterName := c.Param("capabilityName")
|
||||
capabilityList, err := common.ListCapabilities(capabilityCenterName)
|
||||
capabilityList, err := common.ListCapabilities("default", s.c, capabilityCenterName)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/pflag"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
env2 "github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
util2 "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/apiserver/apis"
|
||||
"github.com/oam-dev/kubevela/references/apiserver/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
// AttachTrait attaches a trait to a component
|
||||
@@ -30,13 +20,8 @@ func (s *APIServer) AttachTrait(c *gin.Context) {
|
||||
util.HandleError(c, util.InvalidArgument, "the trait attach request body is invalid")
|
||||
return
|
||||
}
|
||||
ctrl.Log.Info("request parameters body:", "body", body)
|
||||
msg, err := s.DoAttachTrait(c, body)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
util.AssembleResponse(c, msg, nil)
|
||||
|
||||
util.AssembleResponse(c, "deprecated, please use appfile to update", nil)
|
||||
}
|
||||
|
||||
// GetTrait gets a trait by name
|
||||
@@ -46,7 +31,7 @@ func (s *APIServer) GetTrait(c *gin.Context) {
|
||||
var capability types.Capability
|
||||
var err error
|
||||
|
||||
if capability, err = common.GetTraitDefinition(&workloadType, traitType); err != nil {
|
||||
if capability, err = common.GetTraitDefinition("default", s.c, &workloadType, traitType); err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
@@ -58,7 +43,7 @@ func (s *APIServer) ListTrait(c *gin.Context) {
|
||||
var traitList []types.Capability
|
||||
var workloadName string
|
||||
var err error
|
||||
if traitList, err = common.ListTraitDefinitions(&workloadName); err != nil {
|
||||
if traitList, err = common.ListTraitDefinitions("default", s.c, &workloadName); err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
@@ -67,77 +52,5 @@ func (s *APIServer) ListTrait(c *gin.Context) {
|
||||
|
||||
// DetachTrait detaches a trait from a component
|
||||
func (s *APIServer) DetachTrait(c *gin.Context) {
|
||||
envName := c.Param("envName")
|
||||
traitType := c.Param("traitName")
|
||||
componentName := c.Param("compName")
|
||||
applicationName := c.Param("appName")
|
||||
|
||||
var staging = false
|
||||
var err error
|
||||
if stagingStr := c.Param("staging"); stagingStr != "" {
|
||||
if staging, err = strconv.ParseBool(stagingStr); err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
msg, err := s.DoDetachTrait(c, envName, traitType, componentName, applicationName, staging)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
util.AssembleResponse(c, msg, nil)
|
||||
}
|
||||
|
||||
// DoAttachTrait executes attaching trait operation
|
||||
func (s *APIServer) DoAttachTrait(c context.Context, body apis.TraitBody) (string, error) {
|
||||
// Prepare
|
||||
var appObj *api.Application
|
||||
fs := pflag.NewFlagSet("trait", pflag.ContinueOnError)
|
||||
for _, f := range body.Flags {
|
||||
fs.String(f.Name, f.Value, "")
|
||||
}
|
||||
var staging = false
|
||||
var err error
|
||||
if body.Staging != "" {
|
||||
staging, err = strconv.ParseBool(body.Staging)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
traitAlias := body.Name
|
||||
template, err := plugins.GetInstalledCapabilityWithCapName(types.TypeTrait, traitAlias)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Run step
|
||||
env, err := env2.GetEnvByName(body.EnvName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
appObj, err = common.AddOrUpdateTrait(env, body.AppName, body.ComponentName, fs, template)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
io := util2.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
return common.TraitOperationRun(c, s.KubeClient, env, appObj, staging, io)
|
||||
}
|
||||
|
||||
// DoDetachTrait executes detaching trait operation
|
||||
func (s *APIServer) DoDetachTrait(c context.Context, envName string, traitType string, componentName string, appName string, staging bool) (string, error) {
|
||||
var appObj *api.Application
|
||||
var err error
|
||||
if appName == "" {
|
||||
appName = componentName
|
||||
}
|
||||
if appObj, err = common.PrepareDetachTrait(envName, traitType, componentName, appName); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Run
|
||||
env, err := env2.GetEnvByName(envName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
io := util2.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
return common.TraitOperationRun(c, s.KubeClient, env, appObj, staging, io)
|
||||
util.AssembleResponse(c, "deprecated, please use appfile to update", nil)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func (s *APIServer) GetWorkload(c *gin.Context) {
|
||||
// ListWorkload lists all workloads in the cluster
|
||||
func (s *APIServer) ListWorkload(c *gin.Context) {
|
||||
var workloadDefinitionList []apis.WorkloadMeta
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType("default", s.c, types.TypeWorkload)
|
||||
if err != nil {
|
||||
util.HandleError(c, util.StatusInternalServerError, err)
|
||||
return
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
util2 "github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
@@ -36,8 +37,9 @@ func ApplyTerraform(app *v1alpha2.Application, k8sClient client.Client, ioStream
|
||||
var nativeVelaComponents []v1alpha2.ApplicationComponent
|
||||
// parse template
|
||||
appParser := appfile.NewApplicationParser(k8sClient, dm)
|
||||
// TODO(wangyike) this context only for compiling success, lately mabey surport setting sysNs and appNs in api-server or cli
|
||||
appFile, err := appParser.GenerateAppFile(context.TODO(), app.Name, app)
|
||||
|
||||
ctx := util2.SetNamespaceInCtx(context.Background(), namespace)
|
||||
appFile, err := appParser.GenerateAppFile(ctx, app.Name, app)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse appfile: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,14 +2,10 @@ package api
|
||||
|
||||
// Driver is mutli implement interface
|
||||
type Driver interface {
|
||||
// List applications
|
||||
List(envName string) ([]*Application, error)
|
||||
// Save application
|
||||
Save(app *Application, envName string) error
|
||||
// Delete application
|
||||
Delete(envName, appName string) error
|
||||
// Get application
|
||||
Get(envName, appName string) (*Application, error)
|
||||
// Name of storage driver
|
||||
Name() string
|
||||
}
|
||||
|
||||
+27
-72
@@ -2,6 +2,7 @@ package appfile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -16,8 +17,8 @@ import (
|
||||
)
|
||||
|
||||
// NewEmptyApplication new empty application, only set tm
|
||||
func NewEmptyApplication() (*api.Application, error) {
|
||||
tm, err := template.Load()
|
||||
func NewEmptyApplication(namespace string, c types.Args) (*api.Application, error) {
|
||||
tm, err := template.Load(namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,19 +53,17 @@ func Validate(app *api.Application) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNotFound is application not found error
|
||||
func IsNotFound(appName string, err error) bool {
|
||||
return err != nil && err.Error() == fmt.Sprintf(`application "%s" not found`, appName)
|
||||
}
|
||||
|
||||
// LoadApplication will load application with env and name from default vela home dir.
|
||||
func LoadApplication(envName, appName string) (*api.Application, error) {
|
||||
app, err := GetStorage().Get(envName, appName)
|
||||
// LoadApplication will load application from cluster.
|
||||
func LoadApplication(namespace, appName string, c types.Args) (*v1alpha2.Application, error) {
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = Validate(app)
|
||||
return app, err
|
||||
app := &v1alpha2.Application{}
|
||||
if err := newClient.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: appName}, app); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// Delete will delete an app along with it's appfile.
|
||||
@@ -72,50 +71,16 @@ func Delete(envName, appName string) error {
|
||||
return GetStorage().Delete(envName, appName)
|
||||
}
|
||||
|
||||
// List will list all apps
|
||||
func List(envName string) ([]*api.Application, error) {
|
||||
respApps, err := GetStorage().List(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var apps []*api.Application
|
||||
for _, resp := range respApps {
|
||||
app := NewApplication(resp.AppFile, resp.Tm)
|
||||
err := Validate(app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apps = append(apps, app)
|
||||
}
|
||||
return apps, nil
|
||||
}
|
||||
|
||||
// MatchAppByComp will get application with componentName without AppName.
|
||||
func MatchAppByComp(envName, compName string) (*api.Application, error) {
|
||||
apps, err := List(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, subapp := range apps {
|
||||
for _, v := range GetComponents(subapp) {
|
||||
if v == compName {
|
||||
return subapp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no app found contains %s in env %s", compName, envName)
|
||||
}
|
||||
|
||||
// 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 *api.Application) []string {
|
||||
func GetComponents(app *v1alpha2.Application) []string {
|
||||
var components []string
|
||||
for name := range app.Services {
|
||||
components = append(components, name)
|
||||
for _, cmp := range app.Spec.Components {
|
||||
components = append(components, cmp.Name)
|
||||
}
|
||||
sort.Strings(components)
|
||||
return components
|
||||
@@ -130,6 +95,18 @@ func GetServiceConfig(app *api.Application, componentName string) (string, map[s
|
||||
return svc.GetType(), svc.GetApplicationConfig()
|
||||
}
|
||||
|
||||
// GetApplicationSettings will get service type and it's configuration
|
||||
func GetApplicationSettings(app *v1alpha2.Application, componentName string) (string, map[string]interface{}) {
|
||||
for _, comp := range app.Spec.Components {
|
||||
if comp.Name == componentName {
|
||||
data := map[string]interface{}{}
|
||||
_ = json.Unmarshal(comp.Settings.Raw, &data)
|
||||
return comp.WorkloadType, data
|
||||
}
|
||||
}
|
||||
return "", make(map[string]interface{})
|
||||
}
|
||||
|
||||
// GetWorkload will get workload type and it's configuration
|
||||
func GetWorkload(app *api.Application, componentName string) (string, map[string]interface{}) {
|
||||
svcType, config := GetServiceConfig(app, componentName)
|
||||
@@ -163,33 +140,11 @@ func GetTraits(app *api.Application, componentName string) (map[string]map[strin
|
||||
return traitsData, nil
|
||||
}
|
||||
|
||||
// GetTraitsByType will get trait configuration with specified component and trait type, we assume one type of trait can only attach to a component once.
|
||||
func GetTraitsByType(app *api.Application, componentName, traitType string) (map[string]interface{}, error) {
|
||||
service, ok := app.Services[componentName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("service name (%s) doesn't exist", componentName)
|
||||
}
|
||||
t, ok := service[traitType]
|
||||
if !ok {
|
||||
return make(map[string]interface{}), nil
|
||||
}
|
||||
return t.(map[string]interface{}), nil
|
||||
}
|
||||
|
||||
// GetAppConfig will get AppConfig from K8s cluster.
|
||||
func GetAppConfig(ctx context.Context, c client.Client, app *api.Application, env *types.EnvMeta) (*v1alpha2.ApplicationConfiguration, error) {
|
||||
func GetAppConfig(ctx context.Context, c client.Client, app *v1alpha2.Application, env *types.EnvMeta) (*v1alpha2.ApplicationConfiguration, error) {
|
||||
appConfig := &v1alpha2.ApplicationConfiguration{}
|
||||
if err := c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appConfig, nil
|
||||
}
|
||||
|
||||
// GetApplication will get Application from K8s cluster.
|
||||
func GetApplication(ctx context.Context, c client.Client, app *api.Application, env *types.EnvMeta) (*v1alpha2.Application, error) {
|
||||
appl := &v1alpha2.Application{}
|
||||
if err := c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appl, nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -128,7 +127,6 @@ services:
|
||||
continue
|
||||
}
|
||||
assert.Equal(t, c.ExpName, app.Name, caseName)
|
||||
assert.Equal(t, c.ExpComponents, GetComponents(app), caseName)
|
||||
workloadType, workload := GetWorkload(app, c.WantWorkload)
|
||||
assert.Equal(t, c.ExpWorkload, workload, caseName)
|
||||
assert.Equal(t, c.ExpWorkloadType, workloadType, caseName)
|
||||
@@ -137,18 +135,3 @@ services:
|
||||
assert.Equal(t, c.ExpTraits, traits, caseName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadNotExistsApplication(t *testing.T) {
|
||||
caseName := "load not exists application"
|
||||
|
||||
now := time.Now().Unix()
|
||||
appName := fmt.Sprintf("test-app-%d", now)
|
||||
|
||||
app, err := LoadApplication(types.DefaultEnvName, appName)
|
||||
|
||||
assert.Nil(t, app, caseName)
|
||||
assert.Error(t, err, caseName)
|
||||
|
||||
errString := fmt.Sprintf(`application "%s" not found`, appName)
|
||||
assert.EqualError(t, err, errString, caseName)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
"github.com/oam-dev/kubevela/references/appfile/template"
|
||||
)
|
||||
|
||||
// LocalDriverName is local storage driver name
|
||||
@@ -34,33 +32,6 @@ func (l *Local) Name() string {
|
||||
return LocalDriverName
|
||||
}
|
||||
|
||||
// List applications from local storage
|
||||
func (l *Local) List(envName string) ([]*api.Application, error) {
|
||||
appDir, err := getApplicationDir(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files, err := ioutil.ReadDir(appDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list apps from %s err %w", appDir, err)
|
||||
}
|
||||
var apps []*api.Application
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(f.Name(), ".yaml") {
|
||||
continue
|
||||
}
|
||||
app, err := loadFromFile(filepath.Join(appDir, f.Name()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load application err %w", err)
|
||||
}
|
||||
apps = append(apps, app)
|
||||
}
|
||||
return apps, nil
|
||||
}
|
||||
|
||||
// Save application from local storage
|
||||
func (l *Local) Save(app *api.Application, envName string) error {
|
||||
appDir, err := getApplicationDir(envName)
|
||||
@@ -88,24 +59,6 @@ func (l *Local) Delete(envName, appName string) error {
|
||||
return os.Remove(filepath.Join(appDir, appName+".yaml"))
|
||||
}
|
||||
|
||||
// Get application from local storage
|
||||
func (l *Local) Get(envName, appName string) (*api.Application, error) {
|
||||
appDir, err := getApplicationDir(envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app, err := loadFromFile(filepath.Join(appDir, appName+".yaml"))
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf(`application "%s" not found`, appName)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func getApplicationDir(envName string) (string, error) {
|
||||
appDir := filepath.Join(env.GetEnvDirByName(envName), "applications")
|
||||
_, err := system.CreateIfNotExist(appDir)
|
||||
@@ -114,22 +67,3 @@ func getApplicationDir(envName string) (string, error) {
|
||||
}
|
||||
return appDir, err
|
||||
}
|
||||
|
||||
// LoadFromFile will load application from file
|
||||
func loadFromFile(fileName string) (*api.Application, error) {
|
||||
tm, err := template.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = os.Stat(fileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f, err := api.LoadFromFile(fileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app := &api.Application{AppFile: f, Tm: tm}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
@@ -10,18 +10,15 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
"github.com/oam-dev/kubevela/references/appfile/template"
|
||||
)
|
||||
|
||||
var dir string
|
||||
var tm template.Manager
|
||||
var afile *api.AppFile
|
||||
var appName = "testsvc"
|
||||
var envName = "default"
|
||||
|
||||
func init() {
|
||||
dir, _ = getApplicationDir(envName)
|
||||
tm, _ = template.Load()
|
||||
afile = api.NewAppFile()
|
||||
afile.Name = appName
|
||||
svcs := make(map[string]api.Service)
|
||||
@@ -37,34 +34,6 @@ func init() {
|
||||
_ = ioutil.WriteFile(filepath.Join(dir, appName+".yaml"), out, 0644)
|
||||
}
|
||||
|
||||
func TestLocal_Get(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
appName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *api.Application
|
||||
wantErr bool
|
||||
}{
|
||||
{"TestLocal_Get1", args{envName: envName, appName: appName}, &api.Application{AppFile: afile, Tm: tm}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
l := &Local{}
|
||||
got, err := l.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 TestLocal_Delete(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
@@ -110,35 +79,6 @@ func TestLocal_Save(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocal_List(t *testing.T) {
|
||||
type args struct {
|
||||
envName string
|
||||
}
|
||||
want := make([]*api.Application, 0)
|
||||
want = append(want, &api.Application{AppFile: afile, Tm: tm})
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*api.Application
|
||||
wantErr bool
|
||||
}{
|
||||
{"TestLocal_List1", args{envName}, want, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
l := &Local{}
|
||||
got, err := l.List(tt.args.envName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("List() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if len(got) == 0 {
|
||||
t.Errorf("List() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocal_Name(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -197,29 +137,3 @@ func Test_getApplicationDir(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadFromFile(t *testing.T) {
|
||||
type args struct {
|
||||
fileName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *api.Application
|
||||
wantErr bool
|
||||
}{
|
||||
{"testRespApp", args{fileName: filepath.Join(dir, appName+".yaml")}, &api.Application{AppFile: afile, Tm: tm}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := loadFromFile(tt.args.fileName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("loadFromFile() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got.Name != tt.want.Name {
|
||||
t.Errorf("loadFromFile() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package appfile
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
@@ -25,30 +30,39 @@ func SetWorkload(app *api.Application, componentName, workloadType string, workl
|
||||
}
|
||||
|
||||
// SetTrait will set user trait for Appfile
|
||||
func SetTrait(app *api.Application, componentName, traitType string, traitData map[string]interface{}) error {
|
||||
func SetTrait(app *v1alpha2.Application, componentName, traitType string, traitData map[string]interface{}) error {
|
||||
if app == nil {
|
||||
return errors.New("app is nil pointer")
|
||||
}
|
||||
if traitData == nil {
|
||||
traitData = make(map[string]interface{})
|
||||
}
|
||||
|
||||
s, ok := app.Services[componentName]
|
||||
if !ok {
|
||||
s = api.Service{}
|
||||
data, err := json.Marshal(traitData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to marshal trait data %w", err)
|
||||
}
|
||||
|
||||
t, ok := s[traitType]
|
||||
if !ok {
|
||||
t = make(map[string]interface{})
|
||||
var foundComp bool
|
||||
for idx, comp := range app.Spec.Components {
|
||||
if comp.Name != componentName {
|
||||
continue
|
||||
}
|
||||
foundComp = true
|
||||
var added bool
|
||||
for j, tr := range app.Spec.Components[idx].Traits {
|
||||
if tr.Name != traitType {
|
||||
continue
|
||||
}
|
||||
added = true
|
||||
app.Spec.Components[idx].Traits[j].Properties.Raw = data
|
||||
}
|
||||
if !added {
|
||||
app.Spec.Components[idx].Traits = append(app.Spec.Components[idx].Traits, v1alpha2.ApplicationTrait{Name: traitType, Properties: runtime.RawExtension{Raw: data}})
|
||||
}
|
||||
}
|
||||
tm := t.(map[string]interface{})
|
||||
for k, v := range traitData {
|
||||
tm[k] = v
|
||||
if !foundComp {
|
||||
return errors.New(componentName + " not found in app " + app.Name)
|
||||
}
|
||||
s[traitType] = t
|
||||
app.Services[componentName] = s
|
||||
return Validate(app)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTrait will remove a trait from Appfile
|
||||
@@ -65,12 +79,18 @@ func RemoveTrait(app *api.Application, componentName, traitType string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveComponent will remove component from Appfile
|
||||
func RemoveComponent(app *api.Application, componentName string) error {
|
||||
// RemoveComponent will remove component from Application
|
||||
func RemoveComponent(app *v1alpha2.Application, componentName string) error {
|
||||
if app == nil {
|
||||
return errors.New("app is nil pointer")
|
||||
}
|
||||
|
||||
delete(app.Services, componentName)
|
||||
var newComps []v1alpha2.ApplicationComponent
|
||||
for _, comp := range app.Spec.Components {
|
||||
if comp.Name == componentName {
|
||||
continue
|
||||
}
|
||||
newComps = append(newComps, comp)
|
||||
}
|
||||
app.Spec.Components = newComps
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,11 +33,6 @@ func GetStorage() *Storage {
|
||||
return store
|
||||
}
|
||||
|
||||
// List applications storage common implement
|
||||
func (s *Storage) List(envName string) ([]*api.Application, error) {
|
||||
return s.Driver.List(envName)
|
||||
}
|
||||
|
||||
// Save application storage common implement
|
||||
func (s *Storage) Save(app *api.Application, envName string) error {
|
||||
return s.Driver.Save(app, envName)
|
||||
@@ -47,8 +42,3 @@ func (s *Storage) Save(app *api.Application, envName string) error {
|
||||
func (s *Storage) Delete(envName, appName string) error {
|
||||
return s.Driver.Delete(envName, appName)
|
||||
}
|
||||
|
||||
// Get application storage common implement
|
||||
func (s *Storage) Get(envName, appName string) (*api.Application, error) {
|
||||
return s.Driver.Get(envName, appName)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ type Manager interface {
|
||||
}
|
||||
|
||||
// Load will load all installed capabilities and create a manager
|
||||
func Load() (Manager, error) {
|
||||
caps, err := plugins.LoadAllInstalledCapability()
|
||||
func Load(namespace string, c types.Args) (Manager, error) {
|
||||
caps, err := plugins.LoadAllInstalledCapability(namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
@@ -29,7 +28,7 @@ func CapabilityCommandGroup(c types.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
}
|
||||
cmd.AddCommand(
|
||||
NewCenterCommand(ioStream),
|
||||
NewCapListCommand(ioStream),
|
||||
NewCapListCommand(c, ioStream),
|
||||
NewCapInstallCommand(c, ioStream),
|
||||
NewCapUninstallCommand(c, ioStream),
|
||||
)
|
||||
@@ -94,7 +93,7 @@ func NewCapInstallCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
|
||||
if argsLength < 1 {
|
||||
return errors.New("you must specify <center>/<name> for capability you want to install")
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,7 +125,7 @@ func NewCapUninstallCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Co
|
||||
if len(args) < 1 {
|
||||
return errors.New("you must specify <name> for capability you want to uninstall")
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -138,7 +137,11 @@ func NewCapUninstallCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Co
|
||||
}
|
||||
name = l[1]
|
||||
}
|
||||
return common.RemoveCapability(newClient, name, ioStreams)
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return common.RemoveCapability(env.Namespace, c, newClient, name, ioStreams)
|
||||
},
|
||||
}
|
||||
cmd.PersistentFlags().StringP("token", "t", "", "Github Repo token")
|
||||
@@ -168,7 +171,7 @@ func NewCapCenterSyncCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
}
|
||||
|
||||
// NewCapListCommand List capabilities from cap-center
|
||||
func NewCapListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
func NewCapListCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls [cap-center]",
|
||||
Short: "List capabilities from cap-center",
|
||||
@@ -179,7 +182,11 @@ func NewCapListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if len(args) > 0 {
|
||||
repoName = args[0]
|
||||
}
|
||||
capabilityList, err := common.ListCapabilities(repoName)
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
capabilityList, err := common.ListCapabilities(env.Namespace, c, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package cli
|
||||
|
||||
// constants used in `svc` command
|
||||
const (
|
||||
App = "app"
|
||||
Service = "svc"
|
||||
App = "app"
|
||||
Service = "svc"
|
||||
Namespace = "namespace"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ func NewDashboardCommand(c types.Args, ioStreams cmdutil.IOStreams, frontendSour
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -30,11 +29,13 @@ func NewDeleteCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o := &common.DeleteOptions{}
|
||||
o := &common.DeleteOptions{
|
||||
C: c,
|
||||
}
|
||||
o.Client = newClient
|
||||
o.Env, err = GetEnv(cmd)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
corev1alpha2 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
@@ -37,7 +36,7 @@ func NewDryRunCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -54,7 +53,13 @@ func NewDryRunCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
|
||||
parser := appfile.NewApplicationParser(newClient, dm)
|
||||
|
||||
ctx := oamutil.SetNamespaceInCtx(context.Background(), app.Namespace)
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := oamutil.SetNamespaceInCtx(context.Background(), velaEnv.Namespace)
|
||||
|
||||
appFile, err := parser.GenerateAppFile(ctx, app.Name, app)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "generate appFile")
|
||||
|
||||
@@ -64,15 +64,11 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := RefreshDefinitions(ctx, c, ioStreams, true, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CreateOrUpdateEnv(ctx, newClient, &envArgs, args, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
cmdexec "k8s.io/kubectl/pkg/cmd/exec"
|
||||
k8scmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,7 +40,7 @@ type VelaExecOptions struct {
|
||||
context.Context
|
||||
VelaC types.Args
|
||||
Env *types.EnvMeta
|
||||
App *api.Application
|
||||
App *v1alpha2.Application
|
||||
|
||||
f k8scmdutil.Factory
|
||||
kcExecOptions *cmdexec.ExecOptions
|
||||
@@ -122,7 +122,7 @@ func (o *VelaExecOptions) Init(ctx context.Context, c *cobra.Command, argsIn []s
|
||||
return err
|
||||
}
|
||||
o.Env = env
|
||||
app, err := appfile.LoadApplication(env.Name, o.Args[0])
|
||||
app, err := appfile.LoadApplication(env.Namespace, o.Args[0], o.VelaC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -167,8 +167,10 @@ func (o *VelaExecOptions) getComponentName() (string, error) {
|
||||
svcName := o.ServiceName
|
||||
|
||||
if svcName != "" {
|
||||
if _, exist := o.App.Services[svcName]; exist {
|
||||
return svcName, nil
|
||||
for _, cc := range o.App.Spec.Components {
|
||||
if cc.Name == svcName {
|
||||
return svcName, nil
|
||||
}
|
||||
}
|
||||
o.Cmd.Printf("The service name '%s' is not valid\n", svcName)
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/kubectl/pkg/cmd/exec"
|
||||
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
||||
k8scmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestExecCommand(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := types.Args{
|
||||
Config: tf.ClientConfigVal,
|
||||
}
|
||||
cmd := NewExecCommand(fakeC, io)
|
||||
cmd.PersistentFlags().StringP("env", "e", "", "")
|
||||
o := &VelaExecOptions{
|
||||
kcExecOptions: &exec.ExecOptions{},
|
||||
f: tf,
|
||||
ClientSet: fake.NewSimpleClientset(&corev1.PodList{
|
||||
Items: []corev1.Pod{
|
||||
{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "fakePod",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
oam.LabelAppName: "fakeApp",
|
||||
oam.LabelAppComponent: "fakeComp",
|
||||
}},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
err := o.Init(context.Background(), cmd, []string{"fakeApp"})
|
||||
errString := fmt.Sprintf(`application "%s" not found`, "fakeApp")
|
||||
assert.EqualError(t, err, errString)
|
||||
fakeApp := &api.Application{
|
||||
AppFile: &api.AppFile{
|
||||
Name: "fakeApp",
|
||||
Services: map[string]api.Service{
|
||||
"fakeComp": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
o.App = fakeApp
|
||||
|
||||
cf := genericclioptions.NewConfigFlags(true)
|
||||
cf.Namespace = &o.Env.Namespace
|
||||
o.f = k8scmdutil.NewFactory(k8scmdutil.NewMatchVersionFlags(cf))
|
||||
err = o.Complete()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestExecCommandPersistentPreRunE(t *testing.T) {
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := types.Args{}
|
||||
cmd := NewExecCommand(fakeC, io)
|
||||
assert.Nil(t, cmd.PersistentPreRunE(new(cobra.Command), []string{}))
|
||||
}
|
||||
|
||||
func TestGetComponent(t *testing.T) {
|
||||
o := &VelaExecOptions{
|
||||
App: &api.Application{
|
||||
AppFile: &api.AppFile{
|
||||
Name: "fakeApp",
|
||||
Services: map[string]api.Service{
|
||||
"fakeComp1": map[string]interface{}{},
|
||||
"fakeComp2": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
o.ServiceName = "fakeComp1"
|
||||
svcName, err := o.getComponentName()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, o.ServiceName, svcName)
|
||||
|
||||
o.ServiceName = "fakeComp2"
|
||||
svcName, err = o.getComponentName()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, o.ServiceName, svcName)
|
||||
}
|
||||
@@ -19,15 +19,19 @@ func NewExportCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
velaEnv, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o := &common.AppfileOptions{
|
||||
IO: ioStream,
|
||||
Env: &types.EnvMeta{},
|
||||
Env: velaEnv,
|
||||
}
|
||||
filePath, err := cmd.Flags().GetString(appFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, data, err := o.Export(filePath, true)
|
||||
_, data, err := o.Export(filePath, velaEnv.Namespace, true, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+7
-42
@@ -28,6 +28,7 @@ type appInitOptions struct {
|
||||
client client.Client
|
||||
cmdutil.IOStreams
|
||||
Env *types.EnvMeta
|
||||
c types.Args
|
||||
|
||||
app *api.Application
|
||||
appName string
|
||||
@@ -38,7 +39,7 @@ type appInitOptions struct {
|
||||
|
||||
// NewInitCommand creates `init` command
|
||||
func NewInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
o := &appInitOptions{IOStreams: ioStreams}
|
||||
o := &appInitOptions{IOStreams: ioStreams, c: c}
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -49,7 +50,7 @@ func NewInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -69,9 +70,6 @@ func NewInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if err = o.Workload(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = o.Traits(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := appfile.Validate(o.app); err != nil {
|
||||
return err
|
||||
@@ -96,14 +94,14 @@ func NewInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deployStatus, err := printTrackingDeployStatus(ctx, o.client, o.IOStreams, o.workloadName, o.appName, o.Env)
|
||||
deployStatus, err := printTrackingDeployStatus(c, o.IOStreams, o.appName, o.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if deployStatus != compStatusDeployed {
|
||||
return nil
|
||||
}
|
||||
return printAppStatus(context.Background(), newClient, ioStreams, o.appName, o.Env, cmd)
|
||||
return printAppStatus(context.Background(), newClient, ioStreams, o.appName, o.Env, cmd, c)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
@@ -184,7 +182,7 @@ func formatAndGetUsage(p *types.Parameter) string {
|
||||
|
||||
// Workload asks user to choose workload type from installed workloads
|
||||
func (o *appInitOptions) Workload() error {
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(o.Env.Namespace, o.c, types.TypeWorkload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -306,7 +304,7 @@ func (o *appInitOptions) Workload() error {
|
||||
// other type not supported
|
||||
}
|
||||
}
|
||||
o.app, err = common.BaseComplete(o.Env.Name, o.workloadName, o.appName, fs, o.workloadType)
|
||||
o.app, err = common.BaseComplete(o.Env, o.c, o.workloadName, o.appName, fs, o.workloadType)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -319,36 +317,3 @@ func GetCapabilityByName(name string, workloads []types.Capability) (types.Capab
|
||||
}
|
||||
return types.Capability{}, fmt.Errorf("%s not found", name)
|
||||
}
|
||||
|
||||
// Traits attaches specific trait to service
|
||||
func (o *appInitOptions) Traits() error {
|
||||
traits, err := plugins.LoadInstalledCapabilityWithType(types.TypeTrait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch o.workloadType {
|
||||
case "webservice":
|
||||
// TODO(wonderflow) this should get from workload definition to know which trait should be suggestions
|
||||
var suggestTraits = []string{}
|
||||
if o.Env.Domain != "" {
|
||||
suggestTraits = append(suggestTraits, "route")
|
||||
}
|
||||
for _, tr := range suggestTraits {
|
||||
trait, err := GetCapabilityByName(tr, traits)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tflags := pflag.NewFlagSet("trait", pflag.ContinueOnError)
|
||||
for _, pa := range trait.Parameters {
|
||||
types.SetFlagBy(tflags, pa)
|
||||
}
|
||||
// TODO(wonderflow): give a way to add parameter for trait
|
||||
o.app, err = common.AddOrUpdateTrait(o.Env, o.appName, o.workloadName, tflags, trait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// NewLogsCommand creates `logs` command to tail logs of application
|
||||
@@ -45,7 +45,7 @@ func NewLogsCommand(c types.Args, ioStreams util.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := appfile.LoadApplication(env.Name, args[0])
|
||||
app, err := appfile.LoadApplication(env.Namespace, args[0], c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -69,7 +69,7 @@ type Args struct {
|
||||
Output string
|
||||
Env *types.EnvMeta
|
||||
C types.Args
|
||||
App *api.Application
|
||||
App *v1alpha2.Application
|
||||
}
|
||||
|
||||
// Run refer to the implementation at https://github.com/oam-dev/stern/blob/master/stern/main.go
|
||||
|
||||
+45
-81
@@ -5,14 +5,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/apiserver/apis"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
)
|
||||
|
||||
// NewListCommand creates `ls` command and its nested children command
|
||||
@@ -22,8 +20,8 @@ func NewListCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
Use: "ls",
|
||||
Aliases: []string{"list"},
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "List services",
|
||||
Long: "List services of all applications",
|
||||
Short: "List applications",
|
||||
Long: "List all applications in cluster",
|
||||
Example: `vela ls`,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.SetConfig()
|
||||
@@ -33,98 +31,64 @@ func NewListCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appName, err := cmd.Flags().GetString(App)
|
||||
namespace, err := cmd.Flags().GetString(Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printComponentList(ctx, newClient, appName, env, ioStreams)
|
||||
return nil
|
||||
if namespace == "" {
|
||||
namespace = env.Namespace
|
||||
}
|
||||
return printApplicationList(ctx, newClient, namespace, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.PersistentFlags().StringP(App, "", "", "specify the name of application")
|
||||
cmd.PersistentFlags().StringP(Namespace, "n", "", "specify the namespace the application want to list, default is the current env namespace")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printComponentList(ctx context.Context, c client.Reader, appName string, env *types.EnvMeta,
|
||||
ioStreams cmdutil.IOStreams) {
|
||||
deployedComponentList, err := common.ListComponents(ctx, c, common.Option{
|
||||
AppName: appName,
|
||||
Namespace: env.Namespace,
|
||||
})
|
||||
if err != nil {
|
||||
ioStreams.Infof("listing services: %s\n", err)
|
||||
return
|
||||
func printApplicationList(ctx context.Context, c client.Reader, namespace string, ioStreams cmdutil.IOStreams) error {
|
||||
table := newUITable()
|
||||
table.AddRow("APP", "COMPONENT", "TYPE", "TRAITS", "PHASE", "HEALTHY", "STATUS", "CREATED-TIME")
|
||||
applist := v1alpha2.ApplicationList{}
|
||||
if err := c.List(ctx, &applist, client.InNamespace(namespace)); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
fetcher := func(name string) (*v1alpha2.Application, error) {
|
||||
var app = new(v1alpha2.Application)
|
||||
err := c.Get(ctx, client.ObjectKey{Name: name, Namespace: env.Namespace}, app)
|
||||
return app, err
|
||||
}
|
||||
all := mergeStagingComponents(deployedComponentList, env, ioStreams, fetcher)
|
||||
table := newUITable()
|
||||
table.AddRow("SERVICE", "APP", "TYPE", "TRAITS", "STATUS", "CREATED-TIME")
|
||||
for _, a := range all {
|
||||
traitAlias := strings.Join(a.TraitNames, ",")
|
||||
table.AddRow(a.Name, a.App, a.WorkloadName, traitAlias, a.Status, a.CreatedTime)
|
||||
for _, a := range applist.Items {
|
||||
for idx, cmp := range a.Spec.Components {
|
||||
var appName = a.Name
|
||||
if idx > 0 {
|
||||
appName = "├─"
|
||||
if idx == len(a.Spec.Components)-1 {
|
||||
appName = "└─"
|
||||
}
|
||||
}
|
||||
var healthy, status string
|
||||
if len(a.Status.Services) > idx {
|
||||
if a.Status.Services[idx].Healthy {
|
||||
healthy = "healthy"
|
||||
} else {
|
||||
healthy = "unhealthy"
|
||||
}
|
||||
status = a.Status.Services[idx].Message
|
||||
}
|
||||
var traits []string
|
||||
for _, tr := range cmp.Traits {
|
||||
traits = append(traits, tr.Name)
|
||||
}
|
||||
table.AddRow(appName, cmp.Name, cmp.WorkloadType, strings.Join(traits, ","), a.Status.Phase, healthy, status, a.CreationTimestamp)
|
||||
}
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
}
|
||||
|
||||
func mergeStagingComponents(deployed []apis.ComponentMeta, env *types.EnvMeta, ioStreams cmdutil.IOStreams, fetcher func(name string) (*v1alpha2.Application, error)) []apis.ComponentMeta {
|
||||
localApps, err := appfile.List(env.Name)
|
||||
if err != nil {
|
||||
ioStreams.Error("list application err", err)
|
||||
return deployed
|
||||
}
|
||||
var all []apis.ComponentMeta
|
||||
for _, app := range localApps {
|
||||
appl, err := fetcher(app.Name)
|
||||
if err != nil {
|
||||
ioStreams.Errorf("fetch app %s err %v\n", app.Name, err)
|
||||
continue
|
||||
}
|
||||
for _, c := range appl.Spec.Components {
|
||||
traits := []string{}
|
||||
for _, t := range c.Traits {
|
||||
traits = append(traits, t.Name)
|
||||
}
|
||||
compMeta, exist := GetCompMeta(deployed, app.Name, c.Name)
|
||||
if !exist {
|
||||
all = append(all, apis.ComponentMeta{
|
||||
Name: c.Name,
|
||||
App: app.Name,
|
||||
WorkloadName: c.WorkloadType,
|
||||
TraitNames: traits,
|
||||
Status: types.StatusStaging,
|
||||
CreatedTime: app.CreateTime.String(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
compMeta.TraitNames = traits
|
||||
compMeta.WorkloadName = c.WorkloadType
|
||||
if appl.Status.Phase != v1alpha2.ApplicationRunning {
|
||||
compMeta.Status = types.StatusStaging
|
||||
}
|
||||
all = append(all, compMeta)
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// GetCompMeta gets meta of a component
|
||||
func GetCompMeta(deployed []apis.ComponentMeta, appName, compName string) (apis.ComponentMeta, bool) {
|
||||
for _, v := range deployed {
|
||||
if v.Name == compName && v.App == appName {
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
return apis.ComponentMeta{}, false
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// VelaPortForwardOptions for vela port-forward
|
||||
@@ -40,7 +39,7 @@ type VelaPortForwardOptions struct {
|
||||
context.Context
|
||||
VelaC types.Args
|
||||
Env *types.EnvMeta
|
||||
App *api.Application
|
||||
App *v1alpha2.Application
|
||||
|
||||
f k8scmdutil.Factory
|
||||
kcPortForwardOptions *cmdpf.PortForwardOptions
|
||||
@@ -74,7 +73,7 @@ func NewPortForwardCommand(c types.Args, ioStreams util.IOStreams) *cobra.Comman
|
||||
ioStreams.Error("Please specify application name.")
|
||||
return nil
|
||||
}
|
||||
newClient, err := client.New(o.VelaC.Config, client.Options{Scheme: o.VelaC.Schema})
|
||||
newClient, err := o.VelaC.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -114,7 +113,7 @@ func (o *VelaPortForwardOptions) Init(ctx context.Context, cmd *cobra.Command, a
|
||||
}
|
||||
o.Env = env
|
||||
|
||||
app, err := appfile.LoadApplication(env.Name, o.Args[0])
|
||||
app, err := appfile.LoadApplication(env.Namespace, o.Args[0], o.VelaC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -191,7 +190,7 @@ func (o *VelaPortForwardOptions) Complete() error {
|
||||
}
|
||||
if len(o.Args) < 2 {
|
||||
var found bool
|
||||
_, configs := appfile.GetServiceConfig(o.App, svcName)
|
||||
_, configs := appfile.GetApplicationSettings(o.App, svcName)
|
||||
for k, v := range configs {
|
||||
if k == "port" {
|
||||
var val string
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8sfake "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/kubectl/pkg/cmd/portforward"
|
||||
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
func TestPortForwardCommand(t *testing.T) {
|
||||
fakePod := corev1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "fakePod",
|
||||
Namespace: "default",
|
||||
ResourceVersion: "10",
|
||||
Labels: map[string]string{
|
||||
oam.LabelAppComponent: "fakeComp",
|
||||
}},
|
||||
}
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := types.Args{
|
||||
Config: tf.ClientConfigVal,
|
||||
}
|
||||
cmd := NewPortForwardCommand(fakeC, io)
|
||||
cmd.PersistentFlags().StringP("env", "e", "", "")
|
||||
fakeClientSet := k8sfake.NewSimpleClientset(&corev1.PodList{
|
||||
Items: []corev1.Pod{fakePod},
|
||||
})
|
||||
|
||||
o := &VelaPortForwardOptions{
|
||||
ioStreams: io,
|
||||
kcPortForwardOptions: &portforward.PortForwardOptions{},
|
||||
f: tf,
|
||||
ClientSet: fakeClientSet,
|
||||
VelaC: fakeC,
|
||||
}
|
||||
err := o.Init(context.Background(), cmd, []string{"fakeApp", "8081:8080"})
|
||||
errString := fmt.Sprintf(`application "%s" not found`, "fakeApp")
|
||||
assert.EqualError(t, err, errString)
|
||||
}
|
||||
|
||||
func TestNewPortForwardCommandPersistentPreRunE(t *testing.T) {
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := types.Args{}
|
||||
cmd := NewPortForwardCommand(fakeC, io)
|
||||
assert.Nil(t, cmd.PersistentPreRunE(new(cobra.Command), []string{}))
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/gosuri/uitable"
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
type refreshStatus string
|
||||
|
||||
const (
|
||||
added refreshStatus = "Added"
|
||||
updated refreshStatus = "Updated"
|
||||
unchanged refreshStatus = "Unchanged"
|
||||
deleted refreshStatus = "Deleted"
|
||||
)
|
||||
|
||||
const (
|
||||
refreshInterval = 5 * time.Minute
|
||||
)
|
||||
|
||||
// RefreshDefinitions will sync local capabilities with cluster installed ones
|
||||
func RefreshDefinitions(ctx context.Context, c types.Args, ioStreams cmdutil.IOStreams, silentOutput, enforceRefresh bool) error {
|
||||
dir, _ := system.GetCapabilityDir()
|
||||
oldCaps, err := plugins.LoadAllInstalledCapability()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
useCached, err := useCacheInsteadRefresh(dir, refreshInterval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !enforceRefresh && useCached {
|
||||
// use local capabilities instead of fetching from cluster
|
||||
printRefreshReport(nil, oldCaps, ioStreams, silentOutput, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
syncedTemplates, warnings, err := plugins.SyncDefinitionsToLocal(ctx, c, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, w := range warnings {
|
||||
ioStreams.Infof(w)
|
||||
}
|
||||
plugins.RemoveLegacyTemps(syncedTemplates, dir)
|
||||
printRefreshReport(syncedTemplates, oldCaps, ioStreams, silentOutput, false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// silent indicates whether output existing caps if no change occurs. If false, output all existing caps.
|
||||
func printRefreshReport(newCaps, oldCaps []types.Capability, io cmdutil.IOStreams, silent, useCached bool) {
|
||||
var report map[refreshStatus][]types.Capability
|
||||
if useCached {
|
||||
report = map[refreshStatus][]types.Capability{
|
||||
added: make([]types.Capability, 0),
|
||||
updated: make([]types.Capability, 0),
|
||||
unchanged: oldCaps,
|
||||
deleted: make([]types.Capability, 0),
|
||||
}
|
||||
} else {
|
||||
report = refreshResultReport(newCaps, oldCaps)
|
||||
}
|
||||
table := newUITable()
|
||||
table.MaxColWidth = 80
|
||||
table.AddRow("TYPE", "CATEGORY", "DESCRIPTION")
|
||||
|
||||
if len(report[added]) == 0 && len(report[updated]) == 0 && len(report[deleted]) == 0 {
|
||||
// no change occurs, just show all existing caps
|
||||
// always show workload at first
|
||||
for _, cap := range report[unchanged] {
|
||||
if cap.Type == types.TypeWorkload {
|
||||
table.AddRow(cap.Name, cap.Type, cap.Description)
|
||||
}
|
||||
}
|
||||
for _, cap := range report[unchanged] {
|
||||
if cap.Type == types.TypeTrait {
|
||||
table.AddRow(cap.Name, cap.Type, cap.Description)
|
||||
}
|
||||
}
|
||||
if !silent {
|
||||
io.Infof("Automatically discover capabilities successfully %s(no changes)\n\n", emojiSucceed)
|
||||
io.Info(table.String())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
io.Infof("Automatically discover capabilities successfully %sAdd(%s) Update(%s) Delete(%s)\n\n",
|
||||
emojiSucceed,
|
||||
green.Sprint(len(report[added])),
|
||||
yellow.Sprint(len(report[updated])),
|
||||
red.Sprint(len(report[deleted])))
|
||||
// show added/updated/deleted cpas
|
||||
addStsRow(added, report, table)
|
||||
addStsRow(updated, report, table)
|
||||
addStsRow(deleted, report, table)
|
||||
io.Info(table.String())
|
||||
io.Info()
|
||||
}
|
||||
|
||||
func addStsRow(sts refreshStatus, report map[refreshStatus][]types.Capability, t *uitable.Table) {
|
||||
caps := report[sts]
|
||||
if len(caps) == 0 {
|
||||
return
|
||||
}
|
||||
var stsIcon string
|
||||
var stsColor *color.Color
|
||||
switch sts {
|
||||
case added:
|
||||
stsIcon = "+"
|
||||
stsColor = green
|
||||
case updated:
|
||||
stsIcon = "*"
|
||||
stsColor = yellow
|
||||
case deleted:
|
||||
stsIcon = "-"
|
||||
stsColor = red
|
||||
case unchanged:
|
||||
// normal color display
|
||||
}
|
||||
for _, cap := range caps {
|
||||
t.AddRow(
|
||||
// color.New(color.Bold).Sprint(stsColor.Sprint(stsIcon)),
|
||||
stsColor.Sprintf("%s%s", stsIcon, cap.Name),
|
||||
stsColor.Sprint(cap.Type),
|
||||
stsColor.Sprint(cap.Description))
|
||||
}
|
||||
}
|
||||
|
||||
func refreshResultReport(newCaps, oldCaps []types.Capability) map[refreshStatus][]types.Capability {
|
||||
dir, _ := system.GetCapabilityDir()
|
||||
cachedHash := readCapDefHashFromLocal(dir)
|
||||
newHash := map[string]string{}
|
||||
for _, newCap := range newCaps {
|
||||
h, err := hashstructure.Hash(newCap, hashstructure.FormatV2, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
newHash[newCap.Name] = strconv.FormatUint(h, 10)
|
||||
}
|
||||
|
||||
report := map[refreshStatus][]types.Capability{
|
||||
added: make([]types.Capability, 0),
|
||||
updated: make([]types.Capability, 0),
|
||||
unchanged: make([]types.Capability, 0),
|
||||
deleted: make([]types.Capability, 0),
|
||||
}
|
||||
for _, newCap := range newCaps {
|
||||
found := false
|
||||
for _, oldCap := range oldCaps {
|
||||
if newCap.Name == oldCap.Name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
report[added] = append(report[added], newCap)
|
||||
}
|
||||
}
|
||||
for _, oldCap := range oldCaps {
|
||||
found := false
|
||||
for _, newCap := range newCaps {
|
||||
if oldCap.Name == newCap.Name {
|
||||
found = true
|
||||
// use cached hash to determine whether the cap is changed
|
||||
if h, ok := cachedHash[newCap.Name]; ok {
|
||||
if h == newHash[newCap.Name] {
|
||||
report[unchanged] = append(report[unchanged], newCap)
|
||||
} else {
|
||||
report[updated] = append(report[updated], newCap)
|
||||
}
|
||||
break
|
||||
}
|
||||
// in case of missing cache, use Equal func to compare
|
||||
if types.EqualCapability(oldCap, newCap) {
|
||||
report[unchanged] = append(report[unchanged], newCap)
|
||||
} else {
|
||||
report[updated] = append(report[updated], newCap)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
report[deleted] = append(report[deleted], oldCap)
|
||||
}
|
||||
}
|
||||
_ = writeCapDefHashIntoLocal(dir, newHash)
|
||||
return report
|
||||
}
|
||||
|
||||
// useCacheInsteadRefresh checks whether use cached capabilities instead of refresh from cluster
|
||||
// a timestamp records the time when refresh from cluster last time
|
||||
// if duration since last time refresh DOES NOT exceed `cacheExpiredDuration`
|
||||
// use cached capabilities instead of refresh from cluster
|
||||
// else refresh from cluster and refresh the timestamp
|
||||
func useCacheInsteadRefresh(capDir string, cacheExpiredDuration time.Duration) (bool, error) {
|
||||
currentTimestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
tmpDir := filepath.Join(capDir, ".tmp")
|
||||
timeFilePath := filepath.Join(tmpDir, ".lasttimerefresh")
|
||||
exist, _ := system.CreateIfNotExist(tmpDir)
|
||||
if !exist {
|
||||
// file saving timestamp is not created yet, create and refresh the timestamp
|
||||
if err := ioutil.WriteFile(timeFilePath, []byte(currentTimestamp), 0600); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
r, err := ioutil.ReadFile(filepath.Clean(timeFilePath))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// tmpDir exists but `.lasttimerefresh` file doesn't
|
||||
if err := ioutil.WriteFile(timeFilePath, []byte(currentTimestamp), 0600); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
i, err := strconv.ParseInt(string(r), 10, 64)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
lt := time.Unix(i, 0)
|
||||
if time.Since(lt) > cacheExpiredDuration {
|
||||
// cache is expired, refresh the timestamp
|
||||
if err := ioutil.WriteFile(timeFilePath, []byte(currentTimestamp), 0600); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
// cache is not expired
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// each capability has a hash value cached in local capability dir
|
||||
// hash value is used to compare local capability with one from cluster
|
||||
// refresh report will show all changed capabilities
|
||||
func readCapDefHashFromLocal(capDir string) map[string]string {
|
||||
r := map[string]string{}
|
||||
tmpDir := filepath.Join(capDir, ".tmp")
|
||||
hashFilePath := filepath.Join(tmpDir, ".capabilityhash")
|
||||
if exist, err := system.CreateIfNotExist(tmpDir); !exist || err != nil {
|
||||
return r
|
||||
}
|
||||
if _, err := os.Stat(hashFilePath); os.IsNotExist(err) {
|
||||
return r
|
||||
}
|
||||
hashData, err := ioutil.ReadFile(filepath.Clean(hashFilePath))
|
||||
if err != nil {
|
||||
return r
|
||||
}
|
||||
if err := json.Unmarshal(hashData, &r); err != nil {
|
||||
return r
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func writeCapDefHashIntoLocal(capDir string, hashData map[string]string) error {
|
||||
tmpDir := filepath.Join(capDir, ".tmp")
|
||||
hashFilePath := filepath.Join(tmpDir, ".capabilityhash")
|
||||
if _, err := system.CreateIfNotExist(tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(hashData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(hashFilePath, data, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCheckAndUpdateRefreshInterval(t *testing.T) {
|
||||
testdir := "testdir-refresh-interval"
|
||||
testMaxInterval := time.Second
|
||||
|
||||
err := os.MkdirAll(testdir, 0755)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(testdir)
|
||||
|
||||
r, err := useCacheInsteadRefresh(testdir, testMaxInterval)
|
||||
assert.Equal(t, r, false, "should not use cache for tmp file is not created")
|
||||
assert.NoError(t, err)
|
||||
|
||||
r, err = useCacheInsteadRefresh(testdir, testMaxInterval)
|
||||
assert.Equal(t, r, true, "should use cache for interval is not expired")
|
||||
assert.NoError(t, err)
|
||||
|
||||
time.Sleep(2 * testMaxInterval)
|
||||
r, err = useCacheInsteadRefresh(testdir, testMaxInterval)
|
||||
assert.Equal(t, r, false, "should not use cache for interval is already expired")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWriteAndReadLocalCapHash(t *testing.T) {
|
||||
testdir := "testdir-caphash"
|
||||
err := os.MkdirAll(testdir, 0755)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(testdir)
|
||||
|
||||
result := readCapDefHashFromLocal(testdir)
|
||||
assert.Equal(t, result, map[string]string{}, "capability hash data should be empty")
|
||||
fakeHashData := map[string]string{
|
||||
"a": "test1",
|
||||
"b": "test2",
|
||||
}
|
||||
err = writeCapDefHashIntoLocal(testdir, fakeHashData)
|
||||
assert.NoError(t, err, "write new hash data successfully")
|
||||
result = readCapDefHashFromLocal(testdir)
|
||||
assert.Equal(t, result, fakeHashData, "read hash data successfully")
|
||||
}
|
||||
+10
-30
@@ -92,11 +92,11 @@ func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
ioStreams.Errorf("Error: failed to get Env: %s", err)
|
||||
return err
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env, cmd)
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env, cmd, c)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
@@ -107,8 +107,8 @@ func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta, cmd *cobra.Command) error {
|
||||
app, err := appfile.LoadApplication(env.Name, appName)
|
||||
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta, cmd *cobra.Command, velaC types.Args) error {
|
||||
app, err := appfile.LoadApplication(env.Namespace, appName, velaC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,8 +118,7 @@ func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOSt
|
||||
table := newUITable()
|
||||
table.AddRow(" Name:", appName)
|
||||
table.AddRow(" Namespace:", namespace)
|
||||
table.AddRow(" Created at:", app.CreateTime.String())
|
||||
table.AddRow(" Updated at:", app.UpdateTime.String())
|
||||
table.AddRow(" Created at:", app.CreationTimestamp.String())
|
||||
cmd.Printf("%s\n\n", table.String())
|
||||
|
||||
cmd.Printf("Services:\n\n")
|
||||
@@ -216,14 +215,14 @@ HealthCheckLoop:
|
||||
return healthStatus, healthInfo, nil
|
||||
}
|
||||
|
||||
func printTrackingDeployStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, compName, appName string, env *types.EnvMeta) (CompStatus, error) {
|
||||
func printTrackingDeployStatus(c types.Args, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta) (CompStatus, error) {
|
||||
sDeploy := newTrackingSpinnerWithDelay("Checking Status ...", trackingInterval)
|
||||
sDeploy.Start()
|
||||
defer sDeploy.Stop()
|
||||
TrackDeployLoop:
|
||||
for {
|
||||
time.Sleep(trackingInterval)
|
||||
deployStatus, failMsg, err := TrackDeployStatus(ctx, c, compName, appName, env)
|
||||
deployStatus, failMsg, err := TrackDeployStatus(c, appName, env)
|
||||
if err != nil {
|
||||
return compStatusUnknown, err
|
||||
}
|
||||
@@ -245,12 +244,12 @@ TrackDeployLoop:
|
||||
}
|
||||
|
||||
// TrackDeployStatus will only check AppConfig is deployed successfully,
|
||||
func TrackDeployStatus(ctx context.Context, c client.Client, compName, appName string, env *types.EnvMeta) (CompStatus, string, error) {
|
||||
app, appObj, err := getApp(ctx, c, compName, appName, env)
|
||||
func TrackDeployStatus(c types.Args, appName string, env *types.EnvMeta) (CompStatus, string, error) {
|
||||
appObj, err := appfile.LoadApplication(env.Namespace, appName, c)
|
||||
if err != nil {
|
||||
return compStatusUnknown, "", err
|
||||
}
|
||||
if app == nil || appObj == nil {
|
||||
if appObj == nil {
|
||||
return compStatusUnknown, "", errors.New(ErrNotLoadAppConfig)
|
||||
}
|
||||
condition := appObj.Status.Conditions
|
||||
@@ -319,25 +318,6 @@ func trackHealthCheckingStatus(ctx context.Context, c client.Client, compName, a
|
||||
return compStatusHealthCheckDone, HealthStatusNotDiagnosed, "", nil
|
||||
}
|
||||
|
||||
func getApp(ctx context.Context, c client.Client, compName, appName string, env *types.EnvMeta) (*api.Application, *v1alpha2.Application, error) {
|
||||
var app *api.Application
|
||||
var err error
|
||||
if appName != "" {
|
||||
app, err = appfile.LoadApplication(env.Name, appName)
|
||||
} else {
|
||||
app, err = appfile.MatchAppByComp(env.Name, compName)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
appObj, err := appfile.GetApplication(ctx, c, app, env)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return app, appObj, nil
|
||||
}
|
||||
|
||||
func getWorkloadStatusFromApp(app *v1alpha2.Application, compName string) (v1alpha2.ApplicationComponentStatus, bool) {
|
||||
foundWlStatus := false
|
||||
wlStatus := v1alpha2.ApplicationComponentStatus{}
|
||||
|
||||
@@ -111,7 +111,7 @@ func NewInstallCommand(c types.Args, chartContent string, ioStreams cmdutil.IOSt
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -172,9 +172,6 @@ func (i *initCmd) run(ioStreams cmdutil.IOStreams, chartSource string) error {
|
||||
"try running 'vela workloads' or 'vela traits' to check after a while, details: %v", err)
|
||||
return nil
|
||||
}
|
||||
if err := RefreshDefinitions(context.Background(), i.c, ioStreams, false, true); err != nil {
|
||||
return err
|
||||
}
|
||||
ioStreams.Info("- Finished successfully.")
|
||||
|
||||
if waitDuration > 0 {
|
||||
@@ -204,7 +201,7 @@ func CheckCapabilityReady(ctx context.Context, c types.Args, timeout time.Durati
|
||||
defer spiner.Stop()
|
||||
|
||||
for {
|
||||
_, err = plugins.GetCapabilitiesFromCluster(ctx, types.DefaultKubeVelaNS, c, tmpdir, nil)
|
||||
_, err = plugins.GetCapabilitiesFromCluster(ctx, types.DefaultKubeVelaNS, c, nil)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
name: first-vela-app
|
||||
services:
|
||||
testsvc:
|
||||
type: webservice
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
ingress:
|
||||
domain: testsvc.example.com
|
||||
http:
|
||||
"/": 8000
|
||||
abc:
|
||||
type: webservice
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
ingress:
|
||||
domain: testsvc.example.com
|
||||
http:
|
||||
"/": 8000
|
||||
+10
-16
@@ -1,7 +1,6 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -9,15 +8,13 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
// NewTraitsCommand creates `traits` command
|
||||
func NewTraitsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var workloadName string
|
||||
var enforceRefresh bool
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "traits [--apply-to WORKLOAD_NAME]",
|
||||
Use: "traits",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "List traits",
|
||||
Long: "List traits",
|
||||
@@ -26,12 +23,11 @@ func NewTraitsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if err := RefreshDefinitions(ctx, c, ioStreams, true, enforceRefresh); err != nil {
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printTraitList(&workloadName, ioStreams)
|
||||
return printTraitList(env.Namespace, c, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeCap,
|
||||
@@ -39,22 +35,20 @@ func NewTraitsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
|
||||
}
|
||||
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
cmd.Flags().StringVar(&workloadName, "apply-to", "", "Workload name")
|
||||
cmd.Flags().BoolVarP(&enforceRefresh, "", "r", false, "Enforce refresh from cluster even if cache is not expired")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printTraitList(workloadName *string, ioStreams cmdutil.IOStreams) error {
|
||||
func printTraitList(userNamespace string, c types.Args, ioStreams cmdutil.IOStreams) error {
|
||||
table := newUITable()
|
||||
table.MaxColWidth = 120
|
||||
table.Wrap = true
|
||||
traitDefinitionList, err := common.ListTraitDefinitions(workloadName)
|
||||
|
||||
traitDefinitionList, err := common.ListRawTraitDefinitions(userNamespace, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
table.AddRow("NAME", "DESCRIPTION", "APPLIES TO")
|
||||
table.AddRow("NAME", "NAMESPACE", "APPLIES-TO", "CONFLICTS-WITH", "DESCRIPTION")
|
||||
for _, t := range traitDefinitionList {
|
||||
table.AddRow(t.Name, t.Description, strings.Join(t.AppliesTo, "\n"))
|
||||
table.AddRow(t.Name, t.Namespace, strings.Join(t.Spec.AppliesToWorkloads, ","), strings.Join(t.Spec.ConflictsWith, ","), plugins.GetDescription(t.Annotations))
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gosuri/uitable"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -14,84 +12,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
)
|
||||
|
||||
func Test_printTraitList(t *testing.T) {
|
||||
traits := []types.Capability{
|
||||
{
|
||||
Name: "route",
|
||||
CrdName: "routes.oam.dev",
|
||||
// This format is currently OAM spec standard
|
||||
AppliesTo: []string{"apps/v1.Deployment", "alibaba/v1.Clonset"},
|
||||
},
|
||||
{
|
||||
Name: "scaler",
|
||||
CrdName: "scaler.oam.dev",
|
||||
// This format is also reasonable, it's align with oam definition name, so we also support here
|
||||
AppliesTo: []string{"deployments.apps"},
|
||||
},
|
||||
}
|
||||
workloads := []types.Capability{
|
||||
{
|
||||
Name: "deployment",
|
||||
CrdName: "deployments.apps",
|
||||
},
|
||||
{
|
||||
Name: "clonset",
|
||||
CrdName: "clonsets.alibaba",
|
||||
},
|
||||
}
|
||||
newTable := func() *uitable.Table {
|
||||
table := newUITable()
|
||||
table.AddRow("NAME", "DEFINITION", "APPLIES TO")
|
||||
return table
|
||||
}
|
||||
tb1 := newTable()
|
||||
tb1.AddRow("route", "routes.oam.dev", "deployment")
|
||||
tb1.AddRow("", "", "clonset")
|
||||
tb1.AddRow("scaler", "scaler.oam.dev", "deployment")
|
||||
|
||||
tb2 := newTable()
|
||||
tb2.AddRow("route", "routes.oam.dev", "deployment")
|
||||
tb2.AddRow("scaler", "scaler.oam.dev", "deployment")
|
||||
|
||||
tb3 := newTable()
|
||||
tb3.AddRow("route", "routes.oam.dev", "clonset")
|
||||
|
||||
cases := map[string]struct {
|
||||
traits []types.Capability
|
||||
workloads []types.Capability
|
||||
workloadName string
|
||||
iostream cmdutil.IOStreams
|
||||
ExpectedString string
|
||||
}{
|
||||
"All Workloads": {
|
||||
traits: traits,
|
||||
workloads: workloads,
|
||||
ExpectedString: tb1.String() + "\n",
|
||||
},
|
||||
"Specify Workload Name deployment": {
|
||||
traits: traits,
|
||||
workloads: workloads,
|
||||
workloadName: "deployment",
|
||||
ExpectedString: tb2.String() + "\n",
|
||||
},
|
||||
"Specify Workload Name clonset": {
|
||||
traits: traits,
|
||||
workloads: workloads,
|
||||
workloadName: "clonset",
|
||||
ExpectedString: tb3.String() + "\n",
|
||||
},
|
||||
}
|
||||
// TODO(zzxwill) As the old `func printTraitList(traits, workloads []types.Capability, workloadName *string, ioStreams cmdutil.IOStreams)`
|
||||
// doesn't exist any more, comment this unit-test for now
|
||||
//for cname, c := range cases {
|
||||
for _, c := range cases {
|
||||
b := bytes.Buffer{}
|
||||
iostream := cmdutil.IOStreams{Out: &b}
|
||||
nn := c.workloadName
|
||||
assert.NoError(t, printTraitList(&nn, iostream))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTraitsCommandPersistentPreRunE(t *testing.T) {
|
||||
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
fakeC := types.Args{}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -31,7 +30,7 @@ func NewUpCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubecli, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
kubecli, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -45,7 +44,7 @@ func NewUpCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.Run(filePath, c.Config)
|
||||
return o.Run(filePath, velaEnv.Namespace, c)
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStream.Out)
|
||||
|
||||
+11
-17
@@ -1,19 +1,16 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
// NewWorkloadsCommand creates `workloads` command
|
||||
func NewWorkloadsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var enforceRefresh bool
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "workloads",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -24,32 +21,29 @@ func NewWorkloadsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
return c.SetConfig()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if err := RefreshDefinitions(ctx, c, ioStreams, true, enforceRefresh); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printWorkloadList(workloads, ioStreams)
|
||||
return printWorkloadList(env.Namespace, c, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeCap,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
cmd.Flags().BoolVarP(&enforceRefresh, "", "r", false, "Enforce refresh from cluster even if cache is not expired")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printWorkloadList(workloadList []types.Capability, ioStreams cmdutil.IOStreams) error {
|
||||
func printWorkloadList(userNamespace string, c types.Args, ioStreams cmdutil.IOStreams) error {
|
||||
def, err := common.ListRawWorkloadDefinitions(userNamespace, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
table := newUITable()
|
||||
table.MaxColWidth = 120
|
||||
table.AddRow("NAME", "DESCRIPTION")
|
||||
for _, r := range workloadList {
|
||||
table.AddRow(r.Name, r.Description)
|
||||
table.AddRow("NAME", "NAMESPACE", "WORKLOAD", "DESCRIPTION")
|
||||
for _, r := range def {
|
||||
table.AddRow(r.Name, r.Namespace, r.Spec.Reference.Name, plugins.GetDescription(r.Annotations))
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
apitypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
corev1alpha2 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
@@ -95,6 +94,7 @@ type DeleteOptions struct {
|
||||
CompName string
|
||||
Client client.Client
|
||||
Env *types.EnvMeta
|
||||
C types.Args
|
||||
}
|
||||
|
||||
// ListApplications lists all applications
|
||||
@@ -224,19 +224,31 @@ func (o *DeleteOptions) DeleteApp() (string, error) {
|
||||
return "", fmt.Errorf("delete application err: %w", err)
|
||||
}
|
||||
|
||||
// TODO(wonderflow): delete the default health scope here
|
||||
for _, cmp := range app.Spec.Components {
|
||||
healthScopeName, ok := cmp.Scopes[api.DefaultHealthScopeKey]
|
||||
if ok {
|
||||
var healthScope corev1alpha2.HealthScope
|
||||
if err := o.Client.Get(ctx, client.ObjectKey{Namespace: o.Env.Namespace, Name: healthScopeName}, &healthScope); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return "", fmt.Errorf("delete health scope %s err: %w", healthScopeName, err)
|
||||
}
|
||||
if err = o.Client.Delete(ctx, &healthScope); err != nil {
|
||||
return "", fmt.Errorf("delete health scope %s err: %w", healthScopeName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("app \"%s\" deleted from env \"%s\"", o.AppName, o.Env.Name), nil
|
||||
}
|
||||
|
||||
// DeleteComponent will delete one component including server side.
|
||||
func (o *DeleteOptions) DeleteComponent(io cmdutil.IOStreams) (string, error) {
|
||||
var app *api.Application
|
||||
var err error
|
||||
if o.AppName != "" {
|
||||
app, err = appfile.LoadApplication(o.Env.Name, o.AppName)
|
||||
} else {
|
||||
app, err = appfile.MatchAppByComp(o.Env.Name, o.CompName)
|
||||
if o.AppName == "" {
|
||||
return "", errors.New("app name is required")
|
||||
}
|
||||
app, err := appfile.LoadApplication(o.Env.Namespace, o.AppName, o.C)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -249,24 +261,15 @@ func (o *DeleteOptions) DeleteComponent(io cmdutil.IOStreams) (string, error) {
|
||||
if err := appfile.RemoveComponent(app, o.CompName); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := appfile.Save(app, o.Env.Name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Remove component from appConfig in k8s cluster
|
||||
ctx := context.Background()
|
||||
if err := BuildRun(ctx, app, o.Client, o.Env, io); err != nil {
|
||||
|
||||
if err := o.Client.Update(ctx, app); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Remove component in k8s cluster
|
||||
var c corev1alpha2.Component
|
||||
c.Name = o.CompName
|
||||
c.Namespace = o.Env.Namespace
|
||||
err = o.Client.Delete(context.Background(), &c)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return "", fmt.Errorf("delete component err: %w", err)
|
||||
}
|
||||
// It's the server responsibility to GC component
|
||||
|
||||
return fmt.Sprintf("component \"%s\" deleted from \"%s\"", o.CompName, o.AppName), nil
|
||||
}
|
||||
@@ -359,8 +362,8 @@ func saveAndLoadRemoteAppfile(url string) (*api.AppFile, error) {
|
||||
}
|
||||
|
||||
// ExportFromAppFile exports Application from appfile object
|
||||
func (o *AppfileOptions) ExportFromAppFile(app *api.AppFile, quiet bool) (*BuildResult, []byte, error) {
|
||||
tm, err := template.Load()
|
||||
func (o *AppfileOptions) ExportFromAppFile(app *api.AppFile, namespace string, quiet bool, c types.Args) (*BuildResult, []byte, error) {
|
||||
tm, err := template.Load(namespace, c)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -401,7 +404,7 @@ func (o *AppfileOptions) ExportFromAppFile(app *api.AppFile, quiet bool) (*Build
|
||||
}
|
||||
|
||||
// Export export Application object from the path of Appfile
|
||||
func (o *AppfileOptions) Export(filePath string, quiet bool) (*BuildResult, []byte, error) {
|
||||
func (o *AppfileOptions) Export(filePath, namespace string, quiet bool, c types.Args) (*BuildResult, []byte, error) {
|
||||
var app *api.AppFile
|
||||
var err error
|
||||
if !quiet {
|
||||
@@ -410,9 +413,6 @@ func (o *AppfileOptions) Export(filePath string, quiet bool) (*BuildResult, []by
|
||||
if filePath != "" {
|
||||
if strings.HasPrefix(filePath, "https://") || strings.HasPrefix(filePath, "http://") {
|
||||
app, err = saveAndLoadRemoteAppfile(filePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
app, err = api.LoadFromFile(filePath)
|
||||
}
|
||||
@@ -426,16 +426,16 @@ func (o *AppfileOptions) Export(filePath string, quiet bool) (*BuildResult, []by
|
||||
if !quiet {
|
||||
o.IO.Info("Load Template ...")
|
||||
}
|
||||
return o.ExportFromAppFile(app, quiet)
|
||||
return o.ExportFromAppFile(app, namespace, quiet, c)
|
||||
}
|
||||
|
||||
// Run starts an application according to Appfile
|
||||
func (o *AppfileOptions) Run(filePath string, config *rest.Config) error {
|
||||
result, data, err := o.Export(filePath, false)
|
||||
func (o *AppfileOptions) Run(filePath, namespace string, c types.Args) error {
|
||||
result, data, err := o.Export(filePath, namespace, false, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dm, err := discoverymapper.New(config)
|
||||
dm, err := discoverymapper.New(c.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -259,9 +259,9 @@ func SyncCapabilityCenter(capabilityCenterName string) error {
|
||||
|
||||
// RemoveCapabilityFromCluster will remove a capability from cluster.
|
||||
// 1. remove definition 2. uninstall chart 3. remove local files
|
||||
func RemoveCapabilityFromCluster(client client.Client, capabilityName string) (string, error) {
|
||||
func RemoveCapabilityFromCluster(userNamespace string, c types.Args, client client.Client, capabilityName string) (string, error) {
|
||||
ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
||||
if err := RemoveCapability(client, capabilityName, ioStreams); err != nil {
|
||||
if err := RemoveCapability(userNamespace, c, client, capabilityName, ioStreams); err != nil {
|
||||
return "", err
|
||||
}
|
||||
msg := fmt.Sprintf("%s removed successfully", capabilityName)
|
||||
@@ -270,9 +270,9 @@ func RemoveCapabilityFromCluster(client client.Client, capabilityName string) (s
|
||||
|
||||
// RemoveCapability will remove a capability from cluster.
|
||||
// 1. remove definition 2. uninstall chart 3. remove local files
|
||||
func RemoveCapability(client client.Client, capabilityName string, ioStreams cmdutil.IOStreams) error {
|
||||
func RemoveCapability(userNamespace string, c types.Args, client client.Client, capabilityName string, ioStreams cmdutil.IOStreams) error {
|
||||
// TODO(wonderflow): make sure no apps is using this capability
|
||||
caps, err := plugins.LoadAllInstalledCapability()
|
||||
caps, err := plugins.LoadAllInstalledCapability(userNamespace, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -329,14 +329,14 @@ func uninstallCap(client client.Client, cap types.Capability, ioStreams cmdutil.
|
||||
}
|
||||
|
||||
// ListCapabilities will list all caps from specified center
|
||||
func ListCapabilities(capabilityCenterName string) ([]types.Capability, error) {
|
||||
func ListCapabilities(userNamespace string, c types.Args, capabilityCenterName string) ([]types.Capability, error) {
|
||||
var capabilityList []types.Capability
|
||||
dir, err := system.GetCapCenterDir()
|
||||
if err != nil {
|
||||
return capabilityList, err
|
||||
}
|
||||
if capabilityCenterName != "" {
|
||||
return listCenterCapabilities(filepath.Join(dir, capabilityCenterName))
|
||||
return listCenterCapabilities(userNamespace, c, filepath.Join(dir, capabilityCenterName))
|
||||
}
|
||||
dirs, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
@@ -346,7 +346,7 @@ func ListCapabilities(capabilityCenterName string) ([]types.Capability, error) {
|
||||
if !dd.IsDir() {
|
||||
continue
|
||||
}
|
||||
caps, err := listCenterCapabilities(filepath.Join(dir, dd.Name()))
|
||||
caps, err := listCenterCapabilities(userNamespace, c, filepath.Join(dir, dd.Name()))
|
||||
if err != nil {
|
||||
return capabilityList, err
|
||||
}
|
||||
@@ -355,7 +355,7 @@ func ListCapabilities(capabilityCenterName string) ([]types.Capability, error) {
|
||||
return capabilityList, nil
|
||||
}
|
||||
|
||||
func listCenterCapabilities(repoDir string) ([]types.Capability, error) {
|
||||
func listCenterCapabilities(userNamespace string, c types.Args, repoDir string) ([]types.Capability, error) {
|
||||
templates, err := plugins.LoadCapabilityFromSyncedCenter(repoDir)
|
||||
if err != nil {
|
||||
return templates, err
|
||||
@@ -364,9 +364,9 @@ func listCenterCapabilities(repoDir string) ([]types.Capability, error) {
|
||||
return templates, nil
|
||||
}
|
||||
baseDir := filepath.Base(repoDir)
|
||||
workloads := gatherWorkloads(templates)
|
||||
workloads := gatherWorkloads(userNamespace, c, templates)
|
||||
for i, p := range templates {
|
||||
status := checkInstallStatus(baseDir, p)
|
||||
status := checkInstallStatus(userNamespace, c, baseDir, p)
|
||||
convertedApplyTo := ConvertApplyTo(p.AppliesTo, workloads)
|
||||
templates[i].Center = baseDir
|
||||
templates[i].Status = status
|
||||
@@ -409,8 +409,8 @@ func RemoveCapabilityCenter(centerName string) (string, error) {
|
||||
return message, err
|
||||
}
|
||||
|
||||
func gatherWorkloads(templates []types.Capability) []types.Capability {
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
func gatherWorkloads(userNamespace string, c types.Args, templates []types.Capability) []types.Capability {
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(userNamespace, c, types.TypeWorkload)
|
||||
if err != nil {
|
||||
workloads = make([]types.Capability, 0)
|
||||
}
|
||||
@@ -422,9 +422,9 @@ func gatherWorkloads(templates []types.Capability) []types.Capability {
|
||||
return workloads
|
||||
}
|
||||
|
||||
func checkInstallStatus(repoName string, tmp types.Capability) string {
|
||||
func checkInstallStatus(userNamespace string, c types.Args, repoName string, tmp types.Capability) string {
|
||||
var status = "uninstalled"
|
||||
installed, _ := plugins.LoadInstalledCapabilityWithType(tmp.Type)
|
||||
installed, _ := plugins.LoadInstalledCapabilityWithType(userNamespace, c, tmp.Type)
|
||||
for _, i := range installed {
|
||||
if i.Source != nil && i.Source.RepoName == repoName && i.Name == tmp.Name && i.CrdName == tmp.CrdName {
|
||||
return "installed"
|
||||
|
||||
+48
-123
@@ -5,45 +5,79 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
plur "github.com/gertd/go-pluralize"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
client2 "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
// ListTraitDefinitions will list all definition include traits and workloads
|
||||
func ListTraitDefinitions(workloadName *string) ([]types.Capability, error) {
|
||||
func ListTraitDefinitions(userNamespace string, c types.Args, workloadName *string) ([]types.Capability, error) {
|
||||
var traitList []types.Capability
|
||||
traits, err := plugins.LoadInstalledCapabilityWithType(types.TypeTrait)
|
||||
traits, err := plugins.LoadInstalledCapabilityWithType(userNamespace, c, types.TypeTrait)
|
||||
if err != nil {
|
||||
return traitList, err
|
||||
}
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
workloads, err := plugins.LoadInstalledCapabilityWithType(userNamespace, c, types.TypeWorkload)
|
||||
if err != nil {
|
||||
return traitList, err
|
||||
}
|
||||
traitList = convertAllAppliyToList(traits, workloads, workloadName)
|
||||
traitList = convertAllApplyToList(traits, workloads, workloadName)
|
||||
return traitList, nil
|
||||
}
|
||||
|
||||
// ListRawTraitDefinitions will list raw definition
|
||||
func ListRawTraitDefinitions(userNamespace string, c types.Args) ([]v1alpha2.TraitDefinition, error) {
|
||||
client, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := util.SetNamespaceInCtx(context.Background(), userNamespace)
|
||||
traitList := v1alpha2.TraitDefinitionList{}
|
||||
if err = client.List(ctx, &traitList, client2.InNamespace(userNamespace)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sysTraitList := v1alpha2.TraitDefinitionList{}
|
||||
if err = client.List(ctx, &sysTraitList, client2.InNamespace(oam.SystemDefinitonNamespace)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(traitList.Items, sysTraitList.Items...), nil
|
||||
}
|
||||
|
||||
// ListRawWorkloadDefinitions will list raw definition
|
||||
func ListRawWorkloadDefinitions(userNamespace string, c types.Args) ([]v1alpha2.WorkloadDefinition, error) {
|
||||
client, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := util.SetNamespaceInCtx(context.Background(), userNamespace)
|
||||
workloadList := v1alpha2.WorkloadDefinitionList{}
|
||||
if err = client.List(ctx, &workloadList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sysWorkloadList := v1alpha2.WorkloadDefinitionList{}
|
||||
if err = client.List(ctx, &sysWorkloadList, client2.InNamespace(oam.SystemDefinitonNamespace)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(workloadList.Items, sysWorkloadList.Items...), nil
|
||||
}
|
||||
|
||||
// GetTraitDefinition will get trait capability with applyTo converted
|
||||
func GetTraitDefinition(workloadName *string, traitType string) (types.Capability, error) {
|
||||
func GetTraitDefinition(userNamespace string, c types.Args, workloadName *string, traitType string) (types.Capability, error) {
|
||||
var traitDef types.Capability
|
||||
traitCap, err := plugins.GetInstalledCapabilityWithCapName(types.TypeTrait, traitType)
|
||||
if err != nil {
|
||||
return traitDef, err
|
||||
}
|
||||
workloadsCap, err := plugins.LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
workloadsCap, err := plugins.LoadInstalledCapabilityWithType(userNamespace, c, types.TypeWorkload)
|
||||
if err != nil {
|
||||
return traitDef, err
|
||||
}
|
||||
traitList := convertAllAppliyToList([]types.Capability{traitCap}, workloadsCap, workloadName)
|
||||
traitList := convertAllApplyToList([]types.Capability{traitCap}, workloadsCap, workloadName)
|
||||
if len(traitList) != 1 {
|
||||
return traitDef, fmt.Errorf("could not get installed capability by %s", traitType)
|
||||
}
|
||||
@@ -51,7 +85,7 @@ func GetTraitDefinition(workloadName *string, traitType string) (types.Capabilit
|
||||
return traitDef, nil
|
||||
}
|
||||
|
||||
func convertAllAppliyToList(traits []types.Capability, workloads []types.Capability, workloadName *string) []types.Capability {
|
||||
func convertAllApplyToList(traits []types.Capability, workloads []types.Capability, workloadName *string) []types.Capability {
|
||||
var traitList []types.Capability
|
||||
for _, t := range traits {
|
||||
convertedApplyTo := ConvertApplyTo(t.AppliesTo, workloads)
|
||||
@@ -118,112 +152,3 @@ func Parse(applyTo string) string {
|
||||
}
|
||||
return plur.NewClient().Plural(strings.ToLower(l[1])) + "." + apigroup
|
||||
}
|
||||
|
||||
// ValidateAndMutateForCore was built in validate and mutate function for core workloads and traits
|
||||
func ValidateAndMutateForCore(traitType, workloadName string, flags *pflag.FlagSet, env *types.EnvMeta) error {
|
||||
switch traitType {
|
||||
case "route":
|
||||
domain, _ := flags.GetString("domain")
|
||||
if domain == "" {
|
||||
if env.Domain == "" {
|
||||
return fmt.Errorf("--domain is required if not contain in environment")
|
||||
}
|
||||
if strings.HasPrefix(env.Domain, "https://") {
|
||||
env.Domain = strings.TrimPrefix(env.Domain, "https://")
|
||||
}
|
||||
if strings.HasPrefix(env.Domain, "http://") {
|
||||
env.Domain = strings.TrimPrefix(env.Domain, "http://")
|
||||
}
|
||||
if err := flags.Set("domain", workloadName+"."+env.Domain); err != nil {
|
||||
return fmt.Errorf("set flag for vela-core trait('route') err %w, please make sure your template is right", err)
|
||||
}
|
||||
}
|
||||
issuer, _ := flags.GetString("issuer")
|
||||
if issuer == "" && env.Issuer != "" {
|
||||
if err := flags.Set("issuer", env.Issuer); err != nil {
|
||||
return fmt.Errorf("set flag for vela-core trait('route') err %w, please make sure your template is right", err)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// extend other trait here in the future
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddOrUpdateTrait attach trait to workload
|
||||
func AddOrUpdateTrait(env *types.EnvMeta, appName string, componentName string, flagSet *pflag.FlagSet, template types.Capability) (*api.Application, error) {
|
||||
err := ValidateAndMutateForCore(template.Name, componentName, flagSet, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if appName == "" {
|
||||
appName = componentName
|
||||
}
|
||||
app, err := appfile.LoadApplication(env.Name, appName)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
traitAlias := template.Name
|
||||
traitData, err := appfile.GetTraitsByType(app, componentName, traitAlias)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
for _, v := range template.Parameters {
|
||||
name := v.Name
|
||||
if v.Alias != "" {
|
||||
name = v.Alias
|
||||
}
|
||||
// nolint:exhaustive
|
||||
switch v.Type {
|
||||
case cue.IntKind:
|
||||
traitData[v.Name], err = flagSet.GetInt64(name)
|
||||
case cue.StringKind:
|
||||
traitData[v.Name], err = flagSet.GetString(name)
|
||||
case cue.BoolKind:
|
||||
traitData[v.Name], err = flagSet.GetBool(name)
|
||||
case cue.NumberKind, cue.FloatKind:
|
||||
traitData[v.Name], err = flagSet.GetFloat64(name)
|
||||
default:
|
||||
// Currently we don't support get value from complex type
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get flag(s) \"%s\" err %w", name, err)
|
||||
}
|
||||
}
|
||||
if err = appfile.SetTrait(app, componentName, traitAlias, traitData); err != nil {
|
||||
return app, err
|
||||
}
|
||||
return app, appfile.Save(app, env.Name)
|
||||
}
|
||||
|
||||
// TraitOperationRun will check if it's a stage operation before run
|
||||
func TraitOperationRun(ctx context.Context, c client.Client, env *types.EnvMeta, appObj *api.Application,
|
||||
staging bool, io cmdutil.IOStreams) (string, error) {
|
||||
if staging {
|
||||
return "Staging saved", nil
|
||||
}
|
||||
err := BuildRun(ctx, appObj, c, env, io)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Deployed!", nil
|
||||
}
|
||||
|
||||
// PrepareDetachTrait will detach trait in local AppFile
|
||||
func PrepareDetachTrait(envName string, traitType string, componentName string, appName string) (*api.Application, error) {
|
||||
var appObj *api.Application
|
||||
var err error
|
||||
if appName == "" {
|
||||
appName = componentName
|
||||
}
|
||||
if appObj, err = appfile.LoadApplication(envName, appName); err != nil {
|
||||
return appObj, err
|
||||
}
|
||||
|
||||
if err = appfile.RemoveTrait(appObj, componentName, traitType); err != nil {
|
||||
return appObj, err
|
||||
}
|
||||
return appObj, appfile.Save(appObj, envName)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -28,27 +27,20 @@ type RunOptions struct {
|
||||
util.IOStreams
|
||||
}
|
||||
|
||||
// LoadIfExist will load Application from local dir
|
||||
func LoadIfExist(envName string, workloadName string, appGroup string) (*api.Application, error) {
|
||||
// InitApplication will load Application from cluster
|
||||
func InitApplication(env *types.EnvMeta, c types.Args, workloadName string, appGroup string) (*api.Application, error) {
|
||||
var appName string
|
||||
if appGroup != "" {
|
||||
appName = appGroup
|
||||
} else {
|
||||
appName = workloadName
|
||||
}
|
||||
app, err := appfile.LoadApplication(envName, appName)
|
||||
|
||||
// can't handle
|
||||
if err != nil && !appfile.IsNotFound(appName, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(wonderflow): we should load the existing application from cluster and convert to appfile
|
||||
// app, err := appfile.LoadApplication(env.Namespace, appName, c)
|
||||
// compatible application not found
|
||||
if app == nil {
|
||||
app, err = appfile.NewEmptyApplication()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app, err := appfile.NewEmptyApplication(env.Namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app.Name = appName
|
||||
|
||||
@@ -56,8 +48,8 @@ func LoadIfExist(envName string, workloadName string, appGroup string) (*api.App
|
||||
}
|
||||
|
||||
// BaseComplete will construct an Application from cli parameters.
|
||||
func BaseComplete(envName string, workloadName string, appName string, flagSet *pflag.FlagSet, workloadType string) (*api.Application, error) {
|
||||
app, err := LoadIfExist(envName, workloadName, appName)
|
||||
func BaseComplete(env *types.EnvMeta, c types.Args, workloadName string, appName string, flagSet *pflag.FlagSet, workloadType string) (*api.Application, error) {
|
||||
app, err := InitApplication(env, c, workloadName, appName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,7 +61,7 @@ func BaseComplete(envName string, workloadName string, appName string, flagSet *
|
||||
// Not exist
|
||||
tp = workloadType
|
||||
}
|
||||
template, err := plugins.LoadCapabilityByName(tp)
|
||||
template, err := plugins.LoadCapabilityByName(tp, env.Namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -129,17 +121,5 @@ func BaseComplete(envName string, workloadName string, appName string, flagSet *
|
||||
if err = appfile.SetWorkload(app, workloadName, tp, workloadData); err != nil {
|
||||
return app, err
|
||||
}
|
||||
return app, appfile.Save(app, envName)
|
||||
}
|
||||
|
||||
// BaseRun will check if it's a stating operation before run
|
||||
func BaseRun(staging bool, app *api.Application, kubeClient client.Client, env *types.EnvMeta, io util.IOStreams) (string, error) {
|
||||
if staging {
|
||||
return "Staging saved", nil
|
||||
}
|
||||
if err := BuildRun(context.Background(), app, kubeClient, env, io); err != nil {
|
||||
err = fmt.Errorf("create app err: %w", err)
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("App %s deployed", app.Name), nil
|
||||
return app, appfile.Save(app, env.Name)
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ func StoreRepos(repos []CapCenterConfig) error {
|
||||
}
|
||||
|
||||
// ParseAndSyncCapability will convert config from remote center to capability
|
||||
func ParseAndSyncCapability(data []byte, syncDir string) (types.Capability, error) {
|
||||
func ParseAndSyncCapability(data []byte) (types.Capability, error) {
|
||||
var obj = unstructured.Unstructured{Object: make(map[string]interface{})}
|
||||
err := yaml.Unmarshal(data, &obj.Object)
|
||||
if err != nil {
|
||||
@@ -175,14 +175,14 @@ func ParseAndSyncCapability(data []byte, syncDir string) (types.Capability, erro
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(rd.Name, syncDir, rd.Spec.Reference.Name, rd.Annotations, rd.Spec.Extension, types.TypeWorkload, nil, rd.Spec.Schematic)
|
||||
return HandleDefinition(rd.Name, rd.Spec.Reference.Name, rd.Annotations, rd.Spec.Extension, types.TypeWorkload, nil, rd.Spec.Schematic)
|
||||
case "TraitDefinition":
|
||||
var td v1alpha2.TraitDefinition
|
||||
err = yaml.Unmarshal(data, &td)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic)
|
||||
return HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic)
|
||||
case "ScopeDefinition":
|
||||
// TODO(wonderflow): support scope definition here.
|
||||
}
|
||||
@@ -241,7 +241,7 @@ func (g *GithubCenter) SyncCapabilityFromCenter() error {
|
||||
return fmt.Errorf("decode github content %s err %w", *fileContent.Path, err)
|
||||
}
|
||||
}
|
||||
tmp, err := ParseAndSyncCapability(data, filepath.Join(dir, ".tmp"))
|
||||
tmp, err := ParseAndSyncCapability(data)
|
||||
if err != nil {
|
||||
fmt.Printf("parse definition of %s err %v\n", *fileContent.Name, err)
|
||||
continue
|
||||
|
||||
@@ -3,9 +3,7 @@ package plugins
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -20,7 +18,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
util2 "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
@@ -28,12 +25,12 @@ import (
|
||||
const DescriptionUndefined = "description not defined"
|
||||
|
||||
// GetCapabilitiesFromCluster will get capability from K8s cluster
|
||||
func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c types.Args, syncDir string, selector labels.Selector) ([]types.Capability, error) {
|
||||
workloads, _, err := GetWorkloadsFromCluster(ctx, namespace, c, syncDir, selector)
|
||||
func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c types.Args, selector labels.Selector) ([]types.Capability, error) {
|
||||
workloads, _, err := GetWorkloadsFromCluster(ctx, namespace, c, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
traits, _, err := GetTraitsFromCluster(ctx, namespace, c, syncDir, selector)
|
||||
traits, _, err := GetTraitsFromCluster(ctx, namespace, c, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,8 +39,8 @@ func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c types.A
|
||||
}
|
||||
|
||||
// GetWorkloadsFromCluster will get capability from K8s cluster
|
||||
func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args, syncDir string, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -61,11 +58,12 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args
|
||||
|
||||
var templateErrors []error
|
||||
for _, wd := range workloadDefs.Items {
|
||||
tmp, err := HandleDefinition(wd.Name, syncDir, wd.Spec.Reference.Name, wd.Annotations, wd.Spec.Extension, types.TypeWorkload, nil, wd.Spec.Schematic)
|
||||
tmp, err := HandleDefinition(wd.Name, wd.Spec.Reference.Name, wd.Annotations, wd.Spec.Extension, types.TypeWorkload, nil, wd.Spec.Schematic)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "handle workload template `%s` failed", wd.Name))
|
||||
continue
|
||||
}
|
||||
tmp.Namespace = namespace
|
||||
if tmp, err = validateCapabilities(tmp, dm, wd.Name, wd.Spec.Reference); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -75,8 +73,8 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args
|
||||
}
|
||||
|
||||
// GetTraitsFromCluster will get capability from K8s cluster
|
||||
func GetTraitsFromCluster(ctx context.Context, namespace string, c types.Args, syncDir string, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
func GetTraitsFromCluster(ctx context.Context, namespace string, c types.Args, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -93,11 +91,12 @@ func GetTraitsFromCluster(ctx context.Context, namespace string, c types.Args, s
|
||||
|
||||
var templateErrors []error
|
||||
for _, td := range traitDefs.Items {
|
||||
tmp, err := HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic)
|
||||
tmp, err := HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "handle trait template `%s` failed", td.Name))
|
||||
continue
|
||||
}
|
||||
tmp.Namespace = namespace
|
||||
if tmp, err = validateCapabilities(tmp, dm, td.Name, td.Spec.Reference); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -134,9 +133,9 @@ func validateCapabilities(tmp types.Capability, dm discoverymapper.DiscoveryMapp
|
||||
}
|
||||
|
||||
// HandleDefinition will handle definition to capability
|
||||
func HandleDefinition(name, syncDir, crdName string, annotation map[string]string, extension *runtime.RawExtension, tp types.CapType, applyTo []string, schematic *corev1alpha2.Schematic) (types.Capability, error) {
|
||||
func HandleDefinition(name, crdName string, annotation map[string]string, extension *runtime.RawExtension, tp types.CapType, applyTo []string, schematic *corev1alpha2.Schematic) (types.Capability, error) {
|
||||
var tmp types.Capability
|
||||
tmp, err := HandleTemplate(extension, schematic, name, syncDir)
|
||||
tmp, err := HandleTemplate(extension, schematic, name)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
@@ -158,11 +157,12 @@ func GetDescription(annotation map[string]string) string {
|
||||
if !ok {
|
||||
return DescriptionUndefined
|
||||
}
|
||||
desc = strings.ReplaceAll(desc, "\n", " ")
|
||||
return desc
|
||||
}
|
||||
|
||||
// HandleTemplate will handle definition template to capability
|
||||
func HandleTemplate(in *runtime.RawExtension, schematic *corev1alpha2.Schematic, name, syncDir string) (types.Capability, error) {
|
||||
func HandleTemplate(in *runtime.RawExtension, schematic *corev1alpha2.Schematic, name string) (types.Capability, error) {
|
||||
tmp, err := util.ConvertTemplateJSON2Object(name, in, schematic)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
@@ -183,15 +183,10 @@ func HandleTemplate(in *runtime.RawExtension, schematic *corev1alpha2.Schematic,
|
||||
if tmp.CueTemplate == "" {
|
||||
return types.Capability{}, errors.New("template not exist in definition")
|
||||
}
|
||||
_, _ = system.CreateIfNotExist(syncDir)
|
||||
filePath := filepath.Join(syncDir, name+".cue")
|
||||
//nolint:gosec
|
||||
err = ioutil.WriteFile(filePath, []byte(tmp.CueTemplate), 0644)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
tmp.DefinitionPath = filePath
|
||||
tmp.Parameters, err = cue.GetParameters(filePath)
|
||||
tmp.Parameters, err = cue.GetParameters(tmp.CueTemplate)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
@@ -203,7 +198,7 @@ func SyncDefinitionsToLocal(ctx context.Context, c types.Args, localDefinitionDi
|
||||
var syncedTemplates []types.Capability
|
||||
var warnings []string
|
||||
|
||||
templates, templateErrors, err := GetWorkloadsFromCluster(ctx, types.DefaultKubeVelaNS, c, localDefinitionDir, nil)
|
||||
templates, templateErrors, err := GetWorkloadsFromCluster(ctx, types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -215,7 +210,7 @@ func SyncDefinitionsToLocal(ctx context.Context, c types.Args, localDefinitionDi
|
||||
syncedTemplates = append(syncedTemplates, templates...)
|
||||
SinkTemp2Local(templates, localDefinitionDir)
|
||||
|
||||
templates, templateErrors, err = GetTraitsFromCluster(ctx, types.DefaultKubeVelaNS, c, localDefinitionDir, nil)
|
||||
templates, templateErrors, err = GetTraitsFromCluster(ctx, types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
@@ -233,7 +228,7 @@ func SyncDefinitionsToLocal(ctx context.Context, c types.Args, localDefinitionDi
|
||||
func SyncDefinitionToLocal(ctx context.Context, c types.Args, localDefinitionDir string, capabilityName string) (*types.Capability, error) {
|
||||
var foundCapability bool
|
||||
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -244,7 +239,7 @@ func SyncDefinitionToLocal(ctx context.Context, c types.Args, localDefinitionDir
|
||||
foundCapability = true
|
||||
}
|
||||
if foundCapability {
|
||||
template, err := HandleDefinition(capabilityName, localDefinitionDir, workloadDef.Spec.Reference.Name,
|
||||
template, err := HandleDefinition(capabilityName, workloadDef.Spec.Reference.Name,
|
||||
workloadDef.Annotations, workloadDef.Spec.Extension, types.TypeWorkload, nil, workloadDef.Spec.Schematic)
|
||||
if err == nil {
|
||||
return &template, nil
|
||||
@@ -258,7 +253,7 @@ func SyncDefinitionToLocal(ctx context.Context, c types.Args, localDefinitionDir
|
||||
foundCapability = true
|
||||
}
|
||||
if foundCapability {
|
||||
template, err := HandleDefinition(capabilityName, localDefinitionDir, traitDef.Spec.Reference.Name,
|
||||
template, err := HandleDefinition(capabilityName, traitDef.Spec.Reference.Name,
|
||||
traitDef.Annotations, traitDef.Spec.Extension, types.TypeTrait, nil, workloadDef.Spec.Schematic)
|
||||
if err == nil {
|
||||
return &template, nil
|
||||
|
||||
@@ -108,7 +108,7 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
// Notice!! DefinitionPath Object is Cluster Scope object
|
||||
// which means objects created in other DefinitionNamespace will also affect here.
|
||||
It("gettrait", func() {
|
||||
traitDefs, _, err := GetTraitsFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, definitionDir, selector)
|
||||
traitDefs, _, err := GetTraitsFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, selector)
|
||||
Expect(err).Should(BeNil())
|
||||
logf.Log.Info(fmt.Sprintf("Getting trait definitions %v", traitDefs))
|
||||
for i := range traitDefs {
|
||||
@@ -116,7 +116,6 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
By("check CueTemplate is fulfilled")
|
||||
Expect(traitDefs[i].CueTemplate).ShouldNot(BeEmpty())
|
||||
traitDefs[i].CueTemplate = ""
|
||||
traitDefs[i].DefinitionPath = ""
|
||||
}
|
||||
Expect(traitDefs).Should(Equal([]types.Capability{route}))
|
||||
})
|
||||
@@ -124,7 +123,7 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
// Notice!! DefinitionPath Object is Cluster Scope object
|
||||
// which means objects created in other DefinitionNamespace will also affect here.
|
||||
It("getworkload", func() {
|
||||
workloadDefs, _, err := GetWorkloadsFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, definitionDir, selector)
|
||||
workloadDefs, _, err := GetWorkloadsFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, selector)
|
||||
Expect(err).Should(BeNil())
|
||||
logf.Log.Info(fmt.Sprintf("Getting workload definitions %v", workloadDefs))
|
||||
for i := range workloadDefs {
|
||||
@@ -132,17 +131,15 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
By("check CueTemplate is fulfilled")
|
||||
Expect(workloadDefs[i].CueTemplate).ShouldNot(BeEmpty())
|
||||
workloadDefs[i].CueTemplate = ""
|
||||
workloadDefs[i].DefinitionPath = ""
|
||||
}
|
||||
Expect(workloadDefs).Should(Equal([]types.Capability{deployment, websvc}))
|
||||
})
|
||||
It("getall", func() {
|
||||
alldef, err := GetCapabilitiesFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, definitionDir, selector)
|
||||
alldef, err := GetCapabilitiesFromCluster(context.Background(), DefinitionNamespace, types.Args{Config: cfg, Schema: scheme}, selector)
|
||||
Expect(err).Should(BeNil())
|
||||
logf.Log.Info(fmt.Sprintf("Getting all definitions %v", alldef))
|
||||
for i := range alldef {
|
||||
alldef[i].CueTemplate = ""
|
||||
alldef[i].DefinitionPath = ""
|
||||
}
|
||||
Expect(alldef).Should(Equal([]types.Capability{deployment, websvc, route}))
|
||||
})
|
||||
|
||||
+37
-13
@@ -2,6 +2,7 @@ package plugins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -14,8 +15,8 @@ import (
|
||||
)
|
||||
|
||||
// LoadCapabilityByName will load capability from local by name
|
||||
func LoadCapabilityByName(name string) (types.Capability, error) {
|
||||
caps, err := LoadAllInstalledCapability()
|
||||
func LoadCapabilityByName(name string, userNamespace string, c types.Args) (types.Capability, error) {
|
||||
caps, err := LoadAllInstalledCapability(userNamespace, c)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
@@ -28,26 +29,49 @@ func LoadCapabilityByName(name string) (types.Capability, error) {
|
||||
}
|
||||
|
||||
// LoadAllInstalledCapability will list all capability
|
||||
func LoadAllInstalledCapability() ([]types.Capability, error) {
|
||||
workloads, err := LoadInstalledCapabilityWithType(types.TypeWorkload)
|
||||
func LoadAllInstalledCapability(userNamespace string, c types.Args) ([]types.Capability, error) {
|
||||
caps, err := GetCapabilitiesFromCluster(context.TODO(), userNamespace, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
traits, err := LoadInstalledCapabilityWithType(types.TypeTrait)
|
||||
systemCaps, err := GetCapabilitiesFromCluster(context.TODO(), types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workloads = append(workloads, traits...)
|
||||
return workloads, nil
|
||||
caps = append(caps, systemCaps...)
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
// LoadInstalledCapabilityWithType will load cap list by type
|
||||
func LoadInstalledCapabilityWithType(capT types.CapType) ([]types.Capability, error) {
|
||||
dir, err := system.GetCapabilityDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func LoadInstalledCapabilityWithType(userNamespace string, c types.Args, capT types.CapType) ([]types.Capability, error) {
|
||||
switch capT {
|
||||
case types.TypeWorkload:
|
||||
caps, _, err := GetWorkloadsFromCluster(context.TODO(), userNamespace, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
systemCaps, _, err := GetWorkloadsFromCluster(context.TODO(), types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caps = append(caps, systemCaps...)
|
||||
return caps, nil
|
||||
case types.TypeTrait:
|
||||
caps, _, err := GetTraitsFromCluster(context.TODO(), userNamespace, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
systemCaps, _, err := GetTraitsFromCluster(context.TODO(), types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caps = append(caps, systemCaps...)
|
||||
return caps, nil
|
||||
case types.TypeScope:
|
||||
|
||||
}
|
||||
return loadInstalledCapabilityWithType(dir, capT)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetInstalledCapabilityWithCapName will get cap by alias
|
||||
@@ -210,7 +234,7 @@ func LoadCapabilityFromSyncedCenter(dir string) ([]types.Capability, error) {
|
||||
fmt.Printf("read file %s err %v\n", f.Name(), err)
|
||||
continue
|
||||
}
|
||||
tmp, err := ParseAndSyncCapability(data, filepath.Join(dir, ".tmp"))
|
||||
tmp, err := ParseAndSyncCapability(data)
|
||||
if err != nil {
|
||||
fmt.Printf("get definition of %s err %v\n", f.Name(), err)
|
||||
continue
|
||||
|
||||
@@ -183,7 +183,11 @@ func setDisplayFormat(format string) {
|
||||
|
||||
// GenerateReferenceDocs generates reference docs
|
||||
func (ref *MarkdownReference) GenerateReferenceDocs(baseRefPath string) error {
|
||||
caps, err := LoadAllInstalledCapability()
|
||||
c, err := common.InitBaseRestConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
caps, err := LoadAllInstalledCapability("default", c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate reference docs for all capabilities: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user