未验证 提交 ff7f99c5 编写于 作者: K KubeSphere CI Bot 提交者: GitHub

Merge pull request #2011 from wansir/dev

migrate legacy API
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
kind: ValidatingWebhookConfiguration
metadata:
name: kubesphere-iam-validator
webhooks:
......
......@@ -152,7 +152,6 @@ const (
ClusterScope Scope = "Cluster"
WorkspaceScope Scope = "Workspace"
NamespaceScope Scope = "Namespace"
TargetAll = "*"
UserKind = "User"
PolicyRuleKind = "PolicyRule"
RoleKind = "Role"
......
......@@ -37,6 +37,7 @@ import (
resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
......@@ -141,6 +142,7 @@ func (s *APIServer) installKubeSphereAPIs() {
urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.OpenpitrixClient))
urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes()))
urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory))
urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory))
urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config()))
urlruntime.Must(iamv1alpha2.AddToContainer(s.container, im.NewOperator(s.KubernetesClient.KubeSphere(),
s.InformerFactory.KubeSphereSharedInformerFactory()),
......@@ -285,7 +287,6 @@ func (s *APIServer) waitForResourceSync(stopCh <-chan struct{}) error {
{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "roles"},
{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "rolebindings"},
{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "policyrules"},
{Group: "tower.kubesphere.io", Version: "v1alpha1", Resource: "agents"},
}
devopsGVRs := []schema.GroupVersionResource{
......
......@@ -51,7 +51,7 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author
return authorizer.DecisionDeny, "", err
}
// check platform role policy rules
// check global role policy rules
if authorized, reason, err = o.makeDecision(globalRole, attr); authorized == authorizer.DecisionAllow {
return authorized, reason, nil
}
......
......@@ -48,11 +48,12 @@ func newPagination(limit int, offset int) *Pagination {
}
func (p *Pagination) GetValidPagination(total int) (startIndex, endIndex int) {
if p.Limit == NoPagination.Limit {
return 0, total
}
if p.Limit < 0 || p.Offset < 0 {
if p.Limit < 0 || p.Offset < 0 || total == 0 {
return 0, 0
}
......
......@@ -36,7 +36,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response
limit, offset := params.ParsePaging(request)
namespace := request.PathParameter("namespace")
orderBy := params.GetStringValueWithDefault(request, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, false)
conditions, err := params.ParseConditions(request)
if err != nil {
......@@ -301,7 +301,7 @@ func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restf
func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
appId := req.PathParameter("app")
versionId := req.PathParameter("version")
conditions, err := params.ParseConditions(req)
......@@ -331,7 +331,7 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res
func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
......@@ -354,7 +354,7 @@ func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Resp
func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
appId := req.PathParameter("app")
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
conditions, err := params.ParseConditions(req)
......@@ -394,7 +394,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.
func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
conditions, err := params.ParseConditions(req)
......@@ -697,7 +697,7 @@ func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful
func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
conditions, err := params.ParseConditions(req)
......@@ -836,7 +836,7 @@ func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Res
func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
......
......@@ -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) {
......
......@@ -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)
}
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
}
......@@ -32,7 +32,7 @@ func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Respo
return
}
result, err := h.tenant.ListWorkspaces(user.GetName())
result, err := h.tenant.ListWorkspaces(user)
if err != nil {
api.HandleInternalError(resp, nil, err)
......@@ -52,9 +52,9 @@ func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Respo
return
}
worksapceName := req.PathParameter("workspace")
workspace := req.PathParameter("workspace")
result, err := h.tenant.ListNamespaces(worksapceName, user.GetName())
result, err := h.tenant.ListNamespaces(user, workspace)
if err != nil {
api.HandleInternalError(resp, nil, err)
......
......@@ -113,8 +113,7 @@ func (am *amOperator) GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target
return nil, err
}
for _, role := range roles {
if role.Target.Name == iamv1alpha2.TargetAll ||
role.Target.Name == target {
if role.Target.Name == target {
return &role, nil
}
}
......
......@@ -22,18 +22,9 @@ import (
"github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
"github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
)
const (
app = "app"
chart = "chart"
release = "release"
)
type appSearcher struct {
......@@ -48,70 +39,24 @@ func (s *appSearcher) Get(namespace, name string) (interface{}, error) {
return s.informer.App().V1beta1().Applications().Lister().Applications(namespace).Get(name)
}
// exactly Match
func (s *appSearcher) match(match map[string]string, item *v1beta1.Application) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*appSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.Application) bool {
func (s *appSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.Application) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*appSearcher) compare(a, b *v1beta1.Application, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *appSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
apps, err := s.informer.App().V1beta1().Applications().Lister().Applications(namespace).List(labels.Everything())
......@@ -134,7 +79,7 @@ func (s *appSearcher) Search(namespace string, conditions *params.Conditions, or
if reverse {
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -18,17 +18,14 @@
package clusterrole
import (
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
)
type clusterRoleSearcher struct {
......@@ -43,7 +40,6 @@ func (s *clusterRoleSearcher) Get(namespace, name string) (interface{}, error) {
return s.informer.Rbac().V1().ClusterRoles().Lister().Get(name)
}
// exactly Match
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
for k, v := range match {
switch k {
......@@ -55,15 +51,6 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
if !k8sutil.IsControlledBy(item.OwnerReferences, kind, name) {
return false
}
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
case v1alpha2.UserFacing:
if v == "true" {
if !isUserFacingClusterRole(item) {
......@@ -71,8 +58,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
}
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -80,43 +66,15 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
return true
}
// Fuzzy searchInNamespace
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
func (s *clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *clusterRoleSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
clusterRoles, err := s.informer.Rbac().V1().ClusterRoles().Lister().List(labels.Everything())
......@@ -137,11 +95,9 @@ func (s *clusterRoleSearcher) Search(namespace string, conditions *params.Condit
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -18,16 +18,12 @@
package configmap
import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
)
type configMapSearcher struct {
......@@ -42,70 +38,24 @@ func (s *configMapSearcher) Get(namespace, name string) (interface{}, error) {
return s.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).Get(name)
}
// exactly Match
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
func (s *configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
func (s *configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *configMapSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
configMaps, err := s.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
......@@ -128,7 +78,7 @@ func (s *configMapSearcher) Search(namespace string, conditions *params.Conditio
if reverse {
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -18,15 +18,11 @@
package cronjob
import (
"k8s.io/api/batch/v1beta1"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/batch/v1beta1"
"k8s.io/apimachinery/pkg/labels"
)
......@@ -50,26 +46,15 @@ func cronJobStatus(item *v1beta1.CronJob) string {
return v1alpha2.StatusRunning
}
// Exactly Match
func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Status:
if cronJobStatus(item) != v {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -80,50 +65,26 @@ func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bo
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
func (*cronJobSearcher) compare(left, right *v1beta1.CronJob, orderBy string) bool {
switch orderBy {
case v1alpha2.LastScheduleTime:
if a.Status.LastScheduleTime == nil {
if left.Status.LastScheduleTime == nil {
return true
}
if b.Status.LastScheduleTime == nil {
if right.Status.LastScheduleTime == nil {
return false
}
return a.Status.LastScheduleTime.Before(b.Status.LastScheduleTime)
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
return left.Status.LastScheduleTime.Before(right.Status.LastScheduleTime)
default:
fallthrough
case v1alpha2.Name:
return strings.Compare(a.Name, b.Name) <= 0
return v1alpha2.ObjectMetaCompare(left.ObjectMeta, right.ObjectMeta, orderBy)
}
}
......@@ -146,10 +107,7 @@ func (c *cronJobSearcher) Search(namespace string, conditions *params.Conditions
}
}
sort.Slice(result, func(i, j int) bool {
if reverse {
i, j = j, i
}
return c.compare(result[i], result[j], orderBy)
return c.compare(result[i], result[j], orderBy) && !reverse
})
r := make([]interface{}, 0)
......
......@@ -18,16 +18,12 @@
package daemonset
import (
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
)
type daemonSetSearcher struct {
......@@ -52,7 +48,6 @@ func daemonSetStatus(item *v1.DaemonSet) string {
}
}
// Exactly Match
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
for k, v := range match {
switch k {
......@@ -60,18 +55,8 @@ func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) boo
if daemonSetStatus(item) != v {
return false
}
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -79,48 +64,15 @@ func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) boo
return true
}
func (*daemonSetSearcher) fuzzy(fuzzy map[string]string, item *v1.DaemonSet) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
func (*daemonSetSearcher) fuzzy(kv map[string]string, item *v1.DaemonSet) bool {
for k, v := range kv {
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (c *daemonSetSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
daemonSets, err := c.informer.Apps().V1().DaemonSets().Lister().DaemonSets(namespace).List(labels.Everything())
......@@ -143,7 +95,7 @@ func (c *daemonSetSearcher) Search(namespace string, conditions *params.Conditio
if reverse {
i, j = j, i
}
return c.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
/*
*
* Copyright 2020 The KubeSphere Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package deployment
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
"strings"
"time"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/api/apps/v1"
)
type deploymentSearcher struct {
informer informers.SharedInformerFactory
}
func NewDeploymentSetSearcher(informers informers.SharedInformerFactory) v1alpha2.Interface {
return &deploymentSearcher{informer: informers}
}
func (s *deploymentSearcher) Get(namespace, name string) (interface{}, error) {
return s.informer.Apps().V1().Deployments().Lister().Deployments(namespace).Get(name)
}
func deploymentStatus(item *v1.Deployment) string {
if item.Spec.Replicas != nil {
if item.Status.ReadyReplicas == 0 && *item.Spec.Replicas == 0 {
return v1alpha2.StatusStopped
} else if item.Status.ReadyReplicas == *item.Spec.Replicas {
return v1alpha2.StatusRunning
} else {
return v1alpha2.StatusUpdating
}
}
return v1alpha2.StatusStopped
}
func (*deploymentSearcher) match(kv map[string]string, item *v1.Deployment) bool {
for k, v := range kv {
switch k {
case v1alpha2.Status:
if deploymentStatus(item) != v {
return false
}
default:
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
}
return true
}
func (*deploymentSearcher) fuzzy(kv map[string]string, item *v1.Deployment) bool {
for k, v := range kv {
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
func (s *deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
switch orderBy {
case v1alpha2.UpdateTime:
aLastUpdateTime := s.lastUpdateTime(a)
bLastUpdateTime := s.lastUpdateTime(b)
if aLastUpdateTime.Equal(bLastUpdateTime) {
return strings.Compare(a.Name, b.Name) <= 0
}
return aLastUpdateTime.Before(bLastUpdateTime)
default:
return v1alpha2.ObjectMetaCompare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
}
func (s *deploymentSearcher) lastUpdateTime(deployment *v1.Deployment) time.Time {
lastUpdateTime := deployment.CreationTimestamp.Time
for _, condition := range deployment.Status.Conditions {
if condition.LastUpdateTime.After(lastUpdateTime) {
lastUpdateTime = condition.LastUpdateTime.Time
}
}
return lastUpdateTime
}
func (s *deploymentSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
deployments, err := s.informer.Apps().V1().Deployments().Lister().Deployments(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
result := make([]*v1.Deployment, 0)
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = deployments
} else {
for _, item := range deployments {
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item)
}
}
}
sort.Slice(result, func(i, j int) bool {
if reverse {
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
})
r := make([]interface{}, 0)
for _, i := range result {
r = append(r, i)
}
return r, nil
}
......@@ -19,15 +19,11 @@ package hpa
import (
autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type hpaSearcher struct {
......@@ -58,17 +54,8 @@ func (*hpaSearcher) match(match map[string]string, item *autoscalingv2beta2.Hori
if !hpaTargetMatch(item, kind, name) {
return false
}
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
if item.Labels[k] != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -76,47 +63,15 @@ func (*hpaSearcher) match(match map[string]string, item *autoscalingv2beta2.Hori
return true
}
// Fuzzy searchInNamespace
func (*hpaSearcher) fuzzy(fuzzy map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) && !v1alpha2.SearchFuzzy(item.Annotations, k, v) {
return false
}
}
}
return true
}
func (*hpaSearcher) compare(a, b *autoscalingv2beta2.HorizontalPodAutoscaler, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *hpaSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
horizontalPodAutoscalers, err := s.informers.Autoscaling().V2beta2().HorizontalPodAutoscalers().Lister().HorizontalPodAutoscalers(namespace).List(labels.Everything())
......@@ -138,11 +93,9 @@ func (s *hpaSearcher) Search(namespace string, conditions *params.Conditions, or
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -18,15 +18,11 @@
package ingress
import (
"k8s.io/api/extensions/v1beta1"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/labels"
)
......@@ -43,70 +39,24 @@ func (s *ingressSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).Get(name)
}
// exactly Match
func (*ingressSearcher) match(match map[string]string, item *v1beta1.Ingress) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.Ingress) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*ingressSearcher) compare(a, b *v1beta1.Ingress, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *ingressSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
ingresses, err := s.informers.Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything())
......@@ -127,11 +77,9 @@ func (s *ingressSearcher) Search(namespace string, conditions *params.Conditions
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
package v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"strings"
)
......@@ -24,6 +27,7 @@ const (
Keyword = "keyword"
UserFacing = "userfacing"
Status = "status"
Owner = "owner"
StatusRunning = "running"
StatusPaused = "paused"
......@@ -66,7 +70,61 @@ type Interface interface {
Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
}
func SearchFuzzy(m map[string]string, key, value string) bool {
func ObjectMetaExactlyMath(key, value string, item metav1.ObjectMeta) bool {
switch key {
case Name:
names := strings.Split(value, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, value) && !FuzzyMatch(item.Labels, "", value) && !FuzzyMatch(item.Annotations, "", value) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[key]; !ok || val != value {
return false
}
}
return true
}
func ObjectMetaFuzzyMath(key, value string, item metav1.ObjectMeta) bool {
switch key {
case Name:
if !strings.Contains(item.Name, value) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], value) {
return false
}
case Label:
if !FuzzyMatch(item.Labels, "", value) {
return false
}
case Annotation:
if !FuzzyMatch(item.Annotations, "", value) {
return false
}
return false
case App:
if !strings.Contains(item.Labels[Chart], value) && !strings.Contains(item.Labels[Release], value) {
return false
}
case Owner:
for _, ownerReference := range item.OwnerReferences {
if strings.Compare(string(ownerReference.UID), value) == 0 {
return true
}
}
return false
default:
if !FuzzyMatch(item.Labels, key, value) {
return false
}
}
return true
}
func FuzzyMatch(m map[string]string, key, value string) bool {
val, exist := m[key]
......@@ -78,3 +136,17 @@ func SearchFuzzy(m map[string]string, key, value string) bool {
return false
}
func ObjectMetaCompare(left, right metav1.ObjectMeta, compareField string) bool {
switch compareField {
case CreateTime:
if left.CreationTimestamp.Equal(&right.CreationTimestamp) {
return strings.Compare(left.Name, right.Name) <= 0
}
return left.CreationTimestamp.Time.Before(right.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(left.Name, right.Name) <= 0
}
}
......@@ -19,14 +19,11 @@ package job
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"time"
batchv1 "k8s.io/api/batch/v1"
......@@ -64,7 +61,6 @@ func jobStatus(item *batchv1.Job) string {
return status
}
// Exactly Match
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
for k, v := range match {
switch k {
......@@ -80,18 +76,8 @@ func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
if v == "false" && k8sutil.IsControlledBy(item.OwnerReferences, s2iRunKind, "") {
return false
}
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -100,33 +86,11 @@ func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
}
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
......@@ -143,16 +107,12 @@ func jobUpdateTime(item *batchv1.Job) time.Time {
return updateTime
}
func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
func (*jobSearcher) compare(left, right *batchv1.Job, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.UpdateTime:
return jobUpdateTime(a).Before(jobUpdateTime(b))
case v1alpha2.Name:
fallthrough
return jobUpdateTime(left).Before(jobUpdateTime(right))
default:
return strings.Compare(a.Name, b.Name) <= 0
return v1alpha2.ObjectMetaCompare(left.ObjectMeta, right.ObjectMeta, orderBy)
}
}
......@@ -176,9 +136,7 @@ func (s *jobSearcher) Search(namespace string, conditions *params.Conditions, or
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
})
......
......@@ -19,16 +19,12 @@ package namespace
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type namespaceSearcher struct {
......@@ -43,66 +39,24 @@ func (s *namespaceSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Core().V1().Namespaces().Lister().Get(name)
}
// exactly Match
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *namespaceSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
namespaces, err := s.informers.Core().V1().Namespaces().Lister().List(labels.Everything())
......@@ -123,11 +77,9 @@ func (s *namespaceSearcher) Search(namespace string, conditions *params.Conditio
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -20,16 +20,12 @@ package node
import (
"fmt"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
const (
......@@ -80,15 +76,9 @@ func isUnhealthyStatus(condition v1.NodeCondition) bool {
return false
}
// exactly Match
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Role:
labelKey := fmt.Sprintf("node-role.kubernetes.io/%s", v)
if _, ok := item.Labels[labelKey]; !ok {
......@@ -98,13 +88,8 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
if getNodeStatus(item) != v {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -112,43 +97,15 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
return true
}
// Fuzzy searchInNamespace
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *nodeSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
nodes, err := s.informers.Core().V1().Nodes().Lister().List(labels.Everything())
......@@ -169,11 +126,9 @@ func (s *nodeSearcher) Search(namespace string, conditions *params.Conditions, o
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -19,7 +19,6 @@ package persistentvolumeclaim
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"strconv"
......@@ -60,15 +59,9 @@ func pvcStatus(item *v1.PersistentVolumeClaim) string {
return status
}
// exactly Match
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Status:
statuses := strings.Split(v, "|")
if !sliceutil.HasString(statuses, pvcStatus(item)) {
......@@ -78,13 +71,8 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
if item.Spec.StorageClassName == nil || *item.Spec.StorageClassName != v {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -92,47 +80,15 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
return true
}
// Fuzzy searchInNamespace
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *persistentVolumeClaimSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
persistentVolumeClaims, err := s.informers.Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).List(labels.Everything())
......@@ -153,11 +109,9 @@ func (s *persistentVolumeClaimSearcher) Search(namespace string, conditions *par
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -20,16 +20,12 @@ package pod
import (
appsv1 "k8s.io/api/apps/v1"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type podSearcher struct {
......@@ -153,7 +149,6 @@ func (s *podSearcher) podBelongToService(item *v1.Pod, serviceName string) bool
return true
}
// exactly Match
func (s *podSearcher) match(match map[string]string, item *v1.Pod) bool {
for k, v := range match {
switch k {
......@@ -177,18 +172,8 @@ func (s *podSearcher) match(match map[string]string, item *v1.Pod) bool {
if !s.podBelongToService(item, v) {
return false
}
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -196,52 +181,27 @@ func (s *podSearcher) match(match map[string]string, item *v1.Pod) bool {
return true
}
// Fuzzy searchInNamespace
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
func (*podSearcher) compare(left, right *v1.Pod, orderBy string) bool {
switch orderBy {
case v1alpha2.StartTime:
if a.Status.StartTime == nil {
if left.Status.StartTime == nil {
return false
}
if b.Status.StartTime == nil {
if right.Status.StartTime == nil {
return true
}
return a.Status.StartTime.Before(b.Status.StartTime)
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
return left.Status.StartTime.Before(right.Status.StartTime)
default:
return strings.Compare(a.Name, b.Name) <= 0
return v1alpha2.ObjectMetaCompare(left.ObjectMeta, right.ObjectMeta, orderBy)
}
}
......@@ -266,9 +226,7 @@ func (s *podSearcher) Search(namespace string, conditions *params.Conditions, or
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
})
......
/*
*
* Copyright 2020 The KubeSphere Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
package resource
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"
fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"testing"
)
func TestConditions(t *testing.T) {
factory, err := prepare()
if err != nil {
t.Fatal(err)
}
resource := NewResourceGetter(factory)
tests := []struct {
Name string
Namespace string
Resource string
Conditions *params.Conditions
OrderBy string
Reverse bool
Limit int
Offset int
ExpectResponse *models.PageableResponse
ExpectError error
}{{
Name: "list namespace order by name asc",
Namespace: "",
Resource: "namespaces",
Conditions: &params.Conditions{},
OrderBy: "name",
Reverse: false,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{defaultNamespace, kubesphereNamespace},
TotalCount: 2,
},
ExpectError: nil,
}, {
Name: "list namespace order by name desc",
Namespace: "",
Resource: "namespaces",
Conditions: &params.Conditions{},
OrderBy: "name",
Reverse: true,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{kubesphereNamespace, defaultNamespace},
TotalCount: 2,
},
ExpectError: nil,
},
{
Name: "list deployment",
Namespace: "default",
Resource: "deployments",
Conditions: &params.Conditions{},
OrderBy: "name",
Reverse: false,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{nginxDeployment, redisDeployment},
TotalCount: 2,
},
ExpectError: nil,
},
{
Name: "filter deployment by keyword",
Namespace: "default",
Resource: "deployments",
Conditions: &params.Conditions{
Match: map[string]string{v1alpha2.Keyword: "ngin"},
Fuzzy: nil,
},
OrderBy: "name",
Reverse: true,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{nginxDeployment},
TotalCount: 1,
},
ExpectError: nil,
},
{
Name: "filter deployment by label",
Namespace: "default",
Resource: "deployments",
Conditions: &params.Conditions{
Match: map[string]string{"kubesphere.io/creator": "admin"},
Fuzzy: nil,
},
OrderBy: "",
Reverse: true,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{redisDeployment},
TotalCount: 1,
},
ExpectError: nil,
}, {
Name: "filter deployment by status",
Namespace: "default",
Resource: "deployments",
Conditions: &params.Conditions{
Match: map[string]string{v1alpha2.Status: v1alpha2.StatusRunning},
Fuzzy: nil,
},
OrderBy: "",
Reverse: true,
Limit: 10,
Offset: 0,
ExpectResponse: &models.PageableResponse{
Items: []interface{}{nginxDeployment},
TotalCount: 1,
},
ExpectError: nil,
},
}
for _, test := range tests {
response, err := resource.ListResources(test.Namespace, test.Resource, test.Conditions, test.OrderBy, test.Reverse, test.Limit, test.Offset)
if err != test.ExpectError {
t.Fatalf("expected error: %s, got: %s", test.ExpectError, err)
}
if diff := cmp.Diff(test.ExpectResponse, response); diff != "" {
t.Errorf(diff)
}
}
}
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"},
},
}
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,
},
}
)
func prepare() (informers.InformerFactory, error) {
namespaces := []interface{}{defaultNamespace, kubesphereNamespace}
deployments := []interface{}{nginxDeployment, redisDeployment}
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
}
}
return fakeInformerFactory, nil
}
......@@ -28,6 +28,7 @@ import (
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/configmap"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/cronjob"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/daemonset"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/deployment"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/hpa"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/ingress"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/job"
......@@ -62,11 +63,10 @@ func (r ResourceGetter) Add(resource string, getter v1alpha2.Interface) {
func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
resourceGetters := make(map[string]v1alpha2.Interface)
//resourceGetters[v1alpha2.Deployments] = deployments
resourceGetters[v1alpha2.ConfigMaps] = configmap.NewConfigmapSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.CronJobs] = cronjob.NewCronJobSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.DaemonSets] = daemonset.NewDaemonSetSearcher(factory.KubernetesSharedInformerFactory())
// resourceGetters[Deployments] =
resourceGetters[v1alpha2.Deployments] = deployment.NewDeploymentSetSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Ingresses] = ingress.NewIngressSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Jobs] = job.NewJobSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.PersistentVolumeClaims] = persistentvolumeclaim.NewPersistentVolumeClaimSearcher(factory.KubernetesSharedInformerFactory())
......@@ -75,18 +75,16 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
resourceGetters[v1alpha2.StatefulSets] = statefulset.NewStatefulSetSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Pods] = pod.NewPodSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Roles] = role.NewRoleSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Nodes] = node.NewNodeSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.Namespaces] = namespace.NewNamespaceSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.ClusterRoles] = clusterrole.NewClusterRoleSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.HorizontalPodAutoscalers] = hpa.NewHpaSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilders] = s2ibuilder.NewS2iBuilderSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.S2iRuns] = s2irun.NewS2iRunSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilderTemplates] = s2buildertemplate.NewS2iBuidlerTemplateSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.Workspaces] = workspace.NewWorkspaceSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.Applications] = application.NewApplicationSearcher(factory.ApplicationSharedInformerFactory())
return &ResourceGetter{resourcesGetters: resourceGetters}
......
......@@ -22,13 +22,10 @@ import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type roleSearcher struct {
......@@ -43,19 +40,9 @@ func (s *roleSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Rbac().V1().Roles().Lister().Roles(namespace).Get(name)
}
// exactly Match
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
case v1alpha2.UserFacing:
if v == "true" {
if !isUserFacingRole(item) {
......@@ -63,8 +50,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
}
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -72,43 +58,15 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
return true
}
// Fuzzy searchInNamespace
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *roleSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
roles, err := s.informers.Rbac().V1().Roles().Lister().Roles(namespace).List(labels.Everything())
......@@ -129,11 +87,9 @@ func (s *roleSearcher) Search(namespace string, conditions *params.Conditions, o
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -20,15 +20,11 @@ package s2buildertemplate
import (
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type s2iBuilderTemplateSearcher struct {
......@@ -43,66 +39,24 @@ func (s *s2iBuilderTemplateSearcher) Get(namespace, name string) (interface{}, e
return s.informers.Devops().V1alpha1().S2iBuilderTemplates().Lister().Get(name)
}
// exactly Match
func (*s2iBuilderTemplateSearcher) match(match map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*s2iBuilderTemplateSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iBuilderTemplateSearcher) compare(a, b *v1alpha1.S2iBuilderTemplate, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *s2iBuilderTemplateSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
builderTemplates, err := s.informers.Devops().V1alpha1().S2iBuilderTemplates().Lister().List(labels.Everything())
......@@ -123,11 +77,9 @@ func (s *s2iBuilderTemplateSearcher) Search(namespace string, conditions *params
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -22,13 +22,10 @@ import (
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
)
type s2iBuilderSearcher struct {
......@@ -43,66 +40,24 @@ func (s *s2iBuilderSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Devops().V1alpha1().S2iBuilders().Lister().S2iBuilders(namespace).Get(name)
}
// exactly Match
func (*s2iBuilderSearcher) match(match map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*s2iBuilderSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iBuilderSearcher) compare(a, b *v1alpha1.S2iBuilder, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *s2iBuilderSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
s2iBuilders, err := s.informers.Devops().V1alpha1().S2iBuilders().Lister().S2iBuilders(namespace).List(labels.Everything())
......@@ -123,11 +78,9 @@ func (s *s2iBuilderSearcher) Search(namespace string, conditions *params.Conditi
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -22,12 +22,9 @@ import (
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
)
type s2iRunSearcher struct {
......@@ -42,26 +39,15 @@ func (s *s2iRunSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Devops().V1alpha1().S2iRuns().Lister().S2iRuns(namespace).Get(name)
}
// exactly Match
func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Status:
if string(item.Status.RunState) != v {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -69,43 +55,15 @@ func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) boo
return true
}
// Fuzzy searchInNamespace
func (*s2iRunSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iRunSearcher) compare(a, b *v1alpha1.S2iRun, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *s2iRunSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
s2iRuns, err := s.informers.Devops().V1alpha1().S2iRuns().Lister().S2iRuns(namespace).List(labels.Everything())
......@@ -126,11 +84,9 @@ func (s *s2iRunSearcher) Search(namespace string, conditions *params.Conditions,
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -19,16 +19,12 @@ package secret
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type secretSearcher struct {
......@@ -43,26 +39,15 @@ func (s *secretSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Core().V1().Secrets().Lister().Secrets(namespace).Get(name)
}
// exactly Match
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case "type":
if string(item.Type) != v {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -70,47 +55,15 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
return true
}
// Fuzzy searchInNamespace
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *secretSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
secrets, err := s.informers.Core().V1().Secrets().Lister().Secrets(namespace).List(labels.Everything())
......@@ -131,11 +84,9 @@ func (s *secretSearcher) Search(namespace string, conditions *params.Conditions,
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -19,16 +19,12 @@ package service
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type serviceSearcher struct {
......@@ -43,70 +39,24 @@ func (s *serviceSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Core().V1().Services().Lister().Services(namespace).Get(name)
}
// exactly Match
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *serviceSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
services, err := s.informers.Core().V1().Services().Lister().Services(namespace).List(labels.Everything())
......@@ -127,11 +77,9 @@ func (s *serviceSearcher) Search(namespace string, conditions *params.Conditions
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -19,16 +19,12 @@ package statefulset
import (
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type statefulSetSearcher struct {
......@@ -56,26 +52,15 @@ func statefulSetStatus(item *v1.StatefulSet) string {
return v1alpha2.StatusStopped
}
// Exactly Match
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
case v1alpha2.Status:
if statefulSetStatus(item) != v {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
......@@ -84,47 +69,14 @@ func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet)
}
func (*statefulSetSearcher) fuzzy(fuzzy map[string]string, item *v1.StatefulSet) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
case v1alpha2.App:
if !strings.Contains(item.Labels[v1alpha2.Chart], v) && !strings.Contains(item.Labels[v1alpha2.Release], v) {
return false
}
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *statefulSetSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
statefulSets, err := s.informers.Apps().V1().StatefulSets().Lister().StatefulSets(namespace).List(labels.Everything())
......@@ -145,11 +97,9 @@ func (s *statefulSetSearcher) Search(namespace string, conditions *params.Condit
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -19,16 +19,12 @@ package storageclass
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels"
)
type storageClassesSearcher struct {
......@@ -43,66 +39,24 @@ func (s *storageClassesSearcher) Get(namespace, name string) (interface{}, error
return s.informers.Storage().V1().StorageClasses().Lister().Get(name)
}
// exactly Match
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *storageClassesSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
storageClasses, err := s.informers.Storage().V1().StorageClasses().Lister().List(labels.Everything())
......@@ -125,7 +79,7 @@ func (s *storageClassesSearcher) Search(namespace string, conditions *params.Con
if reverse {
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
......@@ -20,15 +20,11 @@ package workspace
import (
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type workspaceSearcher struct {
......@@ -43,66 +39,24 @@ func (s *workspaceSearcher) Get(namespace, name string) (interface{}, error) {
return s.informers.Tenant().V1alpha1().Workspaces().Lister().Get(name)
}
// exactly Match
func (*workspaceSearcher) match(match map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range match {
switch k {
case v1alpha2.Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case v1alpha2.Keyword:
if !strings.Contains(item.Name, v) && !v1alpha2.SearchFuzzy(item.Labels, "", v) && !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
if !v1alpha2.ObjectMetaExactlyMath(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range fuzzy {
switch k {
case v1alpha2.Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case v1alpha2.Label:
if !v1alpha2.SearchFuzzy(item.Labels, "", v) {
return false
}
case v1alpha2.Annotation:
if !v1alpha2.SearchFuzzy(item.Annotations, "", v) {
return false
}
if !v1alpha2.ObjectMetaFuzzyMath(k, v, item.ObjectMeta) {
return false
default:
if !v1alpha2.SearchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*workspaceSearcher) compare(a, b *tenantv1alpha1.Workspace, orderBy string) bool {
switch orderBy {
case v1alpha2.CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case v1alpha2.Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}
func (s *workspaceSearcher) Search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
workspaces, err := s.informers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
......@@ -124,11 +78,9 @@ func (s *workspaceSearcher) Search(namespace string, conditions *params.Conditio
}
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
return v1alpha2.ObjectMetaCompare(result[i].ObjectMeta, result[j].ObjectMeta, orderBy)
})
r := make([]interface{}, 0)
......
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package application
import (
appv1beta1 "github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
"github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type applicationsGetter struct {
informer externalversions.SharedInformerFactory
}
func New(sharedInformers externalversions.SharedInformerFactory) v1alpha3.Interface {
return &applicationsGetter{informer: sharedInformers}
}
func (d *applicationsGetter) Get(namespace, name string) (runtime.Object, error) {
return d.informer.App().V1beta1().Applications().Lister().Applications(namespace).Get(name)
}
func (d *applicationsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := d.informer.App().V1beta1().Applications().Lister().Applications(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, app := range all {
result = append(result, app)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *applicationsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftApplication, ok := left.(*appv1beta1.Application)
if !ok {
return false
}
rightApplication, ok := right.(*appv1beta1.Application)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftApplication.ObjectMeta, rightApplication.ObjectMeta, field)
}
func (d *applicationsGetter) filter(object runtime.Object, filter query.Filter) bool {
application, ok := object.(*appv1beta1.Application)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(application.ObjectMeta, filter)
}
package application
import (
"github.com/google/go-cmp/cmp"
appv1beta1 "github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
"github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
"github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"testing"
)
func applicationsToRuntimeObjects(applications ...*appv1beta1.Application) []runtime.Object {
var objs []runtime.Object
for _, app := range applications {
objs = append(objs, app)
}
return objs
}
func TestListApplications(t *testing.T) {
tests := []struct {
description string
namespace string
deployments []*appv1beta1.Application
query *query.Query
expected api.ListResult
expectedErr error
}{
{
"test name filter",
"bar2",
[]*appv1beta1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo-1",
Namespace: "bar",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo-2",
Namespace: "bar",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "bar-2",
Namespace: "bar2",
},
},
},
&query.Query{
Pagination: &query.Pagination{
Limit: 10,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: []query.Filter{
{
Field: query.FieldNamespace,
Value: query.Value("bar2"),
},
},
},
api.ListResult{
Items: []interface{}{
&appv1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "bar-2",
Namespace: "bar2",
},
},
},
TotalItems: 2,
},
nil,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
objs := applicationsToRuntimeObjects(test.deployments...)
client := fake.NewSimpleClientset(objs...)
informer := externalversions.NewSharedInformerFactory(client, 0)
for _, deployment := range test.deployments {
informer.App().V1beta1().Applications().Informer().GetIndexer().Add(deployment)
}
getter := New(informer)
got, err := getter.List(test.namespace, test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got.Items, test.expected.Items); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package configmap
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type configmapsGetter struct {
informer informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &configmapsGetter{informer: sharedInformers}
}
func (d *configmapsGetter) Get(namespace, name string) (runtime.Object, error) {
return d.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).Get(name)
}
func (d *configmapsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := d.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, app := range all {
result = append(result, app)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *configmapsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftConfigMap, ok := left.(*corev1.ConfigMap)
if !ok {
return false
}
rightConfigMap, ok := right.(*corev1.ConfigMap)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftConfigMap.ObjectMeta, rightConfigMap.ObjectMeta, field)
}
func (d *configmapsGetter) filter(object runtime.Object, filter query.Filter) bool {
configMap, ok := object.(*corev1.ConfigMap)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(configMap.ObjectMeta, filter)
}
package configmap
import (
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListConfigMaps(t *testing.T) {
tests := []struct {
description string
namespace string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
"default",
&query.Query{
Pagination: &query.Pagination{
Limit: 10,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: []query.Filter{
{
Field: query.FieldNamespace,
Value: query.Value("default"),
},
},
},
&api.ListResult{
Items: []interface{}{foo3, foo2, foo1},
TotalItems: len(configmaps),
},
nil,
},
}
getter := prepare()
for _, test := range tests {
got, err := getter.List(test.namespace, test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
}
}
var (
foo1 = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "default",
},
}
foo2 = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "default",
},
}
foo3 = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "foo3",
Namespace: "default",
},
}
configmaps = []interface{}{foo1, foo2, foo3}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, configmap := range configmaps {
informer.Core().V1().ConfigMaps().Informer().GetIndexer().Add(configmap)
}
return New(informer)
}
package deployment
import (
"fmt"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/apps/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
"time"
)
func newDeployments(total int, name, namespace, application string) []*v1.Deployment {
var deployments []*v1.Deployment
for i := 0; i < total; i++ {
deploy := &v1.Deployment{
TypeMeta: metaV1.TypeMeta{
Kind: "Deployment",
APIVersion: "v1",
},
ObjectMeta: metaV1.ObjectMeta{
Name: fmt.Sprintf("%s-%d", name, i),
Namespace: namespace,
Labels: map[string]string{
"seq": fmt.Sprintf("seq-%d", i),
},
Annotations: map[string]string{},
CreationTimestamp: metaV1.Time{Time: time.Now().Add(time.Duration(i*5) * time.Second)},
},
Status: v1.DeploymentStatus{
ReadyReplicas: int32(i + 1),
Replicas: int32(i + 1),
AvailableReplicas: int32(i + 1),
Conditions: []v1.DeploymentCondition{
{
Type: v1.DeploymentAvailable,
LastUpdateTime: metaV1.Time{Time: time.Now().Add(time.Duration(i*5) * time.Second)},
},
},
},
}
deployments = append(deployments, deploy)
}
return deployments
}
func deploymentsToRuntimeObjects(deployments ...*v1.Deployment) []runtime.Object {
var objs []runtime.Object
for _, deploy := range deployments {
objs = append(objs, deploy)
}
return objs
}
func TestListDeployments(t *testing.T) {
tests := []struct {
description string
namespace string
deployments []*v1.Deployment
query *query.Query
expected api.ListResult
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
"bar",
[]*v1.Deployment{
{
ObjectMeta: metaV1.ObjectMeta{
Name: "foo-1",
Namespace: "bar",
},
},
{
ObjectMeta: metaV1.ObjectMeta{
Name: "foo-2",
Namespace: "bar",
},
},
{
ObjectMeta: metaV1.ObjectMeta{
Name: "bar-1",
Namespace: "bar",
},
},
},
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: []query.Filter{
{
Field: query.FieldName,
Value: query.Value("foo"),
Value: query.Value("foo2"),
},
},
},
api.ListResult{
&api.ListResult{
Items: []interface{}{
&v1.Deployment{
ObjectMeta: metaV1.ObjectMeta{
Name: "foo-2",
Namespace: "bar",
},
},
foo2,
},
TotalItems: 2,
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
objs := deploymentsToRuntimeObjects(test.deployments...)
client := fake.NewSimpleClientset(objs...)
informer := informers.NewSharedInformerFactory(client, 0)
for _, deployment := range test.deployments {
informer.Apps().V1().Deployments().Informer().GetIndexer().Add(deployment)
}
getter := New(informer)
got, err := getter.List(test.namespace, test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got.Items, test.expected.Items); diff != "" {
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
deployments = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, deployment := range deployments {
informer.Apps().V1().Deployments().Informer().GetIndexer().Add(deployment)
}
return New(informer)
}
......@@ -17,6 +17,7 @@ type Interface interface {
List(namespace string, query *query.Query) (*api.ListResult, error)
}
// CompareFunc return true is left great than right
type CompareFunc func(runtime.Object, runtime.Object, query.Field) bool
type FilterFunc func(runtime.Object, query.Filter) bool
......@@ -41,9 +42,9 @@ func DefaultList(objects []runtime.Object, query *query.Query, compareFunc Compa
// sort by sortBy field
sort.Slice(filtered, func(i, j int) bool {
if !query.Ascending {
return !compareFunc(filtered[i], filtered[j], query.SortBy)
return compareFunc(filtered[i], filtered[j], query.SortBy)
}
return compareFunc(filtered[i], filtered[j], query.SortBy)
return !compareFunc(filtered[i], filtered[j], query.SortBy)
})
total := len(filtered)
......@@ -55,6 +56,7 @@ func DefaultList(objects []runtime.Object, query *query.Query, compareFunc Compa
}
}
// DefaultObjectMetaCompare return true is left great than right
func DefaultObjectMetaCompare(left, right metav1.ObjectMeta, sortBy query.Field) bool {
switch sortBy {
// ?sortBy=name
......@@ -62,6 +64,10 @@ func DefaultObjectMetaCompare(left, right metav1.ObjectMeta, sortBy query.Field)
return strings.Compare(left.Name, right.Name) > 0
// ?sortBy=creationTimestamp
case query.FieldCreationTimeStamp:
// compare by name if creation timestamp is equal
if left.CreationTimestamp.Equal(&right.CreationTimestamp) {
return strings.Compare(left.Name, right.Name) > 0
}
return left.CreationTimestamp.After(right.CreationTimestamp.Time)
default:
return false
......
......@@ -7,6 +7,7 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/application"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/deployment"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/namespace"
)
......@@ -17,11 +18,12 @@ type ResourceGetter struct {
getters map[schema.GroupVersionResource]v1alpha3.Interface
}
func New(factory informers.InformerFactory) *ResourceGetter {
func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
getters := make(map[schema.GroupVersionResource]v1alpha3.Interface)
getters[schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}] = deployment.New(factory.KubernetesSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"}] = namespace.New(factory.KubernetesSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "app.k8s.io", Version: "v1beta1", Resource: "applications"}] = application.New(factory.ApplicationSharedInformerFactory())
return &ResourceGetter{
getters: getters,
......
......@@ -22,8 +22,8 @@ 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"
v1 "k8s.io/api/core/v1"
corev1 "k8s.io/apimachinery/pkg/apis/meta/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"
......@@ -34,37 +34,7 @@ import (
func TestResourceGetter(t *testing.T) {
namespaces := make([]interface{}, 0)
defaultNamespace := &v1.Namespace{
ObjectMeta: corev1.ObjectMeta{
Name: "default",
Labels: map[string]string{"kubesphere.io/workspace": "system-workspace"},
},
}
kubesphereNamespace := &v1.Namespace{
ObjectMeta: corev1.ObjectMeta{
Name: "kubesphere-system",
Labels: map[string]string{"kubesphere.io/workspace": "system-workspace"},
},
}
namespaces = append(namespaces, defaultNamespace, kubesphereNamespace)
ksClient := fakeks.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset(defaultNamespace, kubesphereNamespace)
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 {
t.Fatal(err)
}
}
resource := New(fakeInformerFactory)
resource := prepare()
tests := []struct {
Name string
......@@ -89,8 +59,8 @@ func TestResourceGetter(t *testing.T) {
},
ExpectError: nil,
ExpectResponse: &api.ListResult{
Items: namespaces,
TotalItems: 2,
Items: []interface{}{foo2, foo1, bar1},
TotalItems: 3,
},
},
}
......@@ -99,7 +69,6 @@ func TestResourceGetter(t *testing.T) {
result, err := resource.List(test.Resource, test.Namespace, test.Query)
t.Logf("%+v", result)
if err != test.ExpectError {
t.Errorf("expected error: %s, got: %s", test.ExpectError, err)
}
......@@ -107,5 +76,44 @@ func TestResourceGetter(t *testing.T) {
t.Errorf(diff)
}
}
}
var (
foo1 = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
namespaces = []interface{}{foo1, foo2, bar1}
)
func prepare() *ResourceGetter {
ksClient := fakeks.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
istioClient := fakeistio.NewSimpleClientset()
appClient := fakeapp.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
for _, namespace := range namespaces {
fakeInformerFactory.KubernetesSharedInformerFactory().Core().V1().
Namespaces().Informer().GetIndexer().Add(namespace)
}
return NewResourceGetter(fakeInformerFactory)
}
......@@ -21,63 +21,91 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
)
type Interface interface {
ListWorkspaces(username string) (*api.ListResult, error)
ListNamespaces(username, workspace string) (*api.ListResult, error)
ListWorkspaces(user user.Info) (*api.ListResult, error)
ListNamespaces(user user.Info, workspace string) (*api.ListResult, error)
}
type tenantOperator struct {
informers informers.InformerFactory
am am.AccessManagementInterface
informers informers.InformerFactory
am am.AccessManagementInterface
authorizer authorizer.Authorizer
}
func New(k8sClient k8s.Client, informers informers.InformerFactory) Interface {
amOperator := am.NewAMOperator(k8sClient.KubeSphere(), informers.KubeSphereSharedInformerFactory())
opaAuthorizer := authorizerfactory.NewOPAAuthorizer(amOperator)
return &tenantOperator{
informers: informers,
am: am.NewAMOperator(k8sClient.KubeSphere(), informers.KubeSphereSharedInformerFactory()),
informers: informers,
am: amOperator,
authorizer: opaAuthorizer,
}
}
func (t *tenantOperator) ListWorkspaces(username string) (*api.ListResult, error) {
func (t *tenantOperator) ListWorkspaces(user user.Info) (*api.ListResult, error) {
workspaces := make([]*tenantv1alpha1.Workspace, 0)
listWS := authorizer.AttributesRecord{
User: user,
Verb: "list",
APIGroup: "tenant.kubesphere.io",
APIVersion: "v1alpha2",
Resource: "workspaces",
}
decision, _, err := t.authorizer.Authorize(listWS)
workspaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.WorkspaceScope, username)
if err != nil {
klog.Error(err)
return nil, err
}
workspaces := make([]*tenantv1alpha1.Workspace, 0)
for _, role := range workspaceRoles {
// all workspaces are allowed
if role.Target.Name == iamv1alpha2.TargetAll {
workspaces, err = t.informers.KubeSphereSharedInformerFactory().
Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
break
}
workspace, err := t.informers.KubeSphereSharedInformerFactory().
Tenant().V1alpha1().Workspaces().Lister().Get(role.Target.Name)
if decision == authorizer.DecisionAllow {
workspaces, err = t.informers.KubeSphereSharedInformerFactory().
Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
if errors.IsNotFound(err) {
klog.Warningf("workspace role: %s found but workspace not exist", role.Target)
continue
if err != nil {
klog.Error(err)
return nil, err
}
} else {
workspaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.WorkspaceScope, user.GetName())
if err != nil {
klog.Error(err)
return nil, err
}
if !containsWorkspace(workspaces, workspace) {
workspaces = append(workspaces, workspace)
for _, role := range workspaceRoles {
workspace, err := t.informers.KubeSphereSharedInformerFactory().
Tenant().V1alpha1().Workspaces().Lister().Get(role.Target.Name)
if errors.IsNotFound(err) {
klog.Warningf("workspace role: %s found but workspace not exist", role.Target)
continue
}
if err != nil {
klog.Error(err)
return nil, err
}
if !containsWorkspace(workspaces, workspace) {
workspaces = append(workspaces, workspace)
}
}
}
......@@ -87,39 +115,59 @@ func (t *tenantOperator) ListWorkspaces(username string) (*api.ListResult, error
}, nil
}
func (t *tenantOperator) ListNamespaces(username, workspace string) (*api.ListResult, error) {
func (t *tenantOperator) ListNamespaces(user user.Info, workspace string) (*api.ListResult, error) {
namespaces := make([]*corev1.Namespace, 0)
listNSInWS := authorizer.AttributesRecord{
User: user,
Verb: "list",
APIGroup: "",
APIVersion: "v1",
Workspace: workspace,
Resource: "namespaces",
}
namespaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.NamespaceScope, username)
decision, _, err := t.authorizer.Authorize(listNSInWS)
if err != nil {
klog.Error(err)
return nil, err
}
namespaces := make([]*corev1.Namespace, 0)
for _, role := range namespaceRoles {
if decision == authorizer.DecisionAllow {
namespaces, err = t.informers.KubernetesSharedInformerFactory().
Core().V1().Namespaces().Lister().List(labels.Everything())
// all workspaces are allowed
if role.Target.Name == iamv1alpha2.TargetAll {
namespaces, err = t.informers.KubernetesSharedInformerFactory().
Core().V1().Namespaces().Lister().List(labels.Everything())
break
if err != nil {
klog.Error(err)
return nil, err
}
} else {
namespaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.NamespaceScope, workspace)
namespace, err := t.informers.KubernetesSharedInformerFactory().
Core().V1().Namespaces().Lister().Get(role.Target.Name)
if errors.IsNotFound(err) {
klog.Warningf("workspace role: %s found but workspace not exist", role.Target)
continue
}
if err != nil {
klog.Error(err)
return nil, err
}
if !containsNamespace(namespaces, namespace) {
namespaces = append(namespaces, namespace)
for _, role := range namespaceRoles {
namespace, err := t.informers.KubernetesSharedInformerFactory().
Core().V1().Namespaces().Lister().Get(role.Target.Name)
if errors.IsNotFound(err) {
klog.Warningf("workspace role: %s found but workspace not exist", role.Target)
continue
}
if err != nil {
klog.Error(err)
return nil, err
}
if !containsNamespace(namespaces, namespace) {
namespaces = append(namespaces, namespace)
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册