mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
@@ -26,8 +26,8 @@ var _ = ginkgo.Describe("Application", func() {
|
||||
e2e.ComponentListContext("ls", applicationName, "")
|
||||
e2e.TraitManualScalerAttachContext("vela attach scaler trait", traitAlias, applicationName)
|
||||
e2e.ApplicationShowContext("show", applicationName, workloadType)
|
||||
e2e.ApplicationStatusContext("app status", applicationName, workloadType)
|
||||
e2e.ApplicationCompStatusContext("svc status", applicationName, workloadType, envName)
|
||||
e2e.ApplicationStatusContext("status", applicationName, workloadType)
|
||||
e2e.ApplicationStatusDeeplyContext("status", applicationName, workloadType, envName)
|
||||
e2e.ApplicationExecContext("exec -- COMMAND", applicationName)
|
||||
e2e.ApplicationPortForwardContext("port-forward", applicationName)
|
||||
e2e.ApplicationInitIntercativeCliContext("init", appNameForInit, workloadType)
|
||||
|
||||
@@ -183,7 +183,7 @@ var (
|
||||
ApplicationStatusContext = func(context string, applicationName string, workloadType string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get status for the application", func() {
|
||||
cli := fmt.Sprintf("vela app status %s", applicationName)
|
||||
cli := fmt.Sprintf("vela status %s", applicationName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring(applicationName))
|
||||
@@ -192,7 +192,7 @@ var (
|
||||
})
|
||||
}
|
||||
|
||||
ApplicationCompStatusContext = func(context string, applicationName, workloadType, envName string) bool {
|
||||
ApplicationStatusDeeplyContext = func(context string, applicationName, workloadType, envName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get status of the service", func() {
|
||||
ginkgo.By("init new k8s client")
|
||||
@@ -206,7 +206,7 @@ var (
|
||||
return len(appConfig.Status.Workloads)
|
||||
}, 90*time.Second, 1*time.Second).ShouldNot(gomega.Equal(0))
|
||||
|
||||
cli := fmt.Sprintf("vela svc status %s", applicationName)
|
||||
cli := fmt.Sprintf("vela status %s", applicationName)
|
||||
output, err := LongTimeExec(cli, 120*time.Second)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("Checking health status"))
|
||||
|
||||
@@ -20,7 +20,6 @@ func NewAppsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
NewAppStatusCommand(c, ioStreams),
|
||||
NewRunCommand(c, ioStreams))
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ func NewCommand() *cobra.Command {
|
||||
NewListCommand(commandArgs, ioStream),
|
||||
NewDeleteCommand(commandArgs, ioStream),
|
||||
NewAppShowCommand(ioStream),
|
||||
NewAppStatusCommand(commandArgs, ioStream),
|
||||
|
||||
// Workloads
|
||||
AddCompCommands(commandArgs, ioStream),
|
||||
|
||||
@@ -41,9 +41,7 @@ func AddCompCommands(c types.Args, ioStreams util.IOStreams) *cobra.Command {
|
||||
compCommands.PersistentFlags().StringP(App, "a", "", "specify the name of application containing the services")
|
||||
|
||||
compCommands.AddCommand(
|
||||
|
||||
NewCompDeployCommands(c, ioStreams),
|
||||
NewCompStatusCommand(c, ioStreams),
|
||||
)
|
||||
return compCommands
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/gosuri/uitable"
|
||||
"github.com/oam-dev/kubevela/api/types"
|
||||
"github.com/oam-dev/kubevela/pkg/application"
|
||||
@@ -49,44 +48,9 @@ func showApplication(cmd *cobra.Command, env *types.EnvMeta, appName string) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var svcFlag, chosenSvc string
|
||||
var svcFlagStatus string
|
||||
// to store the value of flag `--svc` set in Cli, or selected value in survey
|
||||
var targetServices []string
|
||||
if svcFlag = cmd.Flag("svc").Value.String(); svcFlag == "" {
|
||||
svcFlagStatus = oam.FlagNotSet
|
||||
} else {
|
||||
svcFlagStatus = oam.FlagIsInvalid
|
||||
}
|
||||
// all services name of the application `appName`
|
||||
var services []string
|
||||
for svcName := range app.Services {
|
||||
services = append(services, svcName)
|
||||
if svcFlag == svcName {
|
||||
svcFlagStatus = oam.FlagIsValid
|
||||
targetServices = append(targetServices, svcName)
|
||||
}
|
||||
}
|
||||
totalServices := len(services)
|
||||
if svcFlagStatus == oam.FlagNotSet && totalServices == 1 {
|
||||
targetServices = services
|
||||
}
|
||||
if svcFlagStatus == oam.FlagIsInvalid || (svcFlagStatus == oam.FlagNotSet && totalServices > 1) {
|
||||
if svcFlagStatus == oam.FlagIsInvalid {
|
||||
cmd.Printf("The service name '%s' is not valid\n", svcFlag)
|
||||
}
|
||||
chosenSvc, err = chooseSvc(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if chosenSvc == oam.DefaultChosenAllSvc {
|
||||
targetServices = services
|
||||
} else {
|
||||
targetServices = targetServices[:0]
|
||||
targetServices = append(targetServices, chosenSvc)
|
||||
}
|
||||
targetServices, err := oam.GetServicesWhenDescribingApplication(cmd, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.Printf("About:\n\n")
|
||||
@@ -160,18 +124,3 @@ func showComponent(cmd *cobra.Command, env *types.EnvMeta, compName, appName str
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func chooseSvc(services []string) (string, error) {
|
||||
var svcName string
|
||||
services = append(services, oam.DefaultChosenAllSvc)
|
||||
prompt := &survey.Select{
|
||||
Message: "Please choose one service: ",
|
||||
Options: services,
|
||||
Default: oam.DefaultChosenAllSvc,
|
||||
}
|
||||
err := survey.AskOne(prompt, &svcName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve services of the application, err %v", err)
|
||||
}
|
||||
return svcName, nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/api/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/application"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
|
||||
oam2 "github.com/oam-dev/kubevela/pkg/oam"
|
||||
@@ -78,14 +77,7 @@ const (
|
||||
ErrServiceNotFound = "service %s not found in app"
|
||||
)
|
||||
|
||||
const (
|
||||
firstElemPrefix = `├─`
|
||||
lastElemPrefix = `└─`
|
||||
pipe = `│ `
|
||||
)
|
||||
|
||||
var (
|
||||
gray = color.New(color.FgHiBlack)
|
||||
red = color.New(color.FgRed)
|
||||
green = color.New(color.FgGreen)
|
||||
yellow = color.New(color.FgYellow)
|
||||
@@ -131,129 +123,48 @@ func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env)
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP("svc", "s", "", "service name")
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta) error {
|
||||
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta, cmd *cobra.Command) error {
|
||||
app, err := application.Load(env.Name, appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namespace := env.Name
|
||||
tbl := uitable.New()
|
||||
tbl.Separator = " "
|
||||
tbl.AddRow(
|
||||
white.Sprint("NAMESPCAE"),
|
||||
white.Sprint("NAME"),
|
||||
white.Sprint("INFO"))
|
||||
|
||||
tbl.AddRow(
|
||||
namespace,
|
||||
fmt.Sprintf("%s/%s",
|
||||
"Application",
|
||||
appName))
|
||||
|
||||
components := app.GetComponents()
|
||||
// get a map coantaining all workloads health condition
|
||||
wlConditionsMap, err := getWorkloadHealthConditions(ctx, c, app, namespace)
|
||||
targetServices, err := oam2.GetServicesWhenDescribingApplication(cmd, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for cIndex, compName := range components {
|
||||
var cPrefix string
|
||||
switch cIndex {
|
||||
case len(components) - 1:
|
||||
cPrefix = lastElemPrefix
|
||||
default:
|
||||
cPrefix = firstElemPrefix
|
||||
cmd.Printf("About:\n\n")
|
||||
table := uitable.New()
|
||||
table.AddRow(" Name:", appName)
|
||||
table.AddRow(" Namespace:", namespace)
|
||||
table.AddRow(" Created at:", app.CreateTime.String())
|
||||
table.AddRow(" Updated at:", app.UpdateTime.String())
|
||||
cmd.Printf("%s\n\n", table.String())
|
||||
|
||||
cmd.Printf("Services:\n\n")
|
||||
|
||||
for _, svcName := range targetServices {
|
||||
if err := printComponentStatus(ctx, c, ioStreams, svcName, appName, env); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wlHealthCondition := wlConditionsMap[compName]
|
||||
wlHealthStatus := wlHealthCondition.HealthStatus
|
||||
healthColor := getHealthStatusColor(wlHealthStatus)
|
||||
|
||||
// print component info
|
||||
tbl.AddRow("",
|
||||
fmt.Sprintf("%s%s/%s",
|
||||
gray.Sprint(printPrefix(cPrefix)),
|
||||
"Component",
|
||||
compName),
|
||||
healthColor.Sprintf("%s %s", wlHealthStatus, wlHealthCondition.Diagnosis))
|
||||
}
|
||||
ioStreams.Info(tbl)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// map componentName <=> WorkloadHealthCondition
|
||||
func getWorkloadHealthConditions(ctx context.Context, c client.Client, app *application.Application, ns string) (map[string]*WorkloadHealthCondition, error) {
|
||||
hs := &v1alpha2.HealthScope{}
|
||||
// only use default health scope
|
||||
hsName := appfile.FormatDefaultHealthScopeName(app.Name)
|
||||
if err := c.Get(ctx, client.ObjectKey{Namespace: ns, Name: hsName}, hs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wlConditions := hs.Status.WorkloadHealthConditions
|
||||
r := map[string]*WorkloadHealthCondition{}
|
||||
components := app.GetComponents()
|
||||
for _, compName := range components {
|
||||
for _, wlhc := range wlConditions {
|
||||
if wlhc.ComponentName == compName {
|
||||
r[compName] = wlhc
|
||||
break
|
||||
}
|
||||
}
|
||||
if r[compName] == nil {
|
||||
r[compName] = &WorkloadHealthCondition{
|
||||
HealthStatus: HealthStatusNotDiagnosed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func NewCompStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
ctx := context.Background()
|
||||
cmd := &cobra.Command{
|
||||
Use: "status <SERVICE-NAME>",
|
||||
Short: "get status of a service",
|
||||
Long: "get status of a service, including its workload and health status",
|
||||
Example: `vela svc status <SERVICE-NAME>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
argsLength := len(args)
|
||||
if argsLength == 0 {
|
||||
ioStreams.Errorf("Hint: please specify the service name")
|
||||
os.Exit(1)
|
||||
}
|
||||
compName := args[0]
|
||||
env, err := GetEnv(cmd)
|
||||
if err != nil {
|
||||
ioStreams.Errorf("Error: failed to get Env: %s", err)
|
||||
return err
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appName, _ := cmd.Flags().GetString(App)
|
||||
return printComponentStatus(ctx, newClient, ioStreams, compName, appName, env)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
},
|
||||
}
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, compName, appName string, env *types.EnvMeta) error {
|
||||
app, appConfig, err := getApp(ctx, c, compName, appName, env)
|
||||
if err != nil {
|
||||
@@ -267,20 +178,25 @@ func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmduti
|
||||
return fmt.Errorf(ErrServiceNotFound, compName)
|
||||
}
|
||||
workloadType := svc.GetType()
|
||||
ioStreams.Infof("Showing status of service(type: %s) %s deployed in Environment %s\n", workloadType, white.Sprint(compName), env.Name)
|
||||
|
||||
healthStatus, healthInfo, err := healthCheckLoop(ctx, c, compName, appName, env)
|
||||
if err != nil {
|
||||
ioStreams.Info(healthInfo)
|
||||
return err
|
||||
}
|
||||
ioStreams.Infof(white.Sprintf("Service %s Status:", compName))
|
||||
ioStreams.Infof(white.Sprintf(" - Name: %s\n", compName))
|
||||
ioStreams.Infof(" Type: %s\n", workloadType)
|
||||
|
||||
healthColor := getHealthStatusColor(healthStatus)
|
||||
healthInfo = strings.ReplaceAll(healthInfo, "\n", "\n\t") // formart healthInfo output
|
||||
ioStreams.Infof("\t %s %s\n", healthColor.Sprint(healthStatus), healthColor.Sprint(healthInfo))
|
||||
healthInfo = strings.ReplaceAll(healthInfo, "\n", "\n\t") // format healthInfo output
|
||||
ioStreams.Infof(" %s %s\n", healthColor.Sprint(healthStatus), healthColor.Sprint(healthInfo))
|
||||
|
||||
ioStreams.Infof(" Last Deployment:\n")
|
||||
ioStreams.Infof(" Created at: %v\n", appConfig.CreationTimestamp)
|
||||
ioStreams.Infof(" Updated at: %v\n", app.UpdateTime.Format(time.RFC3339))
|
||||
|
||||
// workload Must found
|
||||
ioStreams.Infof(" Routes:\n")
|
||||
workloadStatus, _ := getWorkloadStatusFromAppConfig(appConfig, compName)
|
||||
for _, tr := range workloadStatus.Traits {
|
||||
traitType, traitInfo, err := traitCheckLoop(ctx, c, tr.Reference, compName, appConfig, app, 60*time.Second)
|
||||
@@ -288,12 +204,9 @@ func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmduti
|
||||
ioStreams.Infof("%s status: %s", white.Sprint(traitType), traitInfo)
|
||||
return err
|
||||
}
|
||||
ioStreams.Infof("\t%s: %s", white.Sprint(traitType), traitInfo)
|
||||
ioStreams.Infof(" - %s: %s", white.Sprint(traitType), traitInfo)
|
||||
}
|
||||
|
||||
ioStreams.Infof(white.Sprint("\nLast Deployment:\n"))
|
||||
ioStreams.Infof("\tCreated at: %v\n", appConfig.CreationTimestamp)
|
||||
ioStreams.Infof("\tUpdated at: %v\n", app.UpdateTime.Format(time.RFC3339))
|
||||
ioStreams.Info("")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -527,21 +440,6 @@ func applySpinnerNewSuffix(s *spinner.Spinner, suffix string) {
|
||||
s.Suffix = suffixColor.Sprintf(" %s", suffix)
|
||||
}
|
||||
|
||||
func printPrefix(p string) string {
|
||||
if strings.HasSuffix(p, firstElemPrefix) {
|
||||
p = strings.Replace(p, firstElemPrefix, pipe, strings.Count(p, firstElemPrefix)-1)
|
||||
} else {
|
||||
p = strings.ReplaceAll(p, firstElemPrefix, pipe)
|
||||
}
|
||||
|
||||
if strings.HasSuffix(p, lastElemPrefix) {
|
||||
p = strings.Replace(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))), strings.Count(p, lastElemPrefix)-1)
|
||||
} else {
|
||||
p = strings.ReplaceAll(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func getHealthStatusColor(s HealthStatus) *color.Color {
|
||||
var c *color.Color
|
||||
switch s {
|
||||
|
||||
@@ -6,11 +6,13 @@ import (
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/oam-dev/kubevela/api/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/application"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
|
||||
"github.com/oam-dev/kubevela/pkg/server/apis"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -241,3 +243,61 @@ func (o *DeleteOptions) DeleteComponent(io cmdutil.IOStreams) (string, error) {
|
||||
|
||||
return fmt.Sprintf("delete component succeed %s from %s", o.CompName, o.AppName), nil
|
||||
}
|
||||
|
||||
func chooseSvc(services []string) (string, error) {
|
||||
var svcName string
|
||||
services = append(services, DefaultChosenAllSvc)
|
||||
prompt := &survey.Select{
|
||||
Message: "Please choose one service: ",
|
||||
Options: services,
|
||||
Default: DefaultChosenAllSvc,
|
||||
}
|
||||
err := survey.AskOne(prompt, &svcName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve services of the application, err %v", err)
|
||||
}
|
||||
return svcName, nil
|
||||
}
|
||||
|
||||
// GetServicesWhenDescribingApplication gets the target services list either from cli `--svc` flag or from survey
|
||||
func GetServicesWhenDescribingApplication(cmd *cobra.Command, app *application.Application) ([]string, error) {
|
||||
var svcFlag string
|
||||
var svcFlagStatus string
|
||||
// to store the value of flag `--svc` set in Cli, or selected value in survey
|
||||
var targetServices []string
|
||||
if svcFlag = cmd.Flag("svc").Value.String(); svcFlag == "" {
|
||||
svcFlagStatus = FlagNotSet
|
||||
} else {
|
||||
svcFlagStatus = FlagIsInvalid
|
||||
}
|
||||
// all services name of the application `appName`
|
||||
var services []string
|
||||
for svcName := range app.Services {
|
||||
services = append(services, svcName)
|
||||
if svcFlag == svcName {
|
||||
svcFlagStatus = FlagIsValid
|
||||
targetServices = append(targetServices, svcName)
|
||||
}
|
||||
}
|
||||
totalServices := len(services)
|
||||
if svcFlagStatus == FlagNotSet && totalServices == 1 {
|
||||
targetServices = services
|
||||
}
|
||||
if svcFlagStatus == FlagIsInvalid || (svcFlagStatus == FlagNotSet && totalServices > 1) {
|
||||
if svcFlagStatus == FlagIsInvalid {
|
||||
cmd.Printf("The service name '%s' is not valid\n", svcFlag)
|
||||
}
|
||||
chosenSvc, err := chooseSvc(services)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
if chosenSvc == DefaultChosenAllSvc {
|
||||
targetServices = services
|
||||
} else {
|
||||
targetServices = targetServices[:0]
|
||||
targetServices = append(targetServices, chosenSvc)
|
||||
}
|
||||
}
|
||||
return targetServices, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user