migrate legacy API

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-04-14 13:59:37 +08:00
parent d38e396e8c
commit 5f951508c5
45 changed files with 1475 additions and 1358 deletions

View File

@@ -66,18 +66,20 @@ func (r *resourceHandler) handleListNamespaceResources(request *restful.Request,
conditions, err := params.ParseConditions(request)
if err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, err)
klog.Error(err)
api.HandleBadRequest(response, request, err)
return
}
result, err := r.resourcesGetter.ListResources(namespace, resource, conditions, orderBy, reverse, limit, offset)
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
response.WriteEntity(result)
}
func (r *resourceHandler) handleGetSystemHealthStatus(_ *restful.Request, response *restful.Response) {

View File

@@ -2,34 +2,56 @@ package v1alpha3
import (
"github.com/emicklei/go-restful"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/components"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"net/http"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
resourcev1alpha2 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/server/params"
"strings"
)
type Handler struct {
namespacedResourceGetter *resource.ResourceGetter
componentsGetter components.ComponentsGetter
resourceGetterV1alpha3 *resourcev1alpha3.ResourceGetter
resourcesGetterV1alpha2 *resourcev1alpha2.ResourceGetter
componentsGetter components.ComponentsGetter
}
func New(factory informers.InformerFactory) *Handler {
return &Handler{
namespacedResourceGetter: resource.New(factory),
componentsGetter: components.NewComponentsGetter(factory.KubernetesSharedInformerFactory()),
resourceGetterV1alpha3: resourcev1alpha3.NewResourceGetter(factory),
resourcesGetterV1alpha2: resourcev1alpha2.NewResourceGetter(factory),
componentsGetter: components.NewComponentsGetter(factory.KubernetesSharedInformerFactory()),
}
}
// handleListResources retrieves resources
func (h Handler) handleListResources(request *restful.Request, response *restful.Response) {
func (h *Handler) handleListResources(request *restful.Request, response *restful.Response) {
query := query.ParseQueryParameter(request)
resource := request.PathParameter("resources")
resourceType := request.PathParameter("resources")
namespace := request.PathParameter("namespace")
result, err := h.namespacedResourceGetter.List(resource, namespace, query)
result, err := h.resourceGetterV1alpha3.List(resourceType, namespace, query)
if err == nil {
response.WriteEntity(result)
return
}
if err != resourcev1alpha3.ErrResourceNotSupported {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
// fallback to v1alpha2
result, err = h.fallback(resourceType, namespace, query)
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
@@ -37,38 +59,96 @@ func (h Handler) handleListResources(request *restful.Request, response *restful
response.WriteEntity(result)
}
func (h Handler) handleGetComponentStatus(request *restful.Request, response *restful.Response) {
func (h *Handler) fallback(resourceType string, namespace string, q *query.Query) (*api.ListResult, error) {
orderBy := string(q.SortBy)
limit, offset := q.Pagination.Limit, q.Pagination.Offset
reverse := !q.Ascending
conditions := &params.Conditions{}
for _, filter := range q.Filters {
switch filter.Field {
case query.FieldName:
conditions.Match[v1alpha2.Name] = string(filter.Value)
break
case query.FieldCreationTimeStamp:
conditions.Match[v1alpha2.CreateTime] = string(filter.Value)
break
case query.FieldLastUpdateTimestamp:
conditions.Match[v1alpha2.UpdateTime] = string(filter.Value)
break
case query.FieldLabel:
values := strings.SplitN(string(filter.Value), ":", 2)
if len(values) == 2 {
conditions.Match[values[0]] = values[1]
} else {
conditions.Match[v1alpha2.Label] = values[0]
}
break
case query.FieldAnnotation:
values := strings.SplitN(string(filter.Value), ":", 2)
if len(values) == 2 {
conditions.Match[v1alpha2.Annotation] = values[1]
} else {
conditions.Match[v1alpha2.Annotation] = values[0]
}
break
case query.FieldStatus:
conditions.Match[v1alpha2.Status] = string(filter.Value)
break
case query.FieldOwnerReference:
conditions.Match[v1alpha2.Owner] = string(filter.Value)
break
}
}
result, err := h.resourcesGetterV1alpha2.ListResources(namespace, resourceType, conditions, orderBy, reverse, limit, offset)
if err != nil {
klog.Error(err)
return nil, err
}
return &api.ListResult{
Items: result.Items,
TotalItems: result.TotalCount,
}, nil
}
func (h *Handler) handleGetComponentStatus(request *restful.Request, response *restful.Response) {
component := request.PathParameter("component")
result, err := h.componentsGetter.GetComponentStatus(component)
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
response.WriteHeaderAndEntity(http.StatusOK, result)
response.WriteEntity(result)
}
func (h Handler) handleGetSystemHealthStatus(request *restful.Request, response *restful.Response) {
func (h *Handler) handleGetSystemHealthStatus(request *restful.Request, response *restful.Response) {
result, err := h.componentsGetter.GetSystemHealthStatus()
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
response.WriteHeaderAndEntity(http.StatusOK, result)
response.WriteEntity(result)
}
// get all componentsHandler
func (h Handler) handleGetComponents(request *restful.Request, response *restful.Response) {
func (h *Handler) handleGetComponents(request *restful.Request, response *restful.Response) {
result, err := h.componentsGetter.GetAllComponentsStatus()
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
response.WriteHeaderAndEntity(http.StatusOK, result)
response.WriteEntity(result)
}

View File

@@ -1,7 +1,191 @@
package v1alpha3
import "testing"
import (
"github.com/google/go-cmp/cmp"
fakeapp "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
fakeistio "istio.io/client-go/pkg/clientset/versioned/fake"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fakek8s "k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
"kubesphere.io/kubesphere/pkg/informers"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"testing"
)
func TestComponentHandler(t *testing.T) {
func TestResourceV1alpha2Fallback(t *testing.T) {
tests := []struct {
description string
namespace string
resource string
query *query.Query
expectedError error
expected *api.ListResult
}{
{
description: "list namespaces",
namespace: "default",
resource: "namespaces",
query: &query.Query{
Pagination: &query.Pagination{
Limit: 10,
Offset: 0,
},
SortBy: "name",
Ascending: false,
Filters: nil,
},
expectedError: nil,
expected: &api.ListResult{
Items: []interface{}{kubesphereNamespace, defaultNamespace},
TotalItems: 2,
},
},
{
description: "list secrets fallback",
namespace: "default",
resource: "secrets",
query: &query.Query{
Pagination: &query.Pagination{
Limit: 10,
Offset: 0,
},
SortBy: "name",
Ascending: false,
Filters: nil,
},
expectedError: nil,
expected: &api.ListResult{
Items: []interface{}{secretFoo2, secretFoo1},
TotalItems: 2,
},
},
}
factory, err := prepare()
if err != nil {
t.Fatal(err)
}
handler := New(factory)
for _, test := range tests {
got, err := listResources(test.namespace, test.resource, test.query, handler)
if err != test.expectedError {
t.Fatalf("expected error: %s, got: %s", test.expectedError, err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
}
}
func listResources(namespace, resourceType string, query *query.Query, h *Handler) (*api.ListResult, error) {
result, err := h.resourceGetterV1alpha3.List(resourceType, namespace, query)
if err == nil {
return result, nil
}
if err != resourcev1alpha3.ErrResourceNotSupported {
return nil, err
}
// fallback to v1alpha2
return h.fallback(resourceType, namespace, query)
}
var (
defaultNamespace = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Labels: map[string]string{"kubesphere.io/workspace": "system-workspace"},
},
}
kubesphereNamespace = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "kubesphere-system",
Labels: map[string]string{"kubesphere.io/workspace": "system-workspace"},
},
}
secretFoo1 = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "default",
},
}
secretFoo2 = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "default",
},
}
replicas = int32(1)
nginxDeployment = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Namespace: "default",
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
},
Status: appsv1.DeploymentStatus{
ReadyReplicas: 1,
},
}
redisDeployment = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "redis",
Namespace: "default",
Labels: map[string]string{"kubesphere.io/creator": "admin"},
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
},
Status: appsv1.DeploymentStatus{
ReadyReplicas: 0,
},
}
deployments = []interface{}{redisDeployment, nginxDeployment}
namespaces = []interface{}{defaultNamespace, kubesphereNamespace}
secrets = []interface{}{secretFoo1, secretFoo2}
)
func prepare() (informers.InformerFactory, error) {
ksClient := fakeks.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
istioClient := fakeistio.NewSimpleClientset()
appClient := fakeapp.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
k8sInformerFactory := fakeInformerFactory.KubernetesSharedInformerFactory()
for _, namespace := range namespaces {
err := k8sInformerFactory.Core().V1().Namespaces().Informer().GetIndexer().Add(namespace)
if err != nil {
return nil, err
}
}
for _, deployment := range deployments {
err := k8sInformerFactory.Apps().V1().Deployments().Informer().GetIndexer().Add(deployment)
if err != nil {
return nil, err
}
}
for _, secret := range secrets {
err := k8sInformerFactory.Core().V1().Secrets().Informer().GetIndexer().Add(secret)
if err != nil {
return nil, err
}
}
return fakeInformerFactory, nil
}