github.com/oam-dev/kubevela@v1.9.11/references/cli/top/model/info.go (about)

     1  /*
     2  Copyright 2022 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 model
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"runtime"
    24  	"strconv"
    25  	"strings"
    26  
    27  	v1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/cli-runtime/pkg/genericclioptions"
    30  	"k8s.io/client-go/kubernetes"
    31  	"k8s.io/client-go/rest"
    32  	"k8s.io/client-go/tools/clientcmd/api"
    33  	"k8s.io/metrics/pkg/apis/metrics/v1beta1"
    34  	metrics "k8s.io/metrics/pkg/client/clientset/versioned"
    35  	"sigs.k8s.io/controller-runtime/pkg/client"
    36  
    37  	"github.com/oam-dev/kubevela/apis/types"
    38  	"github.com/oam-dev/kubevela/pkg/utils/common"
    39  	"github.com/oam-dev/kubevela/pkg/utils/helm"
    40  	clicommon "github.com/oam-dev/kubevela/references/common"
    41  	"github.com/oam-dev/kubevela/version"
    42  )
    43  
    44  // Info is system info struct
    45  type Info struct {
    46  	config *api.Config
    47  }
    48  
    49  const (
    50  	// Unknown info
    51  	Unknown = "UNKNOWN"
    52  	// VelaSystemNS is the namespace of vela-system, which is the namespace of vela-core and vela-cluster-gateway
    53  	VelaSystemNS = "vela-system"
    54  	// VelaCoreAppName is the app name of vela-core
    55  	VelaCoreAppName = "app.kubernetes.io/name=vela-core"
    56  	// ClusterGatewayAppName is the app name of vela-core
    57  	ClusterGatewayAppName = "app.kubernetes.io/name=vela-core-cluster-gateway"
    58  )
    59  
    60  // NewInfo return a new info struct
    61  func NewInfo() *Info {
    62  	info := &Info{}
    63  	k := genericclioptions.NewConfigFlags(true)
    64  	rawConfig, err := k.ToRawKubeConfigLoader().RawConfig()
    65  	if err == nil {
    66  		info.config = &rawConfig
    67  	}
    68  	return info
    69  }
    70  
    71  // CurrentContext return current context info
    72  func (i *Info) CurrentContext() string {
    73  	if i.config != nil {
    74  		return i.config.CurrentContext
    75  	}
    76  	return Unknown
    77  }
    78  
    79  // ClusterNum return cluster number
    80  func (i *Info) ClusterNum() string {
    81  	if i.config != nil {
    82  		return strconv.Itoa(len(i.config.Clusters))
    83  	}
    84  	return "0"
    85  }
    86  
    87  // K8SVersion return k8s version info
    88  func K8SVersion(cfg *rest.Config) string {
    89  	c, err := kubernetes.NewForConfig(cfg)
    90  	if err != nil {
    91  		return Unknown
    92  	}
    93  	serverVersion, err := c.ServerVersion()
    94  	if err != nil {
    95  		return Unknown
    96  	}
    97  	vStr := fmt.Sprintf("%s.%s", serverVersion.Major, strings.Replace(serverVersion.Minor, "+", "", 1))
    98  	return vStr
    99  }
   100  
   101  // VelaCLIVersion return vela cli version info
   102  func VelaCLIVersion() string {
   103  	return version.VelaVersion
   104  }
   105  
   106  // VelaCoreVersion return vela core version info
   107  func VelaCoreVersion() string {
   108  	results, err := helm.GetHelmRelease(types.DefaultKubeVelaNS)
   109  	if err != nil {
   110  		return Unknown
   111  	}
   112  	for _, result := range results {
   113  		if result.Chart.ChartFullPath() == types.DefaultKubeVelaChartName {
   114  			return result.Chart.AppVersion()
   115  		}
   116  	}
   117  	return Unknown
   118  }
   119  
   120  // GOLangVersion return golang version info
   121  func GOLangVersion() string {
   122  	return runtime.Version()
   123  }
   124  
   125  // ApplicationRunningNum return the num of running application
   126  func ApplicationRunningNum(cfg *rest.Config) string {
   127  	ctx := context.Background()
   128  	c, err := client.New(cfg, client.Options{Scheme: common.Scheme})
   129  	if err != nil {
   130  		return clicommon.MetricsNA
   131  	}
   132  	appNum, err := applicationNum(ctx, c)
   133  	if err != nil {
   134  		return clicommon.MetricsNA
   135  	}
   136  	runningAppNum, err := runningApplicationNum(ctx, c)
   137  	if err != nil {
   138  		return clicommon.MetricsNA
   139  	}
   140  	return fmt.Sprintf("%d/%d", runningAppNum, appNum)
   141  }
   142  
   143  func velaCorePodUsage(cfg *rest.Config) (*v1beta1.PodMetrics, error) {
   144  	ctx := context.Background()
   145  	c, err := metrics.NewForConfig(cfg)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	metricsList, err := c.MetricsV1beta1().PodMetricses(VelaSystemNS).List(ctx, metav1.ListOptions{LabelSelector: VelaCoreAppName})
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	if len(metricsList.Items) != 1 {
   154  		return nil, errors.New("the num of vela core container isn't right")
   155  	}
   156  	return &metricsList.Items[0], nil
   157  }
   158  
   159  func velaCorePod(cfg *rest.Config) (*v1.Pod, error) {
   160  	ctx := context.Background()
   161  	pods := v1.PodList{}
   162  	c, err := client.New(cfg, client.Options{Scheme: common.Scheme})
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	opts := []client.ListOption{
   167  		client.InNamespace(VelaSystemNS),
   168  		client.MatchingLabels{"app.kubernetes.io/name": "vela-core"},
   169  	}
   170  	err = c.List(ctx, &pods, opts...)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	if len(pods.Items) != 1 {
   175  		return nil, errors.New("the num of vela core container isn't right")
   176  	}
   177  	return &pods.Items[0], nil
   178  }
   179  
   180  // VelaCoreRatio return the usage condition of vela-core pod
   181  func VelaCoreRatio(c client.Client, cfg *rest.Config) (string, string, string, string) {
   182  	mtx, err := velaCorePodUsage(cfg)
   183  	if err != nil {
   184  		return clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA
   185  	}
   186  	pod, err := velaCorePod(cfg)
   187  	if err != nil {
   188  		return clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA
   189  	}
   190  	spec, usage := clicommon.GetPodResourceSpecAndUsage(c, pod, mtx)
   191  	cpuLRatio, memLRatio := clicommon.ToPercentageStr(usage.CPU, spec.Lcpu), clicommon.ToPercentageStr(usage.Mem, spec.Lmem)
   192  	cpuRRatio, memRRatio := clicommon.ToPercentageStr(usage.CPU, spec.Rcpu), clicommon.ToPercentageStr(usage.Mem, spec.Rmem)
   193  	return cpuLRatio, memLRatio, cpuRRatio, memRRatio
   194  }
   195  
   196  func velaCLusterGatewayPodUsage(cfg *rest.Config) (*v1beta1.PodMetrics, error) {
   197  	ctx := context.Background()
   198  	c, err := metrics.NewForConfig(cfg)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	metricsList, err := c.MetricsV1beta1().PodMetricses(VelaSystemNS).List(ctx, metav1.ListOptions{LabelSelector: ClusterGatewayAppName})
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	if len(metricsList.Items) != 1 || len(metricsList.Items[0].Containers) != 1 {
   207  		return nil, errors.New("the num of vela core cluster gateway container isn't right")
   208  	}
   209  	return &metricsList.Items[0], nil
   210  }
   211  
   212  func velaCLusterGatewayPod(cfg *rest.Config) (*v1.Pod, error) {
   213  	ctx := context.Background()
   214  	pods := v1.PodList{}
   215  	c, err := client.New(cfg, client.Options{Scheme: common.Scheme})
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	opts := []client.ListOption{
   220  		client.InNamespace(VelaSystemNS),
   221  		client.MatchingLabels{"app.kubernetes.io/name": "vela-core-cluster-gateway"},
   222  	}
   223  	err = c.List(ctx, &pods, opts...)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	if len(pods.Items) != 1 || len(pods.Items[0].Spec.Containers) != 1 {
   228  		return nil, errors.New("the num of vela core cluster gateway container isn't right")
   229  	}
   230  	return &pods.Items[0], nil
   231  }
   232  
   233  // CLusterGatewayRatio return the usage condition of vela-core cluster gateway pod
   234  func CLusterGatewayRatio(c client.Client, cfg *rest.Config) (string, string, string, string) {
   235  	mtx, err := velaCLusterGatewayPodUsage(cfg)
   236  	if err != nil {
   237  		return clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA
   238  	}
   239  	pod, err := velaCLusterGatewayPod(cfg)
   240  	if err != nil {
   241  		return clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA, clicommon.MetricsNA
   242  	}
   243  	spec, usage := clicommon.GetPodResourceSpecAndUsage(c, pod, mtx)
   244  	cpuLRatio, memLRatio := clicommon.ToPercentageStr(usage.CPU, spec.Lcpu), clicommon.ToPercentageStr(usage.Mem, spec.Lmem)
   245  	cpuRRatio, memRRatio := clicommon.ToPercentageStr(usage.CPU, spec.Rcpu), clicommon.ToPercentageStr(usage.Mem, spec.Rmem)
   246  	return cpuLRatio, memLRatio, cpuRRatio, memRRatio
   247  }