2021-07-13 13:03:25 +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-01-07 15:49:27 +08:00
"os"
2022-01-11 11:29:10 +08:00
"path/filepath"
2022-04-13 22:20:07 +08:00
"sort"
2021-08-11 11:49:44 +08:00
"strings"
2021-07-13 13:03:25 +08:00
"time"
2022-03-28 21:25:38 +08:00
"github.com/fatih/color"
2022-02-23 12:17:31 +08:00
"k8s.io/client-go/discovery"
2022-02-14 14:02:16 +08:00
"helm.sh/helm/v3/pkg/strvals"
2022-01-11 11:29:10 +08:00
"github.com/oam-dev/kubevela/pkg/oam"
2021-12-09 20:31:19 +08:00
"k8s.io/client-go/rest"
2021-07-13 13:03:25 +08:00
"github.com/gosuri/uitable"
"github.com/pkg/errors"
"github.com/spf13/cobra"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
2021-11-25 14:08:20 +08:00
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
2021-07-13 13:03:25 +08:00
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
2021-12-07 15:11:52 +08:00
pkgaddon "github.com/oam-dev/kubevela/pkg/addon"
2021-07-13 13:03:25 +08:00
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/utils/common"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
const (
// DescAnnotation records the description of addon
DescAnnotation = "addons.oam.dev/description"
2021-11-16 13:56:39 +08:00
// DependsOnWorkFlowStepName is workflow step name which is used to check dependsOn app
DependsOnWorkFlowStepName = "depends-on-app"
2021-11-25 10:32:30 +08:00
// AddonTerraformProviderNamespace is the namespace of addon terraform provider
AddonTerraformProviderNamespace = "default"
// AddonTerraformProviderNameArgument is the argument name of addon terraform provider
AddonTerraformProviderNameArgument = "providerName"
2021-07-13 13:03:25 +08:00
)
2021-12-16 11:12:06 +08:00
const (
2021-12-25 11:01:59 +08:00
statusEnabled = "enabled"
statusDisabled = "disabled"
2022-03-31 10:24:20 +08:00
statusSuspend = "suspend"
2021-12-16 11:12:06 +08:00
)
2022-03-21 10:38:56 +08:00
var forceDisable bool
2022-03-28 21:25:38 +08:00
var addonVersion string
2022-03-21 10:38:56 +08:00
2022-03-29 23:03:57 +08:00
var addonClusters string
2021-07-13 13:03:25 +08:00
// NewAddonCommand create `addon` command
2022-01-06 13:29:02 +08:00
func NewAddonCommand ( c common . Args , order string , ioStreams cmdutil . IOStreams ) * cobra . Command {
2021-07-13 13:03:25 +08:00
cmd := & cobra . Command {
Use : "addon" ,
2022-01-10 17:45:20 +08:00
Short : "Manage addons for extension." ,
Long : "Manage addons for extension." ,
2021-07-13 13:03:25 +08:00
Annotations : map [ string ] string {
2022-01-06 13:29:02 +08:00
types . TagCommandOrder : order ,
types . TagCommandType : types . TypeExtension ,
2021-07-13 13:03:25 +08:00
} ,
}
cmd . AddCommand (
2022-01-07 15:49:27 +08:00
NewAddonListCommand ( c ) ,
2021-11-25 10:32:30 +08:00
NewAddonEnableCommand ( c , ioStreams ) ,
2022-01-07 15:49:27 +08:00
NewAddonDisableCommand ( c , ioStreams ) ,
2021-12-25 11:01:59 +08:00
NewAddonStatusCommand ( c , ioStreams ) ,
2021-12-13 19:47:32 +08:00
NewAddonRegistryCommand ( c , ioStreams ) ,
2021-12-22 19:31:20 +08:00
NewAddonUpgradeCommand ( c , ioStreams ) ,
2022-05-07 23:39:34 +08:00
NewAddonPackageCommand ( c ) ,
2021-07-13 13:03:25 +08:00
)
return cmd
}
// NewAddonListCommand create addon list command
2022-01-07 15:49:27 +08:00
func NewAddonListCommand ( c common . Args ) * cobra . Command {
2021-07-13 13:03:25 +08:00
return & cobra . Command {
2021-10-14 18:21:49 +08:00
Use : "list" ,
Aliases : [ ] string { "ls" } ,
Short : "List addons" ,
Long : "List addons in KubeVela" ,
2021-07-13 13:03:25 +08:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-01-11 11:29:10 +08:00
k8sClient , err := c . GetClient ( )
2022-01-07 15:49:27 +08:00
if err != nil {
return err
}
2022-05-10 13:35:12 +08:00
table , err := listAddons ( context . Background ( ) , k8sClient , "" )
2021-07-13 13:03:25 +08:00
if err != nil {
return err
}
2022-05-10 13:35:12 +08:00
fmt . Println ( table . String ( ) )
2021-07-13 13:03:25 +08:00
return nil
} ,
}
}
// NewAddonEnableCommand create addon enable command
2021-11-25 10:32:30 +08:00
func NewAddonEnableCommand ( c common . Args , ioStream cmdutil . IOStreams ) * cobra . Command {
ctx := context . Background ( )
2022-01-11 11:29:10 +08:00
cmd := & cobra . Command {
2022-03-23 14:33:15 +08:00
Use : "enable" ,
Short : "enable an addon" ,
Long : "enable an addon in cluster." ,
Example : ` \
Enable addon by :
vela addon enable < addon - name >
2022-03-28 21:25:38 +08:00
Enable addon with specify version :
2022-05-10 13:35:12 +08:00
vela addon enable < addon - name > -- version < addon - version >
2022-03-23 14:33:15 +08:00
Enable addon for specific clusters , ( local means control plane ) :
vela addon enable < addon - name > -- clusters = { local , cluster1 , cluster2 }
` ,
2021-07-13 13:03:25 +08:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2021-11-25 10:32:30 +08:00
2021-07-13 13:03:25 +08:00
if len ( args ) < 1 {
2021-08-18 11:37:46 +08:00
return fmt . Errorf ( "must specify addon name" )
2021-07-13 13:03:25 +08:00
}
2022-03-23 14:33:15 +08:00
addonArgs , err := parseAddonArgsToMap ( args [ 1 : ] )
2021-08-11 11:49:44 +08:00
if err != nil {
return err
}
2022-03-29 23:03:57 +08:00
addonArgs [ types . ClustersArg ] = transClusters ( addonClusters )
2022-01-07 15:49:27 +08:00
config , err := c . GetConfig ( )
if err != nil {
return err
}
k8sClient , err := c . GetClient ( )
if err != nil {
return err
}
2022-02-23 12:17:31 +08:00
dc , err := c . GetDiscoveryClient ( )
if err != nil {
return err
}
2022-01-11 11:29:10 +08:00
addonOrDir := args [ 0 ]
2022-01-12 17:43:08 +08:00
var name = addonOrDir
2022-02-11 19:56:29 +08:00
if file , err := os . Stat ( addonOrDir ) ; err == nil {
if ! file . IsDir ( ) {
return fmt . Errorf ( "%s is not addon dir" , addonOrDir )
}
2022-02-14 18:04:34 +08:00
ioStream . Infof ( "enable addon by local dir: %s \n" , addonOrDir )
2022-01-11 11:29:10 +08:00
// args[0] is a local path install with local dir, use base dir name as addonName
2022-01-12 17:43:08 +08:00
name = filepath . Base ( addonOrDir )
2022-02-23 12:17:31 +08:00
err = enableAddonByLocal ( ctx , name , addonOrDir , k8sClient , dc , config , addonArgs )
2022-01-11 11:29:10 +08:00
if err != nil {
return err
}
} else {
2022-02-16 14:20:37 +08:00
if filepath . IsAbs ( addonOrDir ) || strings . HasPrefix ( addonOrDir , "." ) || strings . HasSuffix ( addonOrDir , "/" ) {
return fmt . Errorf ( "addon directory %s not found in local" , addonOrDir )
}
2022-03-28 21:25:38 +08:00
err = enableAddon ( ctx , k8sClient , dc , config , name , addonVersion , addonArgs )
2022-01-11 11:29:10 +08:00
if err != nil {
return err
}
2021-07-13 13:03:25 +08:00
}
2022-01-12 17:43:08 +08:00
fmt . Printf ( "Addon: %s enabled Successfully.\n" , name )
2022-04-26 15:27:43 +08:00
AdditionalEndpointPrinter ( ctx , c , k8sClient , name , false )
2021-12-22 19:31:20 +08:00
return nil
} ,
}
2022-03-28 21:25:38 +08:00
cmd . Flags ( ) . StringVarP ( & addonVersion , "version" , "v" , "" , "specify the addon version to enable" )
2022-03-29 23:03:57 +08:00
cmd . Flags ( ) . StringVarP ( & addonClusters , types . ClustersArg , "c" , "" , "specify the runtime-clusters to enable" )
2022-01-11 11:29:10 +08:00
return cmd
2021-12-22 19:31:20 +08:00
}
2022-01-12 17:43:08 +08:00
// AdditionalEndpointPrinter will print endpoints
2022-04-26 15:27:43 +08:00
func AdditionalEndpointPrinter ( ctx context . Context , c common . Args , k8sClient client . Client , name string , isUpgrade bool ) {
2022-04-24 09:16:34 +08:00
fmt . Printf ( "Please access the %s from the following endpoints:\n" , name )
2022-05-11 14:27:38 +08:00
err := printAppEndpoints ( ctx , pkgaddon . Convert2AppName ( name ) , types . DefaultKubeVelaNS , Filter { } , c )
2022-04-24 09:16:34 +08:00
if err != nil {
fmt . Println ( "Get application endpoints error:" , err )
2022-01-12 17:43:08 +08:00
return
}
if name == "velaux" {
2022-04-26 15:27:43 +08:00
if ! isUpgrade {
fmt . Println ( ` To check the initialized admin user name and password by: ` )
fmt . Println ( ` vela logs -n vela-system --name apiserver addon-velaux | grep "initialized admin username" ` )
}
2022-03-31 17:33:06 +08:00
fmt . Println ( ` To open the dashboard directly by port-forward: ` )
fmt . Println ( ` vela port-forward -n vela-system addon-velaux 9082:80 ` )
2022-04-26 15:27:43 +08:00
fmt . Println ( ` Select "Cluster: local | Namespace: vela-system | Kind: Service | Name: velaux" from the prompt. ` )
2022-03-31 17:33:06 +08:00
fmt . Println ( ` Please refer to https://kubevela.io/docs/reference/addons/velaux for more VelaUX addon installation and visiting method. ` )
2022-01-12 17:43:08 +08:00
}
}
2021-12-22 19:31:20 +08:00
// NewAddonUpgradeCommand create addon upgrade command
func NewAddonUpgradeCommand ( c common . Args , ioStream cmdutil . IOStreams ) * cobra . Command {
ctx := context . Background ( )
2022-01-11 11:29:10 +08:00
cmd := & cobra . Command {
2022-03-23 14:33:15 +08:00
Use : "upgrade" ,
Short : "upgrade an addon" ,
Long : "upgrade an addon in cluster." ,
Example : ` \
Upgrade addon by :
vela addon upgrade < addon - name >
2022-03-28 21:25:38 +08:00
Upgrade addon with specify version :
2022-05-10 13:35:12 +08:00
vela addon upgrade < addon - name > -- version < addon - version >
2022-03-23 14:33:15 +08:00
Upgrade addon for specific clusters , ( local means control plane ) :
vela addon upgrade < addon - name > -- clusters = { local , cluster1 , cluster2 }
` ,
2021-12-22 19:31:20 +08:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
if len ( args ) < 1 {
return fmt . Errorf ( "must specify addon name" )
}
2022-01-07 15:49:27 +08:00
config , err := c . GetConfig ( )
if err != nil {
return err
}
k8sClient , err := c . GetClient ( )
if err != nil {
return err
}
2022-02-23 12:17:31 +08:00
dc , err := c . GetDiscoveryClient ( )
if err != nil {
return err
}
2022-03-23 14:33:15 +08:00
addonArgs , err := parseAddonArgsToMap ( args [ 1 : ] )
2021-12-22 19:31:20 +08:00
if err != nil {
return err
}
2022-03-29 23:03:57 +08:00
addonArgs [ types . ClustersArg ] = transClusters ( addonClusters )
2022-01-11 11:29:10 +08:00
addonOrDir := args [ 0 ]
var name string
2022-02-11 19:56:29 +08:00
if file , err := os . Stat ( addonOrDir ) ; err == nil {
if ! file . IsDir ( ) {
return fmt . Errorf ( "%s is not addon dir" , addonOrDir )
}
2022-02-14 18:04:34 +08:00
ioStream . Infof ( "enable addon by local dir: %s \n" , addonOrDir )
2022-01-11 11:29:10 +08:00
// args[0] is a local path install with local dir
2022-04-01 01:04:29 +08:00
name = filepath . Base ( addonOrDir )
2022-01-11 11:29:10 +08:00
_ , err = pkgaddon . FetchAddonRelatedApp ( context . Background ( ) , k8sClient , name )
if err != nil {
return errors . Wrapf ( err , "cannot fetch addon related addon %s" , name )
}
2022-02-23 12:17:31 +08:00
err = enableAddonByLocal ( ctx , name , addonOrDir , k8sClient , dc , config , addonArgs )
2022-01-11 11:29:10 +08:00
if err != nil {
return err
}
} else {
2022-02-16 14:20:37 +08:00
if filepath . IsAbs ( addonOrDir ) || strings . HasPrefix ( addonOrDir , "." ) || strings . HasSuffix ( addonOrDir , "/" ) {
return fmt . Errorf ( "addon directory %s not found in local" , addonOrDir )
}
2022-04-01 01:04:29 +08:00
name = addonOrDir
2022-01-11 11:29:10 +08:00
_ , err = pkgaddon . FetchAddonRelatedApp ( context . Background ( ) , k8sClient , addonOrDir )
if err != nil {
return errors . Wrapf ( err , "cannot fetch addon related addon %s" , addonOrDir )
}
2022-03-28 21:25:38 +08:00
err = enableAddon ( ctx , k8sClient , dc , config , addonOrDir , addonVersion , addonArgs )
2022-01-11 11:29:10 +08:00
if err != nil {
return err
}
2021-12-22 19:31:20 +08:00
}
2022-01-11 11:29:10 +08:00
2022-01-12 17:43:08 +08:00
fmt . Printf ( "Addon: %s\n enabled Successfully." , name )
2022-04-26 15:27:43 +08:00
AdditionalEndpointPrinter ( ctx , c , k8sClient , name , true )
2021-07-13 13:03:25 +08:00
return nil
} ,
}
2022-03-28 21:25:38 +08:00
cmd . Flags ( ) . StringVarP ( & addonVersion , "version" , "v" , "" , "specify the addon version to upgrade" )
2022-01-11 11:29:10 +08:00
return cmd
2021-07-13 13:03:25 +08:00
}
2022-03-23 14:33:15 +08:00
func parseAddonArgsToMap ( args [ ] string ) ( map [ string ] interface { } , error ) {
2021-12-07 15:11:52 +08:00
res := map [ string ] interface { } { }
2022-02-14 14:02:16 +08:00
for _ , arg := range args {
2022-04-28 15:58:23 +08:00
if err := strvals . ParseInto ( arg , res ) ; err != nil {
2022-02-14 14:02:16 +08:00
return nil , err
2021-08-11 11:49:44 +08:00
}
}
return res , nil
}
2021-07-13 13:03:25 +08:00
// NewAddonDisableCommand create addon disable command
2022-01-07 15:49:27 +08:00
func NewAddonDisableCommand ( c common . Args , ioStream cmdutil . IOStreams ) * cobra . Command {
2022-03-21 10:38:56 +08:00
cmd := & cobra . Command {
2021-07-13 13:03:25 +08:00
Use : "disable" ,
Short : "disable an addon" ,
2022-01-12 17:43:08 +08:00
Long : "disable an addon in cluster." ,
2021-07-13 13:03:25 +08:00
Example : "vela addon disable <addon-name>" ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
if len ( args ) < 1 {
2021-08-18 11:37:46 +08:00
return fmt . Errorf ( "must specify addon name" )
2021-07-13 13:03:25 +08:00
}
name := args [ 0 ]
2022-01-07 15:49:27 +08:00
k8sClient , err := c . GetClient ( )
if err != nil {
return err
}
2022-03-21 10:38:56 +08:00
config , err := c . GetConfig ( )
if err != nil {
return err
}
err = disableAddon ( k8sClient , name , config , forceDisable )
2021-07-13 13:03:25 +08:00
if err != nil {
return err
}
2021-10-14 18:21:49 +08:00
fmt . Printf ( "Successfully disable addon:%s\n" , name )
2021-07-13 13:03:25 +08:00
return nil
} ,
}
2022-03-21 10:38:56 +08:00
cmd . Flags ( ) . BoolVarP ( & forceDisable , "force" , "f" , false , "skip checking if applications are still using this addon" )
return cmd
2021-07-13 13:03:25 +08:00
}
2021-12-07 15:11:52 +08:00
// NewAddonStatusCommand create addon status command
2021-12-25 11:01:59 +08:00
func NewAddonStatusCommand ( c common . Args , ioStream cmdutil . IOStreams ) * cobra . Command {
2021-12-07 15:11:52 +08:00
return & cobra . Command {
Use : "status" ,
2022-01-12 17:43:08 +08:00
Short : "get an addon's status." ,
Long : "get an addon's status from cluster." ,
2021-12-07 15:11:52 +08:00
Example : "vela addon status <addon-name>" ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
if len ( args ) < 1 {
return fmt . Errorf ( "must specify addon name" )
}
name := args [ 0 ]
2021-12-25 11:01:59 +08:00
err := statusAddon ( name , ioStream , cmd , c )
2021-12-07 15:11:52 +08:00
if err != nil {
return err
}
return nil
} ,
2021-07-13 13:03:25 +08:00
}
}
2022-03-28 21:25:38 +08:00
func enableAddon ( ctx context . Context , k8sClient client . Client , dc * discovery . DiscoveryClient , config * rest . Config , name string , version string , args map [ string ] interface { } ) error {
2021-12-07 15:11:52 +08:00
var err error
registryDS := pkgaddon . NewRegistryDataStore ( k8sClient )
registries , err := registryDS . ListRegistries ( ctx )
2021-07-13 13:03:25 +08:00
if err != nil {
return err
}
2021-11-25 10:32:30 +08:00
2021-12-07 15:11:52 +08:00
for _ , registry := range registries {
2022-03-28 21:25:38 +08:00
err = pkgaddon . EnableAddon ( ctx , name , version , k8sClient , dc , apply . NewAPIApplicator ( k8sClient ) , config , registry , args , nil )
2021-12-21 09:31:37 +08:00
if errors . Is ( err , pkgaddon . ErrNotExist ) {
2021-12-16 11:12:06 +08:00
continue
2021-12-07 15:11:52 +08:00
}
if err != nil {
return err
}
2022-01-07 15:49:27 +08:00
if err = waitApplicationRunning ( k8sClient , name ) ; err != nil {
2021-12-07 15:11:52 +08:00
return err
}
return nil
2021-11-25 10:32:30 +08:00
}
2022-01-12 17:43:08 +08:00
return fmt . Errorf ( "addon: %s not found in registries" , name )
2021-07-13 13:03:25 +08:00
}
2022-01-11 11:29:10 +08:00
// enableAddonByLocal enable addon in local dir and return the addon name
2022-02-23 12:17:31 +08:00
func enableAddonByLocal ( ctx context . Context , name string , dir string , k8sClient client . Client , dc * discovery . DiscoveryClient , config * rest . Config , args map [ string ] interface { } ) error {
if err := pkgaddon . EnableAddonByLocalDir ( ctx , name , dir , k8sClient , dc , apply . NewAPIApplicator ( k8sClient ) , config , args ) ; err != nil {
2022-01-11 11:29:10 +08:00
return err
}
if err := waitApplicationRunning ( k8sClient , name ) ; err != nil {
return err
}
return nil
}
2022-03-21 10:38:56 +08:00
func disableAddon ( client client . Client , name string , config * rest . Config , force bool ) error {
if err := pkgaddon . DisableAddon ( context . Background ( ) , client , name , config , force ) ; err != nil {
2021-07-13 13:03:25 +08:00
return err
}
2021-12-07 15:11:52 +08:00
return nil
2021-10-14 18:21:49 +08:00
}
2021-12-25 11:01:59 +08:00
func statusAddon ( name string , ioStreams cmdutil . IOStreams , cmd * cobra . Command , c common . Args ) error {
2022-01-11 11:29:10 +08:00
k8sClient , err := c . GetClient ( )
2022-01-07 15:49:27 +08:00
if err != nil {
return err
}
2022-01-11 11:29:10 +08:00
status , err := pkgaddon . GetAddonStatus ( context . Background ( ) , k8sClient , name )
2021-12-07 15:11:52 +08:00
if err != nil {
return err
2021-07-13 13:03:25 +08:00
}
2022-03-31 10:24:20 +08:00
fmt . Print ( generateAddonInfo ( name , status ) )
2021-12-25 11:01:59 +08:00
if status . AddonPhase != statusEnabled && status . AddonPhase != statusDisabled {
2021-12-25 12:37:23 +08:00
fmt . Printf ( "diagnose addon info from application %s" , pkgaddon . Convert2AppName ( name ) )
2022-01-11 11:29:10 +08:00
err := printAppStatus ( context . Background ( ) , k8sClient , ioStreams , pkgaddon . Convert2AppName ( name ) , types . DefaultKubeVelaNS , cmd , c )
2021-12-25 11:01:59 +08:00
if err != nil {
return err
}
2021-10-14 18:21:49 +08:00
}
2021-12-07 15:11:52 +08:00
return nil
2021-07-13 13:03:25 +08:00
}
2022-03-31 10:24:20 +08:00
func generateAddonInfo ( name string , status pkgaddon . Status ) string {
var res string
var phase string
switch status . AddonPhase {
case statusEnabled :
c := color . New ( color . FgGreen )
phase = c . Sprintf ( "%s" , status . AddonPhase )
case statusSuspend :
c := color . New ( color . FgRed )
phase = c . Sprintf ( "%s" , status . AddonPhase )
default :
phase = status . AddonPhase
}
res += fmt . Sprintf ( "addon %s status is %s \n" , name , phase )
if len ( status . InstalledVersion ) != 0 {
res += fmt . Sprintf ( "installedVersion: %s \n" , status . InstalledVersion )
}
if len ( status . Clusters ) != 0 {
var ic [ ] string
for c := range status . Clusters {
ic = append ( ic , c )
}
2022-04-13 22:20:07 +08:00
sort . Strings ( ic )
2022-03-31 10:24:20 +08:00
res += fmt . Sprintf ( "installedClusters: %s \n" , ic )
}
return res
}
2022-05-10 13:35:12 +08:00
func listAddons ( ctx context . Context , clt client . Client , registry string ) ( * uitable . Table , error ) {
2021-12-21 09:31:37 +08:00
var addons [ ] * pkgaddon . UIData
2021-12-07 15:11:52 +08:00
var err error
registryDS := pkgaddon . NewRegistryDataStore ( clt )
registries , err := registryDS . ListRegistries ( ctx )
2021-07-13 13:03:25 +08:00
if err != nil {
2022-05-10 13:35:12 +08:00
return nil , err
2021-07-13 13:03:25 +08:00
}
2022-05-10 13:35:12 +08:00
2021-12-07 15:11:52 +08:00
for _ , r := range registries {
if registry != "" && r . Name != registry {
continue
2021-07-13 13:03:25 +08:00
}
2022-03-28 21:25:38 +08:00
var addonList [ ] * pkgaddon . UIData
var err error
if ! pkgaddon . IsVersionRegistry ( r ) {
meta , err := r . ListAddonMeta ( )
if err != nil {
continue
}
addonList , err = r . ListUIData ( meta , pkgaddon . CLIMetaOptions )
if err != nil {
continue
}
} else {
2022-05-07 23:39:34 +08:00
versionedRegistry := pkgaddon . BuildVersionedRegistry ( r . Name , r . Helm . URL , & common . HTTPOption { Username : r . Helm . Username , Password : r . Helm . Password } )
2022-03-28 21:25:38 +08:00
addonList , err = versionedRegistry . ListAddon ( )
if err != nil {
continue
}
2021-12-07 15:11:52 +08:00
}
2022-03-28 21:25:38 +08:00
addons = mergeAddons ( addons , addonList )
2021-08-11 11:49:44 +08:00
}
2021-07-13 13:03:25 +08:00
2021-12-07 15:11:52 +08:00
table := uitable . New ( )
2022-03-28 21:25:38 +08:00
table . AddRow ( "NAME" , "REGISTRY" , "DESCRIPTION" , "AVAILABLE-VERSIONS" , "STATUS" )
2021-11-25 10:32:30 +08:00
2022-05-10 13:35:12 +08:00
// get locally installed addons first
locallyInstalledAddons := map [ string ] bool { }
appList := v1beta1 . ApplicationList { }
if err := clt . List ( ctx , & appList , client . MatchingLabels { oam . LabelAddonRegistry : pkgaddon . LocalAddonRegistryName } ) ; err != nil {
return table , err
}
for _ , app := range appList . Items {
labels := app . GetLabels ( )
addonName := labels [ oam . LabelAddonName ]
addonVersion := labels [ oam . LabelAddonVersion ]
table . AddRow ( addonName , app . GetLabels ( ) [ oam . LabelAddonRegistry ] , "" , genAvailableVersionInfo ( [ ] string { addonVersion } , addonVersion ) , statusEnabled )
locallyInstalledAddons [ addonName ] = true
}
2021-12-07 15:11:52 +08:00
for _ , addon := range addons {
2022-05-10 13:35:12 +08:00
// if the addon with same name has already installed locally, display the registry one as not installed
if locallyInstalledAddons [ addon . Name ] {
table . AddRow ( addon . Name , addon . RegistryName , addon . Description , addon . AvailableVersions , "disabled" )
continue
}
2021-12-20 14:34:45 +08:00
status , err := pkgaddon . GetAddonStatus ( ctx , clt , addon . Name )
2021-12-07 15:11:52 +08:00
if err != nil {
2022-05-10 13:35:12 +08:00
return table , err
2021-11-25 10:32:30 +08:00
}
2022-03-28 21:25:38 +08:00
statusRow := status . AddonPhase
if len ( status . InstalledVersion ) != 0 {
statusRow += fmt . Sprintf ( " (%s)" , status . InstalledVersion )
}
2022-05-10 13:35:12 +08:00
table . AddRow ( addon . Name , addon . RegistryName , addon . Description , genAvailableVersionInfo ( addon . AvailableVersions , status . InstalledVersion ) , statusRow )
2022-01-11 11:29:10 +08:00
}
2022-05-10 13:35:12 +08:00
return table , nil
2021-07-13 13:03:25 +08:00
}
2022-01-07 15:49:27 +08:00
func waitApplicationRunning ( k8sClient client . Client , addonName string ) error {
2021-11-25 14:08:20 +08:00
trackInterval := 5 * time . Second
2021-12-06 12:33:52 +08:00
timeout := 600 * time . Second
2021-11-25 14:08:20 +08:00
start := time . Now ( )
ctx := context . Background ( )
2021-10-14 18:21:49 +08:00
var app v1beta1 . Application
2021-11-25 14:08:20 +08:00
spinner := newTrackingSpinnerWithDelay ( "Waiting addon running ..." , 1 * time . Second )
spinner . Start ( )
defer spinner . Stop ( )
for {
2022-01-07 15:49:27 +08:00
err := k8sClient . Get ( ctx , types2 . NamespacedName { Name : pkgaddon . Convert2AppName ( addonName ) , Namespace : types . DefaultKubeVelaNS } , & app )
2021-07-25 10:16:43 +08:00
if err != nil {
2021-11-25 14:08:20 +08:00
return client . IgnoreNotFound ( err )
2021-07-25 10:16:43 +08:00
}
2021-10-14 18:21:49 +08:00
phase := app . Status . Phase
if phase == common2 . ApplicationRunning {
2021-11-25 14:08:20 +08:00
return nil
2021-07-25 10:16:43 +08:00
}
2021-11-25 14:08:20 +08:00
timeConsumed := int ( time . Since ( start ) . Seconds ( ) )
applySpinnerNewSuffix ( spinner , fmt . Sprintf ( "Waiting addon application running. It is now in phase: %s (timeout %d/%d seconds)..." ,
phase , timeConsumed , int ( timeout . Seconds ( ) ) ) )
2021-12-06 12:33:52 +08:00
if timeConsumed > int ( timeout . Seconds ( ) ) {
2022-01-07 15:49:27 +08:00
return errors . Errorf ( "Enabling timeout, please run \"vela status %s -n vela-system\" to check the status of the addon" , pkgaddon . Convert2AppName ( addonName ) )
2021-12-06 12:33:52 +08:00
}
2021-11-25 14:08:20 +08:00
time . Sleep ( trackInterval )
}
2021-08-11 11:49:44 +08:00
2021-11-16 13:56:39 +08:00
}
2022-03-31 10:24:20 +08:00
// generate the available version
// this func put the installed version as the first version and keep the origin order
// print ... if available version too much
2022-05-10 13:35:12 +08:00
func genAvailableVersionInfo ( versions [ ] string , installedVersion string ) string {
2022-03-31 10:24:20 +08:00
var v [ ] string
// put installed-version as the first version and keep the origin order
2022-05-10 13:35:12 +08:00
if len ( installedVersion ) != 0 {
2022-03-31 10:24:20 +08:00
for i , version := range versions {
2022-05-10 13:35:12 +08:00
if version == installedVersion {
2022-03-31 10:24:20 +08:00
v = append ( v , version )
versions = append ( versions [ : i ] , versions [ i + 1 : ] ... )
}
}
}
v = append ( v , versions ... )
2022-03-28 21:25:38 +08:00
res := "["
2022-03-31 10:24:20 +08:00
var count int
for _ , version := range v {
if count == 3 {
// just show newest 3 versions
res += "..."
break
}
2022-05-10 13:35:12 +08:00
if version == installedVersion {
2022-03-28 21:25:38 +08:00
col := color . New ( color . Bold , color . FgGreen )
res += col . Sprintf ( "%s" , version )
} else {
res += version
}
res += ", "
2022-03-31 10:24:20 +08:00
count ++
2022-03-28 21:25:38 +08:00
}
res = strings . TrimSuffix ( res , ", " )
res += "]"
return res
}
2021-09-14 19:35:21 +08:00
// TransAddonName will turn addon's name from xxx/yyy to xxx-yyy
func TransAddonName ( name string ) string {
return strings . ReplaceAll ( name , "/" , "-" )
}
2021-11-25 10:32:30 +08:00
2021-12-21 09:31:37 +08:00
func mergeAddons ( a1 , a2 [ ] * pkgaddon . UIData ) [ ] * pkgaddon . UIData {
2021-12-07 15:11:52 +08:00
for _ , item := range a2 {
if hasAddon ( a1 , item . Name ) {
continue
2021-11-25 10:32:30 +08:00
}
2021-12-07 15:11:52 +08:00
a1 = append ( a1 , item )
2021-11-25 10:32:30 +08:00
}
2021-12-07 15:11:52 +08:00
return a1
2021-11-25 10:32:30 +08:00
}
2021-12-21 09:31:37 +08:00
func hasAddon ( addons [ ] * pkgaddon . UIData , name string ) bool {
2021-12-07 15:11:52 +08:00
for _ , addon := range addons {
if addon . Name == name {
return true
2021-11-25 10:32:30 +08:00
}
}
2021-12-07 15:11:52 +08:00
return false
2021-11-25 10:32:30 +08:00
}
2021-12-07 15:11:52 +08:00
2022-03-29 23:03:57 +08:00
func transClusters ( cstr string ) [ ] string {
cstr = strings . TrimPrefix ( strings . TrimSuffix ( cstr , "}" ) , "{" )
var clusterL [ ] string
clusterList := strings . Split ( cstr , "," )
for _ , v := range clusterList {
clusterL = append ( clusterL , strings . TrimSpace ( v ) )
}
return clusterL
}
2022-05-07 23:39:34 +08:00
// NewAddonPackageCommand create addon package command
func NewAddonPackageCommand ( c common . Args ) * cobra . Command {
cmd := & cobra . Command {
Use : "package" ,
Short : "package an addon directory" ,
Long : "package an addon directory into a helm chart archive." ,
Example : "vela addon package <addon directory>" ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
if len ( args ) < 1 {
return fmt . Errorf ( "must specify addon directory path" )
}
addonDict , err := filepath . Abs ( args [ 0 ] )
if err != nil {
return err
}
archive , err := pkgaddon . PackageAddon ( addonDict )
if err != nil {
return errors . Wrapf ( err , "fail to package %s into helm chart archive" , addonDict )
}
fmt . Printf ( "Successfully package addon to: %s\n" , archive )
return nil
} ,
}
return cmd
}
2021-12-07 15:11:52 +08:00
// TODO(wangyike) addon can support multi-tenancy, an addon can be enabled multi times and will create many times
// func checkWhetherTerraformProviderExist(ctx context.Context, k8sClient client.Client, addonName string, args map[string]string) (string, bool, error) {
// _, providerName := getTerraformProviderArgumentValue(addonName, args)
//
// providerNames, err := getTerraformProviderNames(ctx, k8sClient)
// if err != nil {
// return "", false, err
// }
// for _, name := range providerNames {
// if providerName == name {
// return providerName, true, nil
// }
// }
// return providerName, false, nil
// }
// func getTerraformProviderNames(ctx context.Context, k8sClient client.Client) ([]string, error) {
// var names []string
// providerList := &terraformv1beta1.ProviderList{}
// err := k8sClient.List(ctx, providerList, client.InNamespace(AddonTerraformProviderNamespace))
// if err != nil {
// if apimeta.IsNoMatchError(err) || kerrors.IsNotFound(err) {
// return nil, nil
// }
// return nil, err
// }
// for _, provider := range providerList.Items {
// names = append(names, provider.Name)
// }
// return names, nil
// }
//
// Get the value of argument AddonTerraformProviderNameArgument
// func getTerraformProviderArgumentValue(addonName string, args map[string]string) (map[string]string, string) {
// providerName, ok := args[AddonTerraformProviderNameArgument]
// if !ok {
// switch addonName {
// case "terraform-alibaba":
// providerName = "default"
// case "terraform-aws":
// providerName = "aws"
// case "terraform-azure":
// providerName = "azure"
// }
// args[AddonTerraformProviderNameArgument] = providerName
// }
// return args, providerName
// }