Skip to content

Commit

Permalink
chore: adapt cluster describe command with 1.0 api (#438)
Browse files Browse the repository at this point in the history
  • Loading branch information
wangyelei authored and yipeng1030 committed Sep 20, 2024
1 parent 25bdc83 commit b662092
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 227 deletions.
150 changes: 119 additions & 31 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package cluster
import (
"context"
"fmt"
"slices"
"strings"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -313,7 +314,7 @@ func (o *ClusterObjects) GetClusterInfo() *ClusterInfo {
}

primaryComponent := FindClusterComp(o.Cluster, o.ClusterDef.Spec.ComponentDefs[0].Name)
internalEndpoints, externalEndpoints := GetComponentEndpoints(o.Services, primaryComponent)
internalEndpoints, externalEndpoints := GetComponentEndpoints(o.Nodes, o.Services, primaryComponent.Name)
if len(internalEndpoints) > 0 {
cluster.InternalEP = strings.Join(internalEndpoints, ",")
}
Expand All @@ -325,63 +326,150 @@ func (o *ClusterObjects) GetClusterInfo() *ClusterInfo {

func (o *ClusterObjects) GetComponentInfo() []*ComponentInfo {
var comps []*ComponentInfo
for _, c := range o.Cluster.Spec.ComponentSpecs {
// get all pods belonging to current component
var pods []corev1.Pod
setComponentInfos := func(compSpec appsv1alpha1.ClusterComponentSpec,
resources corev1.ResourceRequirements,
storages []appsv1alpha1.ClusterComponentVolumeClaimTemplate,
replicas int32,
clusterCompName string,
templateName string,
isSharding bool) {
// get all pods belonging to current component and instance template
var (
pods []corev1.Pod
// a unique name identifier for component object and labeled with "apps.kubeblocks.io/component-name"
componentName string
)
for _, p := range o.Pods.Items {
if n, ok := p.Labels[constant.KBAppComponentLabelKey]; ok && n == c.Name {
pods = append(pods, p)
if isSharding && p.Labels[constant.KBAppShardingNameLabelKey] != clusterCompName {
continue
}
if !isSharding && p.Labels[constant.KBAppComponentLabelKey] != clusterCompName {
continue
}
insTplName := appsv1alpha1.GetInstanceTemplateName(o.Cluster.Name,
p.Labels[constant.KBAppComponentLabelKey], p.Name)
if insTplName != templateName {
continue
}
componentName = p.Labels[constant.KBAppComponentLabelKey]
pods = append(pods, p)
}

// current component has no derived pods
if len(pods) == 0 {
continue
return
}

image := types.None
if len(pods) > 0 {
image = pods[0].Spec.Containers[0].Image
var images []string
for _, con := range pods[0].Spec.Containers {
if !slices.Contains(images, con.Image) {
images = append(images, con.Image)
}
}
image = strings.Join(images, "\n")
}

running, waiting, succeeded, failed := util.GetPodStatus(pods)
comp := &ComponentInfo{
Name: c.Name,
NameSpace: o.Cluster.Namespace,
Type: c.ComponentDefRef,
Cluster: o.Cluster.Name,
Replicas: fmt.Sprintf("%d / %d", c.Replicas, len(pods)),
Status: fmt.Sprintf("%d / %d / %d / %d ", running, waiting, succeeded, failed),
Image: image,
}
comp.CPU, comp.Memory = getResourceInfo(c.Resources.Requests, c.Resources.Limits)
comp.Storage = o.getStorageInfo(&c)
Name: clusterCompName,
InstanceTemplateName: templateName,
NameSpace: o.Cluster.Namespace,
ComponentDef: compSpec.ComponentDef,
Cluster: o.Cluster.Name,
Replicas: fmt.Sprintf("%d / %d", replicas, len(pods)),
Status: fmt.Sprintf("%d / %d / %d / %d ", running, waiting, succeeded, failed),
Image: image,
}
comp.CPU, comp.Memory = getResourceInfo(resources.Requests, resources.Limits)
comp.Storage = o.getStorageInfo(storages, componentName)
comps = append(comps, comp)
}
buildComponentInfos := func(compSpec appsv1alpha1.ClusterComponentSpec, clusterCompName string, isSharding bool) {
var tplReplicas int32
for _, ins := range compSpec.Instances {
resources := compSpec.Resources
if ins.Resources != nil {
resources = *ins.Resources
}
vcts := o.getCompTemplateVolumeClaimTemplates(&compSpec, ins)
setComponentInfos(compSpec, resources, vcts, ins.GetReplicas(), clusterCompName, ins.Name, isSharding)
}
setComponentInfos(compSpec, compSpec.Resources, compSpec.VolumeClaimTemplates,
compSpec.Replicas-tplReplicas, clusterCompName, "", isSharding)
}
for _, c := range o.Cluster.Spec.ComponentSpecs {
buildComponentInfos(c, c.Name, false)
}
for _, c := range o.Cluster.Spec.ShardingSpecs {
buildComponentInfos(c.Template, c.Name, true)
}
return comps
}

// getCompTemplateVolumeClaimTemplates merges volume claim for instance template
func (o *ClusterObjects) getCompTemplateVolumeClaimTemplates(compSpec *appsv1alpha1.ClusterComponentSpec,
template appsv1alpha1.InstanceTemplate) []appsv1alpha1.ClusterComponentVolumeClaimTemplate {
var vcts []appsv1alpha1.ClusterComponentVolumeClaimTemplate
for i := range compSpec.VolumeClaimTemplates {
insVctIndex := -1
for j := range template.VolumeClaimTemplates {
if template.VolumeClaimTemplates[j].Name == compSpec.VolumeClaimTemplates[i].Name {
insVctIndex = j
break
}
}
if insVctIndex != -1 {
vcts = append(vcts, template.VolumeClaimTemplates[insVctIndex])
} else {
vcts = append(vcts, compSpec.VolumeClaimTemplates[i])
}
}
return vcts
}

func (o *ClusterObjects) GetInstanceInfo() []*InstanceInfo {
var instances []*InstanceInfo
for _, pod := range o.Pods.Items {
componentName := getLabelVal(pod.Labels, constant.KBAppComponentLabelKey)
instance := &InstanceInfo{
Name: pod.Name,
Namespace: pod.Namespace,
Cluster: getLabelVal(pod.Labels, constant.AppInstanceLabelKey),
Component: getLabelVal(pod.Labels, constant.KBAppComponentLabelKey),
Component: componentName,
Status: o.getPodPhase(&pod),
Role: getLabelVal(pod.Labels, constant.RoleLabelKey),
AccessMode: getLabelVal(pod.Labels, constant.ConsensusSetAccessModeLabelKey),
CreatedTime: util.TimeFormat(&pod.CreationTimestamp),
}

var component *appsv1alpha1.ClusterComponentSpec
for i, c := range o.Cluster.Spec.ComponentSpecs {
if c.Name == instance.Component {
component = &o.Cluster.Spec.ComponentSpecs[i]
var componentSpec *appsv1alpha1.ClusterComponentSpec
shardingCompName := pod.Labels[constant.KBAppShardingNameLabelKey]
if shardingCompName != "" {
instance.Component = BuildShardingComponentName(shardingCompName, instance.Component)
for i, c := range o.Cluster.Spec.ShardingSpecs {
if c.Name == shardingCompName {
componentSpec = &o.Cluster.Spec.ShardingSpecs[i].Template
}
}
} else {
for i, c := range o.Cluster.Spec.ComponentSpecs {
if c.Name == instance.Component {
componentSpec = &o.Cluster.Spec.ComponentSpecs[i]
}
}
}
templateName := appsv1alpha1.GetInstanceTemplateName(o.Cluster.Name, componentName, pod.Name)
template := appsv1alpha1.InstanceTemplate{}
if templateName != "" {
for _, v := range componentSpec.Instances {
if v.Name == templateName {
template = v
break
}
}
}
instance.Storage = o.getStorageInfo(component)
vcts := o.getCompTemplateVolumeClaimTemplates(componentSpec, template)
instance.Storage = o.getStorageInfo(vcts, pod.Labels[constant.KBAppComponentLabelKey])
instance.ServiceVersion = componentSpec.ServiceVersion
getInstanceNodeInfo(o.Nodes, &pod, instance)
instance.CPU, instance.Memory = getResourceInfo(resource.PodRequestsAndLimits(&pod))
instances = append(instances, instance)
Expand Down Expand Up @@ -475,8 +563,8 @@ func (o *ClusterObjects) getPodPhase(pod *corev1.Pod) string {
return reason
}

func (o *ClusterObjects) getStorageInfo(component *appsv1alpha1.ClusterComponentSpec) []StorageInfo {
if component == nil {
func (o *ClusterObjects) getStorageInfo(vcts []appsv1alpha1.ClusterComponentVolumeClaimTemplate, componentName string) []StorageInfo {
if len(vcts) == 0 {
return nil
}

Expand All @@ -496,7 +584,7 @@ func (o *ClusterObjects) getStorageInfo(component *appsv1alpha1.ClusterComponent
continue
}

if labels[constant.KBAppComponentLabelKey] != component.Name {
if labels[constant.KBAppComponentLabelKey] != componentName {
continue
}

Expand All @@ -514,7 +602,7 @@ func (o *ClusterObjects) getStorageInfo(component *appsv1alpha1.ClusterComponent
}

var infos []StorageInfo
for _, vcTpl := range component.VolumeClaimTemplates {
for _, vcTpl := range vcts {
s := StorageInfo{
Name: vcTpl.Name,
}
Expand Down
116 changes: 116 additions & 0 deletions pkg/cluster/component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Copyright (C) 2022-2024 ApeCloud Co., Ltd
This file is part of KubeBlocks project
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package cluster

import (
"context"
"fmt"

appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
"github.com/apecloud/kubeblocks/pkg/constant"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"

"github.com/apecloud/kbcli/pkg/types"
)

type ComponentPair struct {
// a unique name identifier for component object,
// and labeled with "apps.kubeblocks.io/component-name"
ComponentName string
ComponentDefName string
ShardingName string
}

func ListShardingComponents(dynamic dynamic.Interface, clusterName, clusterNamespace, componentName string) ([]*appsv1alpha1.Component, error) {
unstructuredObjList, err := dynamic.Resource(types.ComponentGVR()).Namespace(clusterNamespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s,%s=%s", constant.AppInstanceLabelKey, clusterName, constant.KBAppShardingNameLabelKey, componentName),
})
if err != nil {
return nil, nil
}
var components []*appsv1alpha1.Component
for i := range unstructuredObjList.Items {
comp := &appsv1alpha1.Component{}
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObjList.Items[i].UnstructuredContent(), comp); err != nil {
return nil, err
}
components = append(components, comp)
}
return components, nil
}

func BuildShardingComponentName(shardingCompName, componentName string) string {
if shardingCompName == "" {
return componentName
}
return fmt.Sprintf("%s(%s)", shardingCompName, componentName)
}

func GetCompSpecAndCheckSharding(cluster *appsv1alpha1.Cluster, componentName string) (*appsv1alpha1.ClusterComponentSpec, bool) {
compSpec := cluster.Spec.GetComponentByName(componentName)
if compSpec != nil {
return compSpec, false
}
shardingSpec := cluster.Spec.GetShardingByName(componentName)
if shardingSpec == nil {
return nil, false
}
return &shardingSpec.Template, true
}

func GetClusterComponentPairs(dynamicClient dynamic.Interface, cluster *appsv1alpha1.Cluster) ([]ComponentPair, error) {
var componentPairs []ComponentPair
for _, compSpec := range cluster.Spec.ComponentSpecs {
componentPairs = append(componentPairs, ComponentPair{
ComponentName: compSpec.Name,
ComponentDefName: compSpec.ComponentDef,
})
}
for _, shardingSpec := range cluster.Spec.ShardingSpecs {
shardingComponentPairs, err := GetShardingComponentPairs(dynamicClient, cluster, shardingSpec)
if err != nil {
return nil, err
}
componentPairs = append(componentPairs, shardingComponentPairs...)
}
return componentPairs, nil
}

func GetShardingComponentPairs(dynamicClient dynamic.Interface, cluster *appsv1alpha1.Cluster, shardingSpec appsv1alpha1.ShardingSpec) ([]ComponentPair, error) {
var componentPairs []ComponentPair
shardingComps, err := ListShardingComponents(dynamicClient, cluster.Name, cluster.Namespace, shardingSpec.Name)
if err != nil {
return nil, err
}
if len(shardingComps) == 0 {
return nil, fmt.Errorf(`cannot find any component objects for sharding component "%s"`, shardingSpec.Name)
}
for i := range shardingComps {
compName := shardingComps[i].Labels[constant.KBAppComponentLabelKey]
componentPairs = append(componentPairs, ComponentPair{
ComponentName: compName,
ComponentDefName: shardingSpec.Template.ComponentDef,
ShardingName: shardingSpec.Name,
})
}
return componentPairs, nil
}
Loading

0 comments on commit b662092

Please sign in to comment.