github.com/oam-dev/kubevela@v1.9.11/references/cli/ls.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cli 18 19 import ( 20 "context" 21 "strings" 22 23 "github.com/oam-dev/kubevela/pkg/utils" 24 25 "github.com/gosuri/uitable" 26 "github.com/spf13/cobra" 27 apierrors "k8s.io/apimachinery/pkg/api/errors" 28 "k8s.io/apimachinery/pkg/fields" 29 "k8s.io/apimachinery/pkg/labels" 30 "k8s.io/apimachinery/pkg/runtime" 31 "sigs.k8s.io/controller-runtime/pkg/client" 32 33 commontypes "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 34 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 35 "github.com/oam-dev/kubevela/apis/types" 36 "github.com/oam-dev/kubevela/pkg/utils/common" 37 cmdutil "github.com/oam-dev/kubevela/pkg/utils/util" 38 ) 39 40 // AllNamespace list app in all namespaces 41 var AllNamespace bool 42 43 // LabelSelector list app using label selector 44 var LabelSelector string 45 46 // FieldSelector list app using field selector 47 var FieldSelector string 48 49 // NewListCommand creates `ls` command and its nested children command 50 func NewListCommand(c common.Args, order string, ioStreams cmdutil.IOStreams) *cobra.Command { 51 ctx := context.Background() 52 cmd := &cobra.Command{ 53 Use: "ls", 54 Aliases: []string{"list"}, 55 DisableFlagsInUseLine: true, 56 Short: "List applications.", 57 Long: "List all vela applications.", 58 Example: `vela ls`, 59 RunE: func(cmd *cobra.Command, args []string) error { 60 newClient, err := c.GetClient() 61 if err != nil { 62 return err 63 } 64 namespace, err := GetFlagNamespaceOrEnv(cmd, c) 65 if err != nil { 66 return err 67 } 68 if AllNamespace { 69 namespace = "" 70 } 71 return printApplicationList(ctx, newClient, namespace, ioStreams) 72 }, 73 Annotations: map[string]string{ 74 types.TagCommandOrder: order, 75 types.TagCommandType: types.TypeStart, 76 }, 77 } 78 addNamespaceAndEnvArg(cmd) 79 cmd.Flags().BoolVarP(&AllNamespace, "all-namespaces", "A", false, "If true, check the specified action in all namespaces.") 80 cmd.Flags().StringVarP(&LabelSelector, "selector", "l", LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).") 81 cmd.Flags().StringVar(&FieldSelector, "field-selector", FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2).") 82 return cmd 83 } 84 85 func printApplicationList(ctx context.Context, c client.Reader, namespace string, ioStreams cmdutil.IOStreams) error { 86 table, err := buildApplicationListTable(ctx, c, namespace) 87 if err != nil { 88 return err 89 } 90 ioStreams.Info(table.String()) 91 return nil 92 } 93 94 func buildApplicationListTable(ctx context.Context, c client.Reader, namespace string) (*uitable.Table, error) { 95 table := newUITable() 96 header := []interface{}{"APP", "COMPONENT", "TYPE", "TRAITS", "PHASE", "HEALTHY", "STATUS", "CREATED-TIME"} 97 if AllNamespace { 98 header = append([]interface{}{"NAMESPACE"}, header...) 99 } 100 table.AddRow(header...) 101 102 labelSelector := labels.NewSelector() 103 if len(LabelSelector) > 0 { 104 selector, err := labels.Parse(LabelSelector) 105 if err != nil { 106 return nil, err 107 } 108 labelSelector = selector 109 } 110 111 applist := v1beta1.ApplicationList{} 112 if err := c.List(ctx, &applist, client.InNamespace(namespace), &client.ListOptions{LabelSelector: labelSelector}); err != nil { 113 if apierrors.IsNotFound(err) { 114 return table, nil 115 } 116 return nil, err 117 } 118 119 if len(FieldSelector) > 0 { 120 fieldSelector, err := fields.ParseSelector(FieldSelector) 121 if err != nil { 122 return nil, err 123 } 124 var objects []runtime.Object 125 for i := range applist.Items { 126 objects = append(objects, &applist.Items[i]) 127 } 128 applist.Items = objectsToApps(utils.FilterObjectsByFieldSelector(objects, fieldSelector)) 129 } 130 131 for _, a := range applist.Items { 132 service := map[string]commontypes.ApplicationComponentStatus{} 133 for _, s := range a.Status.Services { 134 service[s.Name] = s 135 } 136 137 if len(a.Spec.Components) == 0 { 138 if AllNamespace { 139 table.AddRow(a.Namespace, a.Name, "", "", "", a.Status.Phase, "", "", a.CreationTimestamp) 140 } else { 141 table.AddRow(a.Name, "", "", "", a.Status.Phase, "", "", a.CreationTimestamp) 142 } 143 continue 144 } 145 146 for idx, cmp := range a.Spec.Components { 147 var appName = a.Name 148 if idx > 0 { 149 appName = "├─" 150 if idx == len(a.Spec.Components)-1 { 151 appName = "└─" 152 } 153 } 154 155 var healthy, status string 156 if s, ok := service[cmp.Name]; ok { 157 healthy = getHealthString(s.Healthy) 158 status = s.Message 159 } 160 161 var traits []string 162 for _, tr := range cmp.Traits { 163 traits = append(traits, tr.Type) 164 } 165 if AllNamespace { 166 table.AddRow(a.Namespace, appName, cmp.Name, cmp.Type, strings.Join(traits, ","), a.Status.Phase, healthy, status, a.CreationTimestamp) 167 } else { 168 table.AddRow(appName, cmp.Name, cmp.Type, strings.Join(traits, ","), a.Status.Phase, healthy, status, a.CreationTimestamp) 169 } 170 } 171 } 172 return table, nil 173 } 174 175 func getHealthString(healthy bool) string { 176 if healthy { 177 return "healthy" 178 } 179 return "unhealthy" 180 } 181 182 // objectsToApps objects to apps 183 func objectsToApps(objs []runtime.Object) []v1beta1.Application { 184 res := make([]v1beta1.Application, 0) 185 for _, obj := range objs { 186 obj, ok := obj.(*v1beta1.Application) 187 if ok { 188 res = append(res, *obj) 189 } 190 } 191 return res 192 }