mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
status app
This commit is contained in:
@@ -77,6 +77,7 @@ type Trait struct {
|
||||
Params map[string]interface{}
|
||||
Template string
|
||||
Health string
|
||||
Status string
|
||||
}
|
||||
|
||||
// EvalContext eval trait template and set result to context
|
||||
@@ -84,6 +85,11 @@ func (trait *Trait) EvalContext(ctx process.Context) error {
|
||||
return definition.NewTDTemplater(trait.Name, trait.Template, "").Params(trait.Params).Complete(ctx)
|
||||
}
|
||||
|
||||
// EvalStatus eval trait status
|
||||
func (trait *Trait) EvalStatus(ctx process.Context, cli client.Client, ns string) (string, error) {
|
||||
return definition.NewTDTemplater(trait.Name, "", "").Status(ctx, cli, ns, trait.Status)
|
||||
}
|
||||
|
||||
// EvalHealth eval trait health check
|
||||
func (trait *Trait) EvalHealth(ctx process.Context, client client.Client, name string) error {
|
||||
return definition.NewTDTemplater(trait.Name, "", trait.Health).Output(ctx, client, name).HealthCheck()
|
||||
@@ -188,6 +194,7 @@ func (p *Parser) parseTrait(name string, properties map[string]interface{}) (*Tr
|
||||
Params: properties,
|
||||
Template: templ.TemplateStr,
|
||||
Health: templ.Health,
|
||||
Status: templ.CustomStatus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -244,6 +251,37 @@ func (p *Parser) GenerateApplicationConfiguration(app *Appfile, ns string) (*v1a
|
||||
return appconfig, components, nil
|
||||
}
|
||||
|
||||
// PrintApplicationComponents print appComponent status for application
|
||||
func PrintApplicationComponents(app *Appfile, cli client.Client, ns string,
|
||||
printer func(compName string, appName string, traitsStatus map[string]string) error) error {
|
||||
|
||||
for _, wl := range app.Workloads {
|
||||
traitsStatus := map[string]string{}
|
||||
pCtx, err := PrepareProcessContext(cli, wl, app.Name, ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, tr := range wl.Traits {
|
||||
if err := tr.EvalContext(pCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, tr := range wl.Traits {
|
||||
status, err := tr.EvalStatus(pCtx, cli, ns)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "[%s.%s] eval error", wl.Name, tr.Name)
|
||||
}
|
||||
|
||||
traitsStatus[tr.Name] = status
|
||||
}
|
||||
if err := printer(wl.Name, app.Name, traitsStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// evalWorkloadWithContext evaluate the workload's template to generate component and ACComponent
|
||||
func evalWorkloadWithContext(pCtx process.Context, wl *Workload) (*v1alpha2.Component, *v1alpha2.ApplicationConfigurationComponent, error) {
|
||||
base, assists := pCtx.Output()
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/api"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/plugins"
|
||||
"github.com/oam-dev/kubevela/pkg/serverlib"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/env"
|
||||
@@ -103,8 +104,12 @@ func NewInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if deployStatus != compStatusDeployed {
|
||||
return nil
|
||||
}
|
||||
dm, err := discoverymapper.New(c.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printComponentStatus(context.Background(), o.client, o.IOStreams, o.workloadName, o.appName, o.Env)
|
||||
return printAppStatus(context.Background(), newClient, dm, ioStreams, o.appName, o.Env, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
|
||||
+37
-60
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/api"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
oam2 "github.com/oam-dev/kubevela/pkg/serverlib"
|
||||
)
|
||||
|
||||
@@ -103,7 +103,11 @@ func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printAppStatus(ctx, newClient, ioStreams, appName, env, cmd)
|
||||
dm, err := discoverymapper.New(c.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printAppStatus(ctx, newClient, dm, ioStreams, appName, env, cmd)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeApp,
|
||||
@@ -114,17 +118,12 @@ 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 {
|
||||
func printAppStatus(ctx context.Context, c client.Client, dm discoverymapper.DiscoveryMapper, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta, cmd *cobra.Command) error {
|
||||
app, err := appfile.LoadApplication(env.Name, appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namespace := env.Name
|
||||
|
||||
targetServices, err := oam2.GetServicesWhenDescribingApplication(cmd, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namespace := env.Namespace
|
||||
|
||||
cmd.Printf("About:\n\n")
|
||||
table := newUITable()
|
||||
@@ -136,16 +135,36 @@ func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOSt
|
||||
|
||||
cmd.Printf("Services:\n\n")
|
||||
|
||||
for _, svcName := range targetServices {
|
||||
if err := printComponentStatus(ctx, c, ioStreams, svcName, appName, env); err != nil {
|
||||
return err
|
||||
}
|
||||
remoteApp, err := loadRemoteApplication(c, namespace, appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
parser := appfile.NewApplicationParser(c, dm)
|
||||
appFile, err := parser.GenerateAppFile(appName, remoteApp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return appfile.PrintApplicationComponents(appFile, c, namespace, componentPrinter(ctx, c, ioStreams, env))
|
||||
}
|
||||
|
||||
func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, compName, appName string, env *types.EnvMeta) error {
|
||||
func loadRemoteApplication(c client.Client, ns string, name string) (*v1alpha2.Application, error) {
|
||||
app := new(v1alpha2.Application)
|
||||
err := c.Get(context.Background(), client.ObjectKey{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
}, app)
|
||||
|
||||
return app, err
|
||||
}
|
||||
|
||||
func componentPrinter(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, env *types.EnvMeta) func(compName string, appName string, traitsStatus map[string]string) error {
|
||||
return func(compName string, appName string, traitsStatus map[string]string) error {
|
||||
return printComponentStatus(ctx, c, ioStreams, compName, appName, env, traitsStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, compName string, appName string, env *types.EnvMeta, traitsStatus map[string]string) error {
|
||||
app, appConfig, err := getAppConfig(ctx, c, compName, appName, env)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -173,14 +192,9 @@ func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmduti
|
||||
|
||||
// workload Must found
|
||||
ioStreams.Infof(" Traits:\n")
|
||||
workloadStatus, _ := getWorkloadStatusFromAppConfig(appConfig, compName)
|
||||
for _, tr := range workloadStatus.Traits {
|
||||
traitType, traitInfo, err := traitCheckLoop(ctx, c, tr.Reference, compName, appConfig, app, 60*time.Second)
|
||||
if err != nil {
|
||||
ioStreams.Infof(" - %s%s: %s, err: %v", emojiFail, white.Sprint(traitType), traitInfo, err)
|
||||
continue
|
||||
}
|
||||
ioStreams.Infof(" - %s%s: %s", emojiSucceed, white.Sprint(traitType), traitInfo)
|
||||
|
||||
for traitType, traitInfo := range traitsStatus {
|
||||
ioStreams.Infof(" - %s: %s", white.Sprint(traitType), traitInfo)
|
||||
}
|
||||
ioStreams.Info("")
|
||||
ioStreams.Infof(" Last Deployment:\n")
|
||||
@@ -189,43 +203,6 @@ func printComponentStatus(ctx context.Context, c client.Client, ioStreams cmduti
|
||||
return nil
|
||||
}
|
||||
|
||||
func traitCheckLoop(ctx context.Context, c client.Client, reference runtimev1alpha1.TypedReference, compName string, appConfig *v1alpha2.ApplicationConfiguration, app *api.Application, timeout time.Duration) (string, string, error) {
|
||||
tr, err := oam2.GetUnstructured(ctx, c, appConfig.Namespace, reference)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
traitType, ok := tr.GetLabels()[oam.TraitTypeLabel]
|
||||
if !ok {
|
||||
message, err := oam2.GetStatusFromObject(tr)
|
||||
return traitType, message, err
|
||||
}
|
||||
|
||||
checker := oam2.GetChecker(traitType, c)
|
||||
|
||||
// Health Check Loop For Trait
|
||||
var message string
|
||||
sHealthCheck := newTrackingSpinner(fmt.Sprintf("Checking %s status ...", traitType))
|
||||
sHealthCheck.Start()
|
||||
defer sHealthCheck.Stop()
|
||||
CheckLoop:
|
||||
for {
|
||||
time.Sleep(trackingInterval)
|
||||
var check oam2.CheckStatus
|
||||
check, message, err = checker.Check(ctx, reference, compName, appConfig, app)
|
||||
if err != nil {
|
||||
message = red.Sprintf("%s check failed!", traitType)
|
||||
return traitType, message, err
|
||||
}
|
||||
if check == oam2.StatusDone {
|
||||
break CheckLoop
|
||||
}
|
||||
if time.Since(tr.GetCreationTimestamp().Time) >= timeout {
|
||||
return traitType, fmt.Sprintf("Checking timeout: %s", message), nil
|
||||
}
|
||||
}
|
||||
return traitType, message, nil
|
||||
}
|
||||
|
||||
func healthCheckLoop(ctx context.Context, c client.Client, compName, appName string, env *types.EnvMeta) (HealthStatus, string, error) {
|
||||
// Health Check Loop For Workload
|
||||
var healthInfo string
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/build"
|
||||
@@ -25,6 +26,8 @@ const (
|
||||
OutputFieldName = "output"
|
||||
// OutputsFieldName is the name of the struct contains the map[string]CR data
|
||||
OutputsFieldName = "outputs"
|
||||
// OutputObjectPath is the path of output object in template
|
||||
OutputObjectPath = "path"
|
||||
// PatchFieldName is the name of the struct contains the patch of CR data
|
||||
PatchFieldName = "patch"
|
||||
)
|
||||
@@ -45,6 +48,7 @@ type Template interface {
|
||||
Complete(ctx process.Context) error
|
||||
Output(ctx process.Context, client client.Client, name string) Template
|
||||
HealthCheck() error
|
||||
Status(ctx process.Context, cli client.Client, ns string, handleTempl string) (string, error)
|
||||
}
|
||||
|
||||
type def struct {
|
||||
@@ -174,6 +178,11 @@ func (wd *workloadDef) HealthCheck() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status get workload status
|
||||
func (wd *workloadDef) Status(ctx process.Context, cli client.Client, ns string, handleTempl string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
type traitDef struct {
|
||||
def
|
||||
}
|
||||
@@ -232,6 +241,7 @@ func (td *traitDef) Complete(ctx process.Context) error {
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "traitDef %s new Assist", td.name)
|
||||
}
|
||||
other.SetTag(OutputObjectPath, OutputFieldName)
|
||||
ctx.PutAssistants(process.Assistant{Ins: other, Type: td.name})
|
||||
}
|
||||
|
||||
@@ -247,6 +257,7 @@ func (td *traitDef) Complete(ctx process.Context) error {
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "traitDef %s new Assists(%s)", td.name, fieldInfo.Name)
|
||||
}
|
||||
other.SetTag(OutputObjectPath, strings.Join([]string{OutputsFieldName, fieldInfo.Name}, "."))
|
||||
ctx.PutAssistants(process.Assistant{Ins: other, Type: td.name})
|
||||
}
|
||||
}
|
||||
@@ -266,6 +277,49 @@ func (td *traitDef) Complete(ctx process.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status get trait status by handleTempl
|
||||
func (td *traitDef) Status(ctx process.Context, cli client.Client, ns string, handleTempl string) (string, error) {
|
||||
_, assists := ctx.Output()
|
||||
var root = map[string]interface{}{}
|
||||
for _, assist := range assists {
|
||||
if assist.Type != td.name {
|
||||
continue
|
||||
}
|
||||
traitRef, err := assist.Ins.Unstructured()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := cli.Get(context.Background(), client.ObjectKey{
|
||||
Namespace: ns,
|
||||
Name: traitRef.GetName(),
|
||||
}, traitRef); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
paths := strings.Split(assist.Ins.GetTag(OutputObjectPath), ".")
|
||||
|
||||
x := traitRef.Object
|
||||
for i := len(paths) - 1; i >= 0; i-- {
|
||||
x = map[string]interface{}{paths[i]: x}
|
||||
}
|
||||
for k, v := range x {
|
||||
root[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
bt, _ := json.Marshal(root)
|
||||
var buff = "context: " + string(bt)
|
||||
|
||||
buff += "\n" + handleTempl
|
||||
var r cue.Runtime
|
||||
inst, err := r.Compile("-", buff)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return inst.Lookup("output").String()
|
||||
}
|
||||
|
||||
// Output fetch the trait cr and set result to context
|
||||
func (td *traitDef) Output(ctx process.Context, client client.Client, name string) Template {
|
||||
_, assists := ctx.Output()
|
||||
|
||||
@@ -16,11 +16,14 @@ type Instance interface {
|
||||
IsBase() bool
|
||||
Unify(other Instance) error
|
||||
Compile() ([]byte, error)
|
||||
SetTag(k, v string)
|
||||
GetTag(k string) string
|
||||
}
|
||||
|
||||
type instance struct {
|
||||
v string
|
||||
base bool
|
||||
tags map[string]string
|
||||
}
|
||||
|
||||
// String return instance's cue format string
|
||||
@@ -33,6 +36,16 @@ func (inst *instance) IsBase() bool {
|
||||
return inst.base
|
||||
}
|
||||
|
||||
// SetTag add or update tag for model
|
||||
func (inst *instance) SetTag(k, v string) {
|
||||
inst.tags[k] = v
|
||||
}
|
||||
|
||||
// GetTag get the tag of model by key
|
||||
func (inst *instance) GetTag(k string) string {
|
||||
return inst.tags[k]
|
||||
}
|
||||
|
||||
func (inst *instance) Compile() ([]byte, error) {
|
||||
var r cue.Runtime
|
||||
cueInst, err := r.Compile("-", inst.v)
|
||||
@@ -82,6 +95,7 @@ func NewBase(v cue.Value) (Instance, error) {
|
||||
return &instance{
|
||||
v: vs,
|
||||
base: true,
|
||||
tags: map[string]string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -92,7 +106,8 @@ func NewOther(v cue.Value) (Instance, error) {
|
||||
return nil, err
|
||||
}
|
||||
return &instance{
|
||||
v: vs,
|
||||
v: vs,
|
||||
tags: map[string]string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
type Template struct {
|
||||
TemplateStr string
|
||||
Health string
|
||||
CustomStatus string
|
||||
CapabilityCategory types.CapabilityCategory
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
if wd.Annotations["type"] == string(types.TerraformCategory) {
|
||||
capabilityCategory = types.TerraformCategory
|
||||
}
|
||||
tmpl, err := getTemplAndHealth(wd.Spec.Extension.Raw)
|
||||
tmpl, err := getTempl(wd.Spec.Extension.Raw)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "LoadTemplate [%s] ", key)
|
||||
}
|
||||
@@ -65,7 +66,7 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
if td.Annotations["type"] == string(types.TerraformCategory) {
|
||||
capabilityCategory = types.TerraformCategory
|
||||
}
|
||||
tmpl, err := getTemplAndHealth(td.Spec.Extension.Raw)
|
||||
tmpl, err := getTempl(td.Spec.Extension.Raw)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "LoadTemplate [%s] ", key)
|
||||
}
|
||||
@@ -81,15 +82,23 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
return nil, fmt.Errorf("kind(%s) of %s not supported", kd, key)
|
||||
}
|
||||
|
||||
func getTemplAndHealth(raw []byte) (*Template, error) {
|
||||
func getTempl(raw []byte) (*Template, error) {
|
||||
_tmp := map[string]interface{}{}
|
||||
if err := json.Unmarshal(raw, &_tmp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var health string
|
||||
var (
|
||||
health string
|
||||
status string
|
||||
)
|
||||
if _, ok := _tmp["healthPolicy"]; ok {
|
||||
health = fmt.Sprint(_tmp["healthPolicy"])
|
||||
}
|
||||
return &Template{TemplateStr: fmt.Sprint(_tmp["template"]),
|
||||
Health: health}, nil
|
||||
if _, ok := _tmp["customStatus"]; ok {
|
||||
status = fmt.Sprint(_tmp["customStatus"])
|
||||
}
|
||||
return &Template{
|
||||
TemplateStr: fmt.Sprint(_tmp["template"]),
|
||||
Health: health,
|
||||
CustomStatus: status}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user