2021-08-18 11:37:46 +08:00
|
|
|
/*
|
|
|
|
|
Copyright 2021 The KubeVela Authors.
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package cli
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2022-10-09 20:22:29 +08:00
|
|
|
"os"
|
2021-08-18 11:37:46 +08:00
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
2021-11-24 21:34:44 +08:00
|
|
|
k8stypes "k8s.io/apimachinery/pkg/types"
|
2021-08-18 11:37:46 +08:00
|
|
|
|
2022-09-09 15:10:18 +08:00
|
|
|
pkgmulticluster "github.com/kubevela/pkg/multicluster"
|
|
|
|
|
|
2022-10-09 20:22:29 +08:00
|
|
|
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
2021-08-18 11:37:46 +08:00
|
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
|
|
|
|
"github.com/oam-dev/kubevela/apis/types"
|
2022-03-28 14:47:47 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/oam"
|
2021-08-18 11:37:46 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/utils/common"
|
|
|
|
|
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
2022-06-24 18:03:04 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/workflow/operation"
|
2021-08-18 11:37:46 +08:00
|
|
|
"github.com/oam-dev/kubevela/references/appfile"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// NewWorkflowCommand create `workflow` command
|
|
|
|
|
func NewWorkflowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
|
Use: "workflow",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Operate application delivery workflow.",
|
2022-01-10 17:45:20 +08:00
|
|
|
Long: "Operate the Workflow during Application Delivery.",
|
2021-08-18 11:37:46 +08:00
|
|
|
Annotations: map[string]string{
|
2022-01-06 13:29:02 +08:00
|
|
|
types.TagCommandType: types.TypeCD,
|
2021-08-18 11:37:46 +08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
cmd.AddCommand(
|
|
|
|
|
NewWorkflowSuspendCommand(c, ioStreams),
|
2021-08-18 17:04:21 +08:00
|
|
|
NewWorkflowResumeCommand(c, ioStreams),
|
2021-08-20 20:45:09 +08:00
|
|
|
NewWorkflowTerminateCommand(c, ioStreams),
|
|
|
|
|
NewWorkflowRestartCommand(c, ioStreams),
|
2021-11-24 21:34:44 +08:00
|
|
|
NewWorkflowRollbackCommand(c, ioStreams),
|
2021-08-18 11:37:46 +08:00
|
|
|
)
|
|
|
|
|
return cmd
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewWorkflowSuspendCommand create workflow suspend command
|
|
|
|
|
func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
2021-10-19 17:34:30 +08:00
|
|
|
cmd := &cobra.Command{
|
2021-08-18 11:37:46 +08:00
|
|
|
Use: "suspend",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Suspend an application workflow.",
|
|
|
|
|
Long: "Suspend an application workflow in cluster.",
|
2021-08-18 11:37:46 +08:00
|
|
|
Example: "vela workflow suspend <application-name>",
|
2022-10-09 20:22:29 +08:00
|
|
|
PreRun: checkApplicationNotRunning(c),
|
2021-08-18 11:37:46 +08:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return fmt.Errorf("must specify application name")
|
|
|
|
|
}
|
2021-11-19 18:00:03 +08:00
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
2021-08-18 11:37:46 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-10-19 17:34:30 +08:00
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
2021-08-18 11:37:46 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
|
|
|
|
|
config, err := c.GetConfig()
|
2021-08-18 11:37:46 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-09-09 15:10:18 +08:00
|
|
|
config.Wrap(pkgmulticluster.NewTransportWrapper())
|
2022-06-24 18:03:04 +08:00
|
|
|
cli, err := c.GetClient()
|
2021-08-18 11:37:46 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
|
|
|
|
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
|
|
|
|
return wo.Suspend(context.Background(), app)
|
2021-08-18 11:37:46 +08:00
|
|
|
},
|
|
|
|
|
}
|
2022-01-06 13:29:02 +08:00
|
|
|
addNamespaceAndEnvArg(cmd)
|
2021-10-19 17:34:30 +08:00
|
|
|
return cmd
|
2021-08-18 11:37:46 +08:00
|
|
|
}
|
|
|
|
|
|
2021-08-18 17:04:21 +08:00
|
|
|
// NewWorkflowResumeCommand create workflow resume command
|
|
|
|
|
func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
2021-10-19 17:34:30 +08:00
|
|
|
cmd := &cobra.Command{
|
2021-08-18 17:04:21 +08:00
|
|
|
Use: "resume",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Resume a suspend application workflow.",
|
|
|
|
|
Long: "Resume a suspend application workflow in cluster.",
|
2021-08-18 17:04:21 +08:00
|
|
|
Example: "vela workflow resume <application-name>",
|
2022-10-09 20:22:29 +08:00
|
|
|
PreRun: checkApplicationNotRunning(c),
|
2021-08-18 17:04:21 +08:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return fmt.Errorf("must specify application name")
|
|
|
|
|
}
|
2021-11-19 18:00:03 +08:00
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
2021-08-18 17:04:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-10-19 17:34:30 +08:00
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
2021-08-18 17:04:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
|
|
|
|
|
config, err := c.GetConfig()
|
2021-08-18 17:04:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-09-09 15:10:18 +08:00
|
|
|
config.Wrap(pkgmulticluster.NewTransportWrapper())
|
2022-06-24 18:03:04 +08:00
|
|
|
cli, err := c.GetClient()
|
2021-08-18 17:04:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
|
|
|
|
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
|
|
|
|
return wo.Resume(context.Background(), app)
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
|
}
|
2022-01-06 13:29:02 +08:00
|
|
|
addNamespaceAndEnvArg(cmd)
|
2021-10-19 17:34:30 +08:00
|
|
|
return cmd
|
2021-08-18 17:04:21 +08:00
|
|
|
}
|
|
|
|
|
|
2021-08-20 20:45:09 +08:00
|
|
|
// NewWorkflowTerminateCommand create workflow terminate command
|
|
|
|
|
func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
2021-10-19 17:34:30 +08:00
|
|
|
cmd := &cobra.Command{
|
2021-08-20 20:45:09 +08:00
|
|
|
Use: "terminate",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Terminate an application workflow.",
|
|
|
|
|
Long: "Terminate an application workflow in cluster.",
|
2021-08-20 20:45:09 +08:00
|
|
|
Example: "vela workflow terminate <application-name>",
|
2022-10-09 20:22:29 +08:00
|
|
|
PreRun: checkApplicationNotRunning(c),
|
2021-08-20 20:45:09 +08:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return fmt.Errorf("must specify application name")
|
|
|
|
|
}
|
2021-11-19 18:00:03 +08:00
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-10-19 17:34:30 +08:00
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if app.Status.Workflow == nil {
|
|
|
|
|
return fmt.Errorf("the workflow in application is not running")
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
cli, err := c.GetClient()
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
|
|
|
|
return wo.Terminate(context.Background(), app)
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
|
}
|
2022-01-06 13:29:02 +08:00
|
|
|
addNamespaceAndEnvArg(cmd)
|
2021-10-19 17:34:30 +08:00
|
|
|
return cmd
|
2021-08-20 20:45:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewWorkflowRestartCommand create workflow restart command
|
|
|
|
|
func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
2021-10-19 17:34:30 +08:00
|
|
|
cmd := &cobra.Command{
|
2021-08-20 20:45:09 +08:00
|
|
|
Use: "restart",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Restart an application workflow.",
|
|
|
|
|
Long: "Restart an application workflow in cluster.",
|
2021-08-20 20:45:09 +08:00
|
|
|
Example: "vela workflow restart <application-name>",
|
2022-10-09 20:22:29 +08:00
|
|
|
PreRun: checkApplicationNotRunning(c),
|
2021-08-20 20:45:09 +08:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return fmt.Errorf("must specify application name")
|
|
|
|
|
}
|
2021-11-19 18:00:03 +08:00
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-10-19 17:34:30 +08:00
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
config, err := c.GetConfig()
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-09-09 15:10:18 +08:00
|
|
|
config.Wrap(pkgmulticluster.NewTransportWrapper())
|
2022-06-24 18:03:04 +08:00
|
|
|
cli, err := c.GetClient()
|
2021-08-20 20:45:09 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
|
|
|
|
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
|
|
|
|
return wo.Restart(context.Background(), app)
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
|
}
|
2022-01-06 13:29:02 +08:00
|
|
|
addNamespaceAndEnvArg(cmd)
|
2021-10-19 17:34:30 +08:00
|
|
|
return cmd
|
2021-08-20 20:45:09 +08:00
|
|
|
}
|
|
|
|
|
|
2021-11-24 21:34:44 +08:00
|
|
|
// NewWorkflowRollbackCommand create workflow rollback command
|
|
|
|
|
func NewWorkflowRollbackCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
|
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
|
Use: "rollback",
|
2022-01-12 17:43:08 +08:00
|
|
|
Short: "Rollback an application workflow to the latest revision.",
|
|
|
|
|
Long: "Rollback an application workflow to the latest revision.",
|
2021-11-24 21:34:44 +08:00
|
|
|
Example: "vela workflow rollback <application-name>",
|
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return fmt.Errorf("must specify application name")
|
|
|
|
|
}
|
|
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
config, err := c.GetConfig()
|
2021-11-24 21:34:44 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-09-09 15:10:18 +08:00
|
|
|
config.Wrap(pkgmulticluster.NewTransportWrapper())
|
2022-06-24 18:03:04 +08:00
|
|
|
cli, err := c.GetClient()
|
2021-11-24 21:34:44 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-06-24 18:03:04 +08:00
|
|
|
if app.Status.Workflow != nil && !app.Status.Workflow.Terminated && !app.Status.Workflow.Suspend && !app.Status.Workflow.Finished {
|
|
|
|
|
return fmt.Errorf("can not rollback a running workflow")
|
|
|
|
|
}
|
|
|
|
|
if oam.GetPublishVersion(app) == "" {
|
|
|
|
|
if app.Status.LatestRevision == nil || app.Status.LatestRevision.Name == "" {
|
|
|
|
|
return fmt.Errorf("the latest revision is not set: %s", app.Name)
|
|
|
|
|
}
|
|
|
|
|
// get the last revision
|
|
|
|
|
revision := &v1beta1.ApplicationRevision{}
|
|
|
|
|
if err := cli.Get(context.TODO(), k8stypes.NamespacedName{Name: app.Status.LatestRevision.Name, Namespace: app.Namespace}, revision); err != nil {
|
|
|
|
|
return fmt.Errorf("failed to get the latest revision: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app.Spec = revision.Spec.Application.Spec
|
|
|
|
|
if err := cli.Status().Update(context.TODO(), app); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Successfully rollback workflow to the latest revision: %s\n", app.Name)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
|
|
|
|
return wo.Rollback(context.Background(), app)
|
2021-11-24 21:34:44 +08:00
|
|
|
},
|
|
|
|
|
}
|
2022-01-06 13:29:02 +08:00
|
|
|
addNamespaceAndEnvArg(cmd)
|
2021-11-24 21:34:44 +08:00
|
|
|
return cmd
|
|
|
|
|
}
|
2022-10-09 20:22:29 +08:00
|
|
|
|
|
|
|
|
func checkApplicationNotRunning(c common.Args) func(cmd *cobra.Command, args []string) {
|
|
|
|
|
return func(cmd *cobra.Command, args []string) {
|
|
|
|
|
// Any error will be returned to let the normal execution report the error
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
app, err := appfile.LoadApplication(namespace, args[0], c)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if app.Status.Phase == common2.ApplicationRunning {
|
|
|
|
|
cmd.Printf("%s workflow not allowed because application %s is running\n", cmd.Use, args[0])
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|