From f5b98a39e5a4b30cb2635e859fb98c9585c43fa6 Mon Sep 17 00:00:00 2001 From: "Roland.Ma" Date: Mon, 6 Sep 2021 03:14:32 +0000 Subject: [PATCH] add cluster list api Signed-off-by: Roland.Ma --- pkg/apiserver/apiserver.go | 2 +- pkg/kapis/gateway/v1alpha1/handler.go | 16 +++- pkg/kapis/gateway/v1alpha1/register.go | 5 +- pkg/models/gateway/gateway.go | 125 +++++++++++++++++++------ 4 files changed, 115 insertions(+), 33 deletions(-) diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 998e97443..b716b25a3 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -271,7 +271,7 @@ func (s *APIServer) installKubeSphereAPIs() { urlruntime.Must(kubeedgev1alpha1.AddToContainer(s.container, s.Config.KubeEdgeOptions.Endpoint)) urlruntime.Must(notificationkapisv2beta1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), s.KubernetesClient.KubeSphere())) - urlruntime.Must(gatewayv1alpha1.AddToContainer(s.container, s.Config.GatewayOptions, s.RuntimeClient)) + urlruntime.Must(gatewayv1alpha1.AddToContainer(s.container, s.Config.GatewayOptions, s.RuntimeCache, s.RuntimeClient)) } func (s *APIServer) Run(ctx context.Context) (err error) { diff --git a/pkg/kapis/gateway/v1alpha1/handler.go b/pkg/kapis/gateway/v1alpha1/handler.go index 03b479549..a31351c12 100644 --- a/pkg/kapis/gateway/v1alpha1/handler.go +++ b/pkg/kapis/gateway/v1alpha1/handler.go @@ -19,9 +19,11 @@ package v1alpha1 import ( "github.com/emicklei/go-restful" "kubesphere.io/api/gateway/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" operator "kubesphere.io/kubesphere/pkg/models/gateway" servererr "kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/simple/client/gateway" @@ -33,12 +35,12 @@ type handler struct { } //newHandler create an instance of the handler -func newHandler(options *gateway.Options, client client.Client) *handler { +func newHandler(options *gateway.Options, cache cache.Cache, client client.Client) *handler { // Do not register Gateway scheme globally. Which will cause conflict in ks-controller-manager. v1alpha1.AddToScheme(client.Scheme()) return &handler{ options: options, - gw: operator.NewGatewayOperator(client, options), + gw: operator.NewGatewayOperator(client, cache, options), } } @@ -114,5 +116,13 @@ func (h *handler) Upgrade(request *restful.Request, response *restful.Response) } func (h *handler) List(request *restful.Request, response *restful.Response) { - //TODO + queryParam := query.ParseQueryParameter(request) + + result, err := h.gw.ListGateways(queryParam) + if err != nil { + api.HandleError(response, request, err) + return + } + + response.WriteEntity(result) } diff --git a/pkg/kapis/gateway/v1alpha1/register.go b/pkg/kapis/gateway/v1alpha1/register.go index 96db179fc..c3bc84687 100644 --- a/pkg/kapis/gateway/v1alpha1/register.go +++ b/pkg/kapis/gateway/v1alpha1/register.go @@ -23,6 +23,7 @@ import ( restfulspec "github.com/emicklei/go-restful-openapi" "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/api/gateway/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "kubesphere.io/kubesphere/pkg/api" @@ -34,10 +35,10 @@ import ( var GroupVersion = schema.GroupVersion{Group: "gateway.kubesphere.io", Version: "v1alpha1"} -func AddToContainer(container *restful.Container, options *gateway.Options, client client.Client) error { +func AddToContainer(container *restful.Container, options *gateway.Options, cache cache.Cache, client client.Client) error { ws := runtime.NewWebService(GroupVersion) - handler := newHandler(options, client) + handler := newHandler(options, cache, client) // register gateway apis ws.Route(ws.POST("/namespaces/{namespace}/gateways"). diff --git a/pkg/models/gateway/gateway.go b/pkg/models/gateway/gateway.go index 842eb0174..07ebb72b2 100644 --- a/pkg/models/gateway/gateway.go +++ b/pkg/models/gateway/gateway.go @@ -19,16 +19,23 @@ package gateway import ( "context" "fmt" + "strings" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "kubesphere.io/api/gateway/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" "kubesphere.io/kubesphere/pkg/simple/client/gateway" ) @@ -45,16 +52,19 @@ type GatewayOperator interface { DeleteGateway(namespace string) error UpdateGateway(namespace string, obj *v1alpha1.Gateway) (*v1alpha1.Gateway, error) UpgradeGateway(namespace string) (*v1alpha1.Gateway, error) + ListGateways(query *query.Query) (*api.ListResult, error) } type gatewayOperator struct { client client.Client + cache cache.Cache options *gateway.Options } -func NewGatewayOperator(client client.Client, options *gateway.Options) GatewayOperator { +func NewGatewayOperator(client client.Client, cache cache.Cache, options *gateway.Options) GatewayOperator { return &gatewayOperator{ client: client, + cache: cache, options: options, } } @@ -96,8 +106,6 @@ func (c *gatewayOperator) getGlobalGateway() *v1alpha1.Gateway { // getLegacyGateway returns gateway created by the router api. // Should always prompt user to upgrade the gateway. func (c *gatewayOperator) getLegacyGateway(namespace string) *v1alpha1.Gateway { - var legacy v1alpha1.Gateway - s := &corev1.ServiceList{} // filter legacy service by labels @@ -113,34 +121,37 @@ func (c *gatewayOperator) getLegacyGateway(namespace string) *v1alpha1.Gateway { // create a fake Gateway object when legacy service exists if len(s.Items) > 0 { - svc := s.Items[0] - legacy = v1alpha1.Gateway{ - TypeMeta: v1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - ObjectMeta: v1.ObjectMeta{ - Name: svc.Name, - Namespace: svc.Namespace, - }, - Spec: v1alpha1.GatewaySpec{ - Conroller: v1alpha1.ControllerSpec{ - Scope: v1alpha1.Scope{ - Enabled: true, - Namespace: namespace, - }, - }, - Service: v1alpha1.ServiceSpec{ - Annotations: svc.Annotations, - Type: svc.Spec.Type, - }, - }, - } - return &legacy + return c.convert(namespace, &s.Items[0]) } return nil } +func (c *gatewayOperator) convert(namespace string, svc *corev1.Service) *v1alpha1.Gateway { + legacy := v1alpha1.Gateway{ + TypeMeta: v1.TypeMeta{ + Kind: "", + APIVersion: "", + }, + ObjectMeta: v1.ObjectMeta{ + Name: svc.Name, + Namespace: svc.Namespace, + }, + Spec: v1alpha1.GatewaySpec{ + Conroller: v1alpha1.ControllerSpec{ + Scope: v1alpha1.Scope{ + Enabled: true, + Namespace: namespace, + }, + }, + Service: v1alpha1.ServiceSpec{ + Annotations: svc.Annotations, + Type: svc.Spec.Type, + }, + }, + } + return &legacy +} + // GetGateways returns all Gateways from the project. There are at most 2 gatways exists in a project, // a Glabal Gateway and a Project Gateway or a Legacy Project Gateway. func (c *gatewayOperator) GetGateways(namespace string) ([]*v1alpha1.Gateway, error) { @@ -246,3 +257,63 @@ func (c *gatewayOperator) UpgradeGateway(namespace string) (*v1alpha1.Gateway, e err = c.client.Create(context.TODO(), l) return l, err } + +func (c *gatewayOperator) ListGateways(query *query.Query) (*api.ListResult, error) { + applications := v1alpha1.GatewayList{} + err := c.cache.List(context.TODO(), &applications, &client.ListOptions{LabelSelector: query.Selector()}) + if err != nil { + return nil, err + } + var result []runtime.Object + for i := range applications.Items { + result = append(result, &applications.Items[i]) + } + + services := &corev1.ServiceList{} + + // filter legacy service by labels + _ = c.client.List(context.TODO(), services, &client.ListOptions{ + LabelSelector: labels.SelectorFromSet( + labels.Set{ + "app": "kubesphere", + "component": "ks-router", + "tier": "backend", + }), + }) + + for _, s := range services.Items { + g := c.convert(s.Labels["project"], &s) + result = append(result, g) + } + + return v1alpha3.DefaultList(result, query, c.compare, c.filter), nil +} + +func (d *gatewayOperator) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + leftApplication, ok := left.(*v1alpha1.Gateway) + if !ok { + return false + } + + rightApplication, ok := right.(*v1alpha1.Gateway) + if !ok { + return false + } + + return v1alpha3.DefaultObjectMetaCompare(leftApplication.ObjectMeta, rightApplication.ObjectMeta, field) +} + +func (d *gatewayOperator) filter(object runtime.Object, filter query.Filter) bool { + gateway, ok := object.(*v1alpha1.Gateway) + if !ok { + return false + } + + switch filter.Field { + case query.FieldNamespace: + return strings.Compare(gateway.Spec.Conroller.Scope.Namespace, string(filter.Value)) == 0 + default: + return v1alpha3.DefaultObjectMetaFilter(gateway.ObjectMeta, filter) + } +}