devlopment branch (#1736)

This commit is contained in:
zryfish
2020-01-02 20:52:00 +08:00
committed by GitHub
parent ff0ffe8650
commit eceadec69c
440 changed files with 61524 additions and 3699 deletions

View File

@@ -19,47 +19,56 @@ package components
import (
"fmt"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
"kubesphere.io/kubesphere/pkg/constants"
)
func GetComponentStatus(name string) (interface{}, error) {
type ComponentsGetter interface {
GetComponentStatus(name string) (v1alpha2.ComponentStatus, error)
GetSystemHealthStatus() (v1alpha2.HealthStatus, error)
GetAllComponentsStatus() ([]v1alpha2.ComponentStatus, error)
}
type componentsGetter struct {
informers informers.SharedInformerFactory
}
func NewComponentsGetter(informers informers.SharedInformerFactory) ComponentsGetter {
return &componentsGetter{informers: informers}
}
func (c *componentsGetter) GetComponentStatus(name string) (v1alpha2.ComponentStatus, error) {
var service *corev1.Service
var err error
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
for _, ns := range constants.SystemNamespaces {
service, err = serviceLister.Services(ns).Get(name)
service, err = c.informers.Core().V1().Services().Lister().Services(ns).Get(name)
if err == nil {
break
}
}
if err != nil {
return nil, err
return v1alpha2.ComponentStatus{}, err
}
if len(service.Spec.Selector) == 0 {
return nil, fmt.Errorf("component %s has no selector", name)
return v1alpha2.ComponentStatus{}, fmt.Errorf("component %s has no selector", name)
}
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
pods, err := c.informers.Core().V1().Pods().Lister().Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
if err != nil {
return nil, err
return v1alpha2.ComponentStatus{}, err
}
component := models.ComponentStatus{
component := v1alpha2.ComponentStatus{
Name: service.Name,
Namespace: service.Namespace,
SelfLink: service.SelfLink,
@@ -86,21 +95,20 @@ func isAllContainersReady(pod *corev1.Pod) bool {
return true
}
func GetSystemHealthStatus() (*models.HealthStatus, error) {
func (c *componentsGetter) GetSystemHealthStatus() (v1alpha2.HealthStatus, error) {
status := &models.HealthStatus{}
status := v1alpha2.HealthStatus{}
// get kubesphere-system components
components, err := GetAllComponentsStatus()
components, err := c.GetAllComponentsStatus()
if err != nil {
klog.Errorln(err)
}
status.KubeSphereComponents = components
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
// get node status
nodes, err := nodeLister.List(labels.Everything())
nodes, err := c.informers.Core().V1().Nodes().Lister().List(labels.Everything())
if err != nil {
klog.Errorln(err)
return status, nil
@@ -116,7 +124,7 @@ func GetSystemHealthStatus() (*models.HealthStatus, error) {
}
}
}
nodeStatus := models.NodeStatus{TotalNodes: totalNodes, HealthyNodes: healthyNodes}
nodeStatus := v1alpha2.NodeStatus{TotalNodes: totalNodes, HealthyNodes: healthyNodes}
status.NodeStatus = nodeStatus
@@ -124,16 +132,14 @@ func GetSystemHealthStatus() (*models.HealthStatus, error) {
}
func GetAllComponentsStatus() ([]models.ComponentStatus, error) {
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
func (c *componentsGetter) GetAllComponentsStatus() ([]v1alpha2.ComponentStatus, error) {
components := make([]models.ComponentStatus, 0)
components := make([]v1alpha2.ComponentStatus, 0)
var err error
for _, ns := range constants.SystemNamespaces {
services, err := serviceLister.Services(ns).List(labels.Everything())
services, err := c.informers.Core().V1().Services().Lister().Services(ns).List(labels.Everything())
if err != nil {
klog.Error(err)
@@ -147,7 +153,7 @@ func GetAllComponentsStatus() ([]models.ComponentStatus, error) {
continue
}
component := models.ComponentStatus{
component := v1alpha2.ComponentStatus{
Name: service.Name,
Namespace: service.Namespace,
SelfLink: service.SelfLink,
@@ -157,7 +163,7 @@ func GetAllComponentsStatus() ([]models.ComponentStatus, error) {
TotalBackends: 0,
}
pods, err := podLister.Pods(ns).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
pods, err := c.informers.Core().V1().Pods().Lister().Pods(ns).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
if err != nil {
klog.Errorln(err)

View File

@@ -0,0 +1,356 @@
package components
import (
"fmt"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
"testing"
"time"
)
func service(name, namespace string, selector map[string]string) runtime.Object {
return &v1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: v1.ServiceSpec{
Selector: selector,
},
}
}
func pods(name, namespace string, labels map[string]string, healthPods, totalPods int) []runtime.Object {
var ps []runtime.Object
for index := 0; index < totalPods; index++ {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%d", name, index),
Namespace: namespace,
Labels: labels,
},
Status: v1.PodStatus{
Phase: v1.PodRunning,
ContainerStatuses: []v1.ContainerStatus{
{
Name: fmt.Sprintf("%s-%d", name, index),
Ready: true,
},
},
},
}
if index >= healthPods {
pod.Status.Phase = v1.PodPending
pod.Status.ContainerStatuses[0].Ready = false
}
ps = append(ps, pod)
}
return ps
}
func nodes(name string, healthNodes, totalNodes int) []runtime.Object {
var ns []runtime.Object
for index := 0; index < totalNodes; index++ {
node := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%d", name, index),
},
Status: v1.NodeStatus{
Phase: v1.NodeRunning,
Conditions: []v1.NodeCondition{
{
Type: v1.NodeReady,
Status: v1.ConditionTrue,
},
},
},
}
if index >= healthNodes {
node.Status.Phase = v1.NodePending
node.Status.Conditions[0].Status = v1.ConditionFalse
}
ns = append(ns, node)
}
return ns
}
func TestGetSystemHealthStatus(t *testing.T) {
var tests = []struct {
description string
labels map[string]string
namespace string
name string
healthPods int
totalPods int
healthNodes int
totalNodes int
expected v1alpha2.HealthStatus
}{
{
"no backends",
map[string]string{"app": "foo"},
"kube-system",
"",
0,
0,
0,
0,
v1alpha2.HealthStatus{
KubeSphereComponents: []v1alpha2.ComponentStatus{
{
Namespace: "kube-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 0,
HealthyBackends: 0,
},
},
NodeStatus: v1alpha2.NodeStatus{},
},
},
{
"all healthy",
map[string]string{"app": "foo"},
"kubesphere-system",
"ks-apiserver",
2,
2,
2,
2,
v1alpha2.HealthStatus{
KubeSphereComponents: []v1alpha2.ComponentStatus{
{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 2,
HealthyBackends: 2,
},
},
NodeStatus: v1alpha2.NodeStatus{
TotalNodes: 2,
HealthyNodes: 2,
},
},
},
{
"all unhealthy",
map[string]string{"app": "foo"},
"kubesphere-system",
"ks-apiserver",
0,
2,
0,
2,
v1alpha2.HealthStatus{
KubeSphereComponents: []v1alpha2.ComponentStatus{
{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 2,
HealthyBackends: 0,
},
},
NodeStatus: v1alpha2.NodeStatus{
TotalNodes: 2,
HealthyNodes: 0,
},
},
},
{
"half healthy",
map[string]string{"app": "foo"},
"kubesphere-system",
"ks-apiserver",
2,
4,
2,
4,
v1alpha2.HealthStatus{
KubeSphereComponents: []v1alpha2.ComponentStatus{
{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 4,
HealthyBackends: 2,
},
},
NodeStatus: v1alpha2.NodeStatus{
TotalNodes: 4,
HealthyNodes: 2,
},
},
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
ps := pods(test.name, test.namespace, test.labels, test.healthPods, test.totalPods)
svc := service(test.name, test.namespace, test.labels)
ns := nodes(test.name, test.healthNodes, test.totalNodes)
var objs []runtime.Object
objs = append(objs, ps...)
objs = append(objs, svc)
objs = append(objs, ns...)
client := fake.NewSimpleClientset(objs...)
informer := informers.NewSharedInformerFactory(client, time.Minute*10)
informer.Core().V1().Services().Informer().GetIndexer().Add(svc)
for _, obj := range ps {
informer.Core().V1().Pods().Informer().GetIndexer().Add(obj)
}
for _, obj := range ns {
informer.Core().V1().Nodes().Informer().GetIndexer().Add(obj)
}
c := NewComponentsGetter(informer)
healthStatus, err := c.GetSystemHealthStatus()
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(healthStatus, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
return
}
})
}
}
func TestGetComponentStatus(t *testing.T) {
var tests = []struct {
description string
name string
namespace string
labels map[string]string
healthPods int
totalPods int
expected v1alpha2.ComponentStatus
expectedError bool
}{
{
"no component",
"random",
"foo",
map[string]string{"app": "foo"},
2,
4,
v1alpha2.ComponentStatus{
Name: "",
Namespace: "",
SelfLink: "",
Label: nil,
StartedAt: time.Time{},
TotalBackends: 0,
HealthyBackends: 0,
},
true,
},
{
"all healthy",
"ks-apiserver",
"kubesphere-system",
map[string]string{"app": "foo"},
2,
4,
v1alpha2.ComponentStatus{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 4,
HealthyBackends: 2,
},
false,
},
{
"all unhealthy",
"ks-apiserver",
"kubesphere-system",
map[string]string{"app": "foo"},
0,
4,
v1alpha2.ComponentStatus{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 4,
HealthyBackends: 0,
},
false,
},
{
"half healthy",
"ks-apiserver",
"kubesphere-system",
map[string]string{"app": "foo"},
2,
4,
v1alpha2.ComponentStatus{
Name: "ks-apiserver",
Namespace: "kubesphere-system",
Label: map[string]string{"app": "foo"},
TotalBackends: 4,
HealthyBackends: 2,
},
false,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
ps := pods(test.name, test.namespace, test.labels, test.healthPods, test.totalPods)
svc := service(test.name, test.namespace, test.labels)
var objs []runtime.Object
objs = append(objs, ps...)
objs = append(objs, svc)
client := fake.NewSimpleClientset(objs...)
informer := informers.NewSharedInformerFactory(client, time.Minute*10)
informer.Core().V1().Services().Informer().GetIndexer().Add(svc)
for _, obj := range ps {
informer.Core().V1().Pods().Informer().GetIndexer().Add(obj)
}
c := NewComponentsGetter(informer)
healthStatus, err := c.GetComponentStatus(test.name)
if err == nil && test.expectedError {
t.Fatalf("expected error while got nothing")
} else if err != nil && !test.expectedError {
t.Fatal(err)
}
if diff := cmp.Diff(healthStatus, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
return
}
})
}
}