fix: cluster list granted to users is incorrect

This commit is contained in:
hongming
2022-05-20 17:12:55 +08:00
parent 32ac94a7e5
commit 382be8b16b
11 changed files with 176 additions and 142 deletions

View File

@@ -488,9 +488,10 @@ func addAllControllers(mgr manager.Manager, client k8s.Client, informerFactory i
if cmOptions.MultiClusterOptions.Enable { if cmOptions.MultiClusterOptions.Enable {
clusterController := cluster.NewClusterController( clusterController := cluster.NewClusterController(
client.Kubernetes(), client.Kubernetes(),
client.KubeSphere(),
client.Config(), client.Config(),
kubesphereInformer.Cluster().V1alpha1().Clusters(), kubesphereInformer.Cluster().V1alpha1().Clusters(),
client.KubeSphere().ClusterV1alpha1().Clusters(), kubesphereInformer.Iam().V1alpha2().Users().Lister(),
cmOptions.MultiClusterOptions.ClusterControllerResyncPeriod, cmOptions.MultiClusterOptions.ClusterControllerResyncPeriod,
cmOptions.MultiClusterOptions.HostClusterName, cmOptions.MultiClusterOptions.HostClusterName,
) )

View File

@@ -26,31 +26,25 @@ import (
"sync" "sync"
"time" "time"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/utils/clusterclient"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/discovery"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/util/retry"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
urlruntime "k8s.io/apimachinery/pkg/util/runtime" urlruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
unionauth "k8s.io/apiserver/pkg/authentication/request/union" unionauth "k8s.io/apiserver/pkg/authentication/request/union"
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
"k8s.io/client-go/discovery"
"k8s.io/client-go/util/retry"
"k8s.io/klog" "k8s.io/klog"
runtimecache "sigs.k8s.io/controller-runtime/pkg/cache"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1" clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1"
iamv1alpha2 "kubesphere.io/api/iam/v1alpha2" iamv1alpha2 "kubesphere.io/api/iam/v1alpha2"
notificationv2beta1 "kubesphere.io/api/notification/v2beta1" notificationv2beta1 "kubesphere.io/api/notification/v2beta1"
tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1" tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1"
typesv1beta1 "kubesphere.io/api/types/v1beta1" typesv1beta1 "kubesphere.io/api/types/v1beta1"
runtimecache "sigs.k8s.io/controller-runtime/pkg/cache"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
audit "kubesphere.io/kubesphere/pkg/apiserver/auditing" audit "kubesphere.io/kubesphere/pkg/apiserver/auditing"
"kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/basic" "kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/basic"
@@ -101,6 +95,7 @@ import (
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/group" "kubesphere.io/kubesphere/pkg/models/iam/group"
"kubesphere.io/kubesphere/pkg/models/iam/im" "kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/loginrecord" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/loginrecord"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/user" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/user"
"kubesphere.io/kubesphere/pkg/simple/client/alerting" "kubesphere.io/kubesphere/pkg/simple/client/alerting"
@@ -113,6 +108,7 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/s3" "kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/simple/client/sonarqube" "kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
"kubesphere.io/kubesphere/pkg/utils/clusterclient"
"kubesphere.io/kubesphere/pkg/utils/iputil" "kubesphere.io/kubesphere/pkg/utils/iputil"
"kubesphere.io/kubesphere/pkg/utils/metrics" "kubesphere.io/kubesphere/pkg/utils/metrics"
) )
@@ -238,9 +234,9 @@ func (s *APIServer) installKubeSphereAPIs(stopCh <-chan struct{}) {
urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory, urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory,
s.KubernetesClient.Master())) s.KubernetesClient.Master()))
urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(),
s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, s.OpenpitrixClient)) s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, imOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, s.OpenpitrixClient))
urlruntime.Must(tenantv1alpha3.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), urlruntime.Must(tenantv1alpha3.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(),
s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, s.OpenpitrixClient)) s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, imOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, s.OpenpitrixClient))
urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), rbacAuthorizer, s.KubernetesClient.Config(), s.Config.TerminalOptions)) urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), rbacAuthorizer, s.KubernetesClient.Config(), s.Config.TerminalOptions))
urlruntime.Must(clusterkapisv1alpha1.AddToContainer(s.container, urlruntime.Must(clusterkapisv1alpha1.AddToContainer(s.container,
s.KubernetesClient.KubeSphere(), s.KubernetesClient.KubeSphere(),

View File

@@ -25,6 +25,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"reflect" "reflect"
"strings"
"time" "time"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@@ -48,11 +49,13 @@ import (
fedv1b1 "sigs.k8s.io/kubefed/pkg/apis/core/v1beta1" fedv1b1 "sigs.k8s.io/kubefed/pkg/apis/core/v1beta1"
clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1" clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1"
iamv1alpha2 "kubesphere.io/api/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/config" "kubesphere.io/kubesphere/pkg/apiserver/config"
clusterclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/cluster/v1alpha1" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1" clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1"
clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1" clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1"
iamv1alpha2listers "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/simple/client/multicluster" "kubesphere.io/kubesphere/pkg/simple/client/multicluster"
"kubesphere.io/kubesphere/pkg/utils/k8sutil" "kubesphere.io/kubesphere/pkg/utils/k8sutil"
@@ -126,12 +129,13 @@ type clusterController struct {
eventRecorder record.EventRecorder eventRecorder record.EventRecorder
// build this only for host cluster // build this only for host cluster
client kubernetes.Interface k8sClient kubernetes.Interface
hostConfig *rest.Config hostConfig *rest.Config
clusterClient clusterclient.ClusterInterface ksClient kubesphere.Interface
clusterLister clusterlister.ClusterLister clusterLister clusterlister.ClusterLister
userLister iamv1alpha2listers.UserLister
clusterHasSynced cache.InformerSynced clusterHasSynced cache.InformerSynced
queue workqueue.RateLimitingInterface queue workqueue.RateLimitingInterface
@@ -144,10 +148,11 @@ type clusterController struct {
} }
func NewClusterController( func NewClusterController(
client kubernetes.Interface, k8sClient kubernetes.Interface,
ksClient kubesphere.Interface,
config *rest.Config, config *rest.Config,
clusterInformer clusterinformer.ClusterInformer, clusterInformer clusterinformer.ClusterInformer,
clusterClient clusterclient.ClusterInterface, userLister iamv1alpha2listers.UserLister,
resyncPeriod time.Duration, resyncPeriod time.Duration,
hostClusterName string, hostClusterName string,
) *clusterController { ) *clusterController {
@@ -156,19 +161,20 @@ func NewClusterController(
broadcaster.StartLogging(func(format string, args ...interface{}) { broadcaster.StartLogging(func(format string, args ...interface{}) {
klog.Info(fmt.Sprintf(format, args)) klog.Info(fmt.Sprintf(format, args))
}) })
broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: client.CoreV1().Events("")}) broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: k8sClient.CoreV1().Events("")})
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cluster-controller"}) recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cluster-controller"})
c := &clusterController{ c := &clusterController{
eventBroadcaster: broadcaster, eventBroadcaster: broadcaster,
eventRecorder: recorder, eventRecorder: recorder,
client: client, k8sClient: k8sClient,
ksClient: ksClient,
hostConfig: config, hostConfig: config,
clusterClient: clusterClient,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "cluster"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "cluster"),
workerLoopPeriod: time.Second, workerLoopPeriod: time.Second,
resyncPeriod: resyncPeriod, resyncPeriod: resyncPeriod,
hostClusterName: hostClusterName, hostClusterName: hostClusterName,
userLister: userLister,
} }
c.clusterLister = clusterInformer.Lister() c.clusterLister = clusterInformer.Lister()
c.clusterHasSynced = clusterInformer.Informer().HasSynced c.clusterHasSynced = clusterInformer.Informer().HasSynced
@@ -213,7 +219,7 @@ func (c *clusterController) Run(workers int, stopCh <-chan struct{}) error {
klog.Errorf("Error create host cluster, error %v", err) klog.Errorf("Error create host cluster, error %v", err)
} }
if err := c.probeClusters(); err != nil { if err := c.resyncClusters(); err != nil {
klog.Errorf("failed to reconcile cluster ready status, err: %v", err) klog.Errorf("failed to reconcile cluster ready status, err: %v", err)
} }
}, c.resyncPeriod, stopCh) }, c.resyncPeriod, stopCh)
@@ -256,7 +262,7 @@ func (c *clusterController) reconcileHostCluster() error {
if len(clusters) == 0 { if len(clusters) == 0 {
hostCluster.Spec.Connection.KubeConfig = hostKubeConfig hostCluster.Spec.Connection.KubeConfig = hostKubeConfig
hostCluster.Name = c.hostClusterName hostCluster.Name = c.hostClusterName
_, err = c.clusterClient.Create(context.TODO(), hostCluster, metav1.CreateOptions{}) _, err = c.ksClient.ClusterV1alpha1().Clusters().Create(context.TODO(), hostCluster, metav1.CreateOptions{})
return err return err
} else if len(clusters) > 1 { } else if len(clusters) > 1 {
return fmt.Errorf("there MUST not be more than one host clusters, while there are %d", len(clusters)) return fmt.Errorf("there MUST not be more than one host clusters, while there are %d", len(clusters))
@@ -280,18 +286,20 @@ func (c *clusterController) reconcileHostCluster() error {
} }
// update host cluster config // update host cluster config
_, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}) _, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{})
return err return err
} }
func (c *clusterController) probeClusters() error { func (c *clusterController) resyncClusters() error {
clusters, err := c.clusterLister.List(labels.Everything()) clusters, err := c.clusterLister.List(labels.Everything())
if err != nil { if err != nil {
return err return err
} }
for _, cluster := range clusters { for _, cluster := range clusters {
c.syncCluster(cluster.Name) if err = c.syncCluster(cluster.Name); err != nil {
klog.Warningf("failed to sync cluster %s: %s", cluster.Name, err)
}
} }
return nil return nil
} }
@@ -328,7 +336,7 @@ func (c *clusterController) syncCluster(key string) error {
// registering our finalizer. // registering our finalizer.
if !sets.NewString(cluster.ObjectMeta.Finalizers...).Has(clusterv1alpha1.Finalizer) { if !sets.NewString(cluster.ObjectMeta.Finalizers...).Has(clusterv1alpha1.Finalizer) {
cluster.ObjectMeta.Finalizers = append(cluster.ObjectMeta.Finalizers, clusterv1alpha1.Finalizer) cluster.ObjectMeta.Finalizers = append(cluster.ObjectMeta.Finalizers, clusterv1alpha1.Finalizer)
if cluster, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}); err != nil { if cluster, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{}); err != nil {
return err return err
} }
} }
@@ -338,17 +346,21 @@ func (c *clusterController) syncCluster(key string) error {
// need to unJoin federation first, before there are // need to unJoin federation first, before there are
// some cleanup work to do in member cluster which depends // some cleanup work to do in member cluster which depends
// agent to proxy traffic // agent to proxy traffic
err = c.unJoinFederation(nil, name) if err = c.unJoinFederation(nil, name); err != nil {
if err != nil {
klog.Errorf("Failed to unjoin federation for cluster %s, error %v", name, err) klog.Errorf("Failed to unjoin federation for cluster %s, error %v", name, err)
return err return err
} }
// cleanup after cluster has been deleted
if err := c.syncClusterMembers(nil, cluster); err != nil {
klog.Errorf("Failed to sync cluster members for %s: %v", name, err)
return err
}
// remove our cluster finalizer // remove our cluster finalizer
finalizers := sets.NewString(cluster.ObjectMeta.Finalizers...) finalizers := sets.NewString(cluster.ObjectMeta.Finalizers...)
finalizers.Delete(clusterv1alpha1.Finalizer) finalizers.Delete(clusterv1alpha1.Finalizer)
cluster.ObjectMeta.Finalizers = finalizers.List() cluster.ObjectMeta.Finalizers = finalizers.List()
if _, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}); err != nil { if _, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{}); err != nil {
return err return err
} }
} }
@@ -407,7 +419,7 @@ func (c *clusterController) syncCluster(key string) error {
} }
c.updateClusterCondition(cluster, federationNotReadyCondition) c.updateClusterCondition(cluster, federationNotReadyCondition)
_, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}) _, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{})
if err != nil { if err != nil {
klog.Errorf("Failed to update cluster status, %#v", err) klog.Errorf("Failed to update cluster status, %#v", err)
} }
@@ -496,8 +508,8 @@ func (c *clusterController) syncCluster(key string) error {
return err return err
} }
if !reflect.DeepEqual(oldCluster, cluster) { if !reflect.DeepEqual(oldCluster.Status, cluster.Status) {
_, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}) _, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{})
if err != nil { if err != nil {
klog.Errorf("Failed to update cluster status, %#v", err) klog.Errorf("Failed to update cluster status, %#v", err)
return err return err
@@ -508,6 +520,10 @@ func (c *clusterController) syncCluster(key string) error {
return err return err
} }
if err = c.syncClusterMembers(clusterClient, cluster); err != nil {
return fmt.Errorf("failed to sync cluster membership for %s: %s", cluster.Name, err)
}
return nil return nil
} }
@@ -541,7 +557,7 @@ func (c *clusterController) setClusterNameInConfigMap(client kubernetes.Interfac
} }
func (c *clusterController) checkIfClusterIsHostCluster(memberClusterNodes *v1.NodeList) bool { func (c *clusterController) checkIfClusterIsHostCluster(memberClusterNodes *v1.NodeList) bool {
hostNodes, err := c.client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) hostNodes, err := c.k8sClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
if err != nil { if err != nil {
return false return false
} }
@@ -786,3 +802,55 @@ func (c *clusterController) updateKubeConfigExpirationDateCondition(cluster *clu
}) })
return nil return nil
} }
// syncClusterMembers Sync granted clusters for users periodically
func (c *clusterController) syncClusterMembers(clusterClient *kubernetes.Clientset, cluster *clusterv1alpha1.Cluster) error {
users, err := c.userLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("failed to list users: %s", err)
}
grantedUsers := sets.NewString()
clusterName := cluster.Name
if cluster.DeletionTimestamp.IsZero() {
list, err := clusterClient.RbacV1().ClusterRoleBindings().List(context.Background(),
metav1.ListOptions{LabelSelector: iamv1alpha2.UserReferenceLabel})
if err != nil {
return fmt.Errorf("failed to list clusterrolebindings: %s", err)
}
for _, clusterRoleBinding := range list.Items {
for _, sub := range clusterRoleBinding.Subjects {
if sub.Kind == iamv1alpha2.ResourceKindUser {
grantedUsers.Insert(sub.Name)
}
}
}
}
for _, user := range users {
user = user.DeepCopy()
grantedClustersAnnotation := user.Annotations[iamv1alpha2.GrantedClustersAnnotation]
var grantedClusters sets.String
if len(grantedClustersAnnotation) > 0 {
grantedClusters = sets.NewString(strings.Split(grantedClustersAnnotation, ",")...)
} else {
grantedClusters = sets.NewString()
}
if grantedUsers.Has(user.Name) && !grantedClusters.Has(clusterName) {
grantedClusters.Insert(clusterName)
} else if !grantedUsers.Has(user.Name) && grantedClusters.Has(clusterName) {
grantedClusters.Delete(clusterName)
}
grantedClustersAnnotation = strings.Join(grantedClusters.List(), ",")
if user.Annotations[iamv1alpha2.GrantedClustersAnnotation] != grantedClustersAnnotation {
if user.Annotations == nil {
user.Annotations = make(map[string]string, 0)
}
user.Annotations[iamv1alpha2.GrantedClustersAnnotation] = grantedClustersAnnotation
if _, err := c.ksClient.IamV1alpha2().Users().Update(context.Background(), user, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update user %s: %s", user.Name, err)
}
}
}
return nil
}

View File

@@ -28,8 +28,6 @@ import (
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
quotav1alpha2 "kubesphere.io/api/quota/v1alpha2" quotav1alpha2 "kubesphere.io/api/quota/v1alpha2"
tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2"
@@ -43,6 +41,8 @@ import (
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/models/tenant" "kubesphere.io/kubesphere/pkg/models/tenant"
servererr "kubesphere.io/kubesphere/pkg/server/errors" servererr "kubesphere.io/kubesphere/pkg/server/errors"
@@ -60,7 +60,7 @@ type tenantHandler struct {
func NewTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, func NewTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface,
evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client,
am am.AccessManagementInterface, authorizer authorizer.Authorizer, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter,
meteringOptions *meteringclient.Options, opClient openpitrix.Interface) *tenantHandler { meteringOptions *meteringclient.Options, opClient openpitrix.Interface) *tenantHandler {
@@ -69,7 +69,7 @@ func NewTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.In
} }
return &tenantHandler{ return &tenantHandler{
tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter, opClient), tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, im, authorizer, monitoringclient, resourceGetter, opClient),
meteringOptions: meteringOptions, meteringOptions: meteringOptions,
} }
} }
@@ -557,8 +557,8 @@ func (h *tenantHandler) ListClusters(r *restful.Request, response *restful.Respo
return return
} }
result, err := h.tenant.ListClusters(user) queryParam := query.ParseQueryParameter(r)
result, err := h.tenant.ListClusters(user, queryParam)
if err != nil { if err != nil {
klog.Error(err) klog.Error(err)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {

View File

@@ -19,8 +19,6 @@ package v1alpha2
import ( import (
"net/http" "net/http"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
restfulspec "github.com/emicklei/go-restful-openapi" restfulspec "github.com/emicklei/go-restful-openapi"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
@@ -42,8 +40,10 @@ import (
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/metering" "kubesphere.io/kubesphere/pkg/models/metering"
"kubesphere.io/kubesphere/pkg/models/monitoring" "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/simple/client/auditing" "kubesphere.io/kubesphere/pkg/simple/client/auditing"
@@ -65,12 +65,12 @@ func Resource(resource string) schema.GroupResource {
func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface, func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface,
ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client,
auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, auditingclient auditing.Client, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options, opClient openpitrix.Interface) error { monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options, opClient openpitrix.Interface) error {
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
ws := runtime.NewWebService(GroupVersion) ws := runtime.NewWebService(GroupVersion)
handler := NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient) handler := NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, im, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient)
ws.Route(ws.GET("/clusters"). ws.Route(ws.GET("/clusters").
To(handler.ListClusters). To(handler.ListClusters).

View File

@@ -24,8 +24,6 @@ import (
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"kubesphere.io/kubesphere/pkg/apiserver/query" "kubesphere.io/kubesphere/pkg/apiserver/query"
@@ -33,6 +31,8 @@ import (
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/models/tenant" "kubesphere.io/kubesphere/pkg/models/tenant"
"kubesphere.io/kubesphere/pkg/simple/client/auditing" "kubesphere.io/kubesphere/pkg/simple/client/auditing"
@@ -49,7 +49,7 @@ type tenantHandler struct {
func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface,
evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client,
am am.AccessManagementInterface, authorizer authorizer.Authorizer, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter,
meteringOptions *meteringclient.Options, opClient openpitrix.Interface) *tenantHandler { meteringOptions *meteringclient.Options, opClient openpitrix.Interface) *tenantHandler {
@@ -58,7 +58,7 @@ func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.In
} }
return &tenantHandler{ return &tenantHandler{
tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter, opClient), tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, im, authorizer, monitoringclient, resourceGetter, opClient),
meteringOptions: meteringOptions, meteringOptions: meteringOptions,
} }
} }

View File

@@ -19,8 +19,6 @@ package v1alpha3
import ( import (
"net/http" "net/http"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
restfulspec "github.com/emicklei/go-restful-openapi" restfulspec "github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@@ -39,6 +37,8 @@ import (
"kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2" "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/simple/client/auditing" "kubesphere.io/kubesphere/pkg/simple/client/auditing"
@@ -60,14 +60,13 @@ func Resource(resource string) schema.GroupResource {
func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface, func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface,
ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client,
auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, auditingclient auditing.Client, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options, monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options, opClient openpitrix.Interface) error {
opClient openpitrix.Interface) error {
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
ws := runtime.NewWebService(GroupVersion) ws := runtime.NewWebService(GroupVersion)
v1alpha2Handler := v1alpha2.NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient) v1alpha2Handler := v1alpha2.NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, im, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient)
handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient) handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, im, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, opClient)
ws.Route(ws.POST("/workspacetemplates"). ws.Route(ws.POST("/workspacetemplates").
To(v1alpha2Handler.CreateWorkspaceTemplate). To(v1alpha2Handler.CreateWorkspaceTemplate).

View File

@@ -20,6 +20,9 @@ import (
"sort" "sort"
"strings" "strings"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/klog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@@ -150,33 +153,13 @@ func DefaultObjectMetaFilter(item metav1.ObjectMeta, filter query.Filter) bool {
} }
} }
func labelMatch(labels map[string]string, filter string) bool { func labelMatch(m map[string]string, filter string) bool {
fields := strings.SplitN(filter, "=", 2) labelSelector, err := labels.Parse(filter)
var key, value string if err != nil {
var opposite bool klog.Warningf("invalid labelSelector %s: %s", filter, err)
if len(fields) == 2 { return false
key = fields[0]
if strings.HasSuffix(key, "!") {
key = strings.TrimSuffix(key, "!")
opposite = true
}
value = fields[1]
} else {
key = fields[0]
value = "*"
} }
for k, v := range labels { return labelSelector.Matches(labels.Set(m))
if opposite {
if (k == key) && v != value {
return true
}
} else {
if (k == key) && (value == "*" || v == value) {
return true
}
}
}
return false
} }
func objectsToInterfaces(objs []runtime.Object) []interface{} { func objectsToInterfaces(objs []runtime.Object) []interface{} {

View File

@@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
@@ -40,6 +41,8 @@ import (
tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2"
typesv1beta1 "kubesphere.io/api/types/v1beta1" typesv1beta1 "kubesphere.io/api/types/v1beta1"
iamv1alpha2 "kubesphere.io/api/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/api"
auditingv1alpha1 "kubesphere.io/kubesphere/pkg/api/auditing/v1alpha1" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/api/auditing/v1alpha1"
eventsv1alpha1 "kubesphere.io/kubesphere/pkg/api/events/v1alpha1" eventsv1alpha1 "kubesphere.io/kubesphere/pkg/api/events/v1alpha1"
@@ -53,6 +56,7 @@ import (
"kubesphere.io/kubesphere/pkg/models/auditing" "kubesphere.io/kubesphere/pkg/models/auditing"
"kubesphere.io/kubesphere/pkg/models/events" "kubesphere.io/kubesphere/pkg/models/events"
"kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/im"
"kubesphere.io/kubesphere/pkg/models/logging" "kubesphere.io/kubesphere/pkg/models/logging"
"kubesphere.io/kubesphere/pkg/models/metering" "kubesphere.io/kubesphere/pkg/models/metering"
"kubesphere.io/kubesphere/pkg/models/monitoring" "kubesphere.io/kubesphere/pkg/models/monitoring"
@@ -92,7 +96,7 @@ type Interface interface {
DeleteNamespace(workspace, namespace string) error DeleteNamespace(workspace, namespace string) error
UpdateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) UpdateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error)
PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error)
ListClusters(info user.Info) (*api.ListResult, error) ListClusters(info user.Info, queryParam *query.Query) (*api.ListResult, error)
Metering(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (monitoring.Metrics, error) Metering(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (monitoring.Metrics, error)
MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metering.ResourceStatistic, error) MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metering.ResourceStatistic, error)
CreateWorkspaceResourceQuota(workspace string, resourceQuota *quotav1alpha2.ResourceQuota) (*quotav1alpha2.ResourceQuota, error) CreateWorkspaceResourceQuota(workspace string, resourceQuota *quotav1alpha2.ResourceQuota) (*quotav1alpha2.ResourceQuota, error)
@@ -103,6 +107,7 @@ type Interface interface {
type tenantOperator struct { type tenantOperator struct {
am am.AccessManagementInterface am am.AccessManagementInterface
im im.IdentityManagementInterface
authorizer authorizer.Authorizer authorizer authorizer.Authorizer
k8sclient kubernetes.Interface k8sclient kubernetes.Interface
ksclient kubesphere.Interface ksclient kubesphere.Interface
@@ -114,9 +119,10 @@ type tenantOperator struct {
opRelease openpitrix.ReleaseInterface opRelease openpitrix.ReleaseInterface
} }
func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient eventsclient.Client, loggingClient loggingclient.Client, auditingclient auditingclient.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, opClient openpitrix.Interface) Interface { func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient eventsclient.Client, loggingClient loggingclient.Client, auditingclient auditingclient.Client, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, opClient openpitrix.Interface) Interface {
return &tenantOperator{ return &tenantOperator{
am: am, am: am,
im: im,
authorizer: authorizer, authorizer: authorizer,
resourceGetter: resourcesv1alpha3.NewResourceGetter(informers, nil), resourceGetter: resourcesv1alpha3.NewResourceGetter(informers, nil),
k8sclient: k8sclient, k8sclient: k8sclient,
@@ -498,7 +504,7 @@ func (t *tenantOperator) ListWorkspaceClusters(workspaceName string) (*api.ListR
for _, cluster := range workspace.Spec.Placement.Clusters { for _, cluster := range workspace.Spec.Placement.Clusters {
obj, err := t.resourceGetter.Get(clusterv1alpha1.ResourcesPluralCluster, "", cluster.Name) obj, err := t.resourceGetter.Get(clusterv1alpha1.ResourcesPluralCluster, "", cluster.Name)
if err != nil { if err != nil {
klog.Error(err) klog.Warning(err)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
continue continue
} }
@@ -527,89 +533,69 @@ func (t *tenantOperator) ListWorkspaceClusters(workspaceName string) (*api.ListR
return &api.ListResult{Items: []interface{}{}, TotalItems: 0}, nil return &api.ListResult{Items: []interface{}{}, TotalItems: 0}, nil
} }
func (t *tenantOperator) ListClusters(user user.Info) (*api.ListResult, error) { func (t *tenantOperator) ListClusters(user user.Info, queryParam *query.Query) (*api.ListResult, error) {
listClustersInGlobalScope := authorizer.AttributesRecord{ listClustersInGlobalScope := authorizer.AttributesRecord{
User: user, User: user,
Verb: "list", Verb: "list",
APIGroup: "cluster.kubesphere.io",
Resource: "clusters", Resource: "clusters",
ResourceScope: request.GlobalScope, ResourceScope: request.GlobalScope,
ResourceRequest: true, ResourceRequest: true,
} }
allowedListClustersInGlobalScope, _, err := t.authorizer.Authorize(listClustersInGlobalScope) allowedListClustersInGlobalScope, _, err := t.authorizer.Authorize(listClustersInGlobalScope)
if err != nil { if err != nil {
klog.Error(err) return nil, fmt.Errorf("failed to authorize: %s", err)
return nil, err
} }
listWorkspacesInGlobalScope := authorizer.AttributesRecord{ if allowedListClustersInGlobalScope == authorizer.DecisionAllow {
User: user, return t.resourceGetter.List(clusterv1alpha1.ResourcesPluralCluster, "", queryParam)
Verb: "list",
Resource: "workspaces",
ResourceScope: request.GlobalScope,
ResourceRequest: true,
} }
allowedListWorkspacesInGlobalScope, _, err := t.authorizer.Authorize(listWorkspacesInGlobalScope) userDetail, err := t.im.DescribeUser(user.GetName())
if err != nil { if err != nil {
klog.Error(err) return nil, fmt.Errorf("failed to describe user: %s", err)
return nil, err
} }
if allowedListClustersInGlobalScope == authorizer.DecisionAllow || grantedClustersAnnotation := userDetail.Annotations[iamv1alpha2.GrantedClustersAnnotation]
allowedListWorkspacesInGlobalScope == authorizer.DecisionAllow { var grantedClusters sets.String
result, err := t.resourceGetter.List(clusterv1alpha1.ResourcesPluralCluster, "", query.New()) if len(grantedClustersAnnotation) > 0 {
grantedClusters = sets.NewString(strings.Split(grantedClustersAnnotation, ",")...)
} else {
grantedClusters = sets.NewString()
}
var clusters []*clusterv1alpha1.Cluster
for _, grantedCluster := range grantedClusters.List() {
obj, err := t.resourceGetter.Get(clusterv1alpha1.ResourcesPluralCluster, "", grantedCluster)
if err != nil { if err != nil {
klog.Error(err) if errors.IsNotFound(err) {
return nil, err
}
return result, nil
}
workspaceRoleBindings, err := t.am.ListWorkspaceRoleBindings(user.GetName(), user.GetGroups(), "")
if err != nil {
klog.Error(err)
return nil, err
}
clusters := map[string]*clusterv1alpha1.Cluster{}
for _, roleBinding := range workspaceRoleBindings {
workspaceName := roleBinding.Labels[tenantv1alpha1.WorkspaceLabel]
workspace, err := t.DescribeWorkspaceTemplate(workspaceName)
if err != nil {
klog.Error(err)
return nil, err
}
for _, grantedCluster := range workspace.Spec.Placement.Clusters {
// skip if cluster exist
if clusters[grantedCluster.Name] != nil {
continue continue
} }
obj, err := t.resourceGetter.Get(clusterv1alpha1.ResourcesPluralCluster, "", grantedCluster.Name) return nil, fmt.Errorf("failed to fetch cluster: %s", err)
if err != nil {
klog.Error(err)
if errors.IsNotFound(err) {
continue
}
return nil, err
}
cluster := obj.(*clusterv1alpha1.Cluster)
clusters[cluster.Name] = cluster
} }
cluster := obj.(*clusterv1alpha1.Cluster)
clusters = append(clusters, cluster)
} }
items := make([]interface{}, 0) items := make([]runtime.Object, 0)
for _, cluster := range clusters { for _, cluster := range clusters {
items = append(items, cluster) items = append(items, cluster)
} }
return &api.ListResult{Items: items, TotalItems: len(items)}, nil // apply additional labelSelector
if queryParam.LabelSelector != "" {
queryParam.Filters[query.FieldLabel] = query.Value(queryParam.LabelSelector)
}
// use default pagination search logic
result := resources.DefaultList(items, queryParam, func(left runtime.Object, right runtime.Object, field query.Field) bool {
return resources.DefaultObjectMetaCompare(left.(*clusterv1alpha1.Cluster).ObjectMeta, right.(*clusterv1alpha1.Cluster).ObjectMeta, field)
}, func(workspace runtime.Object, filter query.Filter) bool {
return resources.DefaultObjectMetaFilter(workspace.(*clusterv1alpha1.Cluster).ObjectMeta, filter)
})
return result, nil
} }
func (t *tenantOperator) DeleteWorkspaceTemplate(workspace string, opts metav1.DeleteOptions) error { func (t *tenantOperator) DeleteWorkspaceTemplate(workspace string, opts metav1.DeleteOptions) error {

View File

@@ -544,5 +544,5 @@ func prepare() Interface {
amOperator := am.NewOperator(ksClient, k8sClient, fakeInformerFactory, nil) amOperator := am.NewOperator(ksClient, k8sClient, fakeInformerFactory, nil)
authorizer := rbac.NewRBACAuthorizer(amOperator) authorizer := rbac.NewRBACAuthorizer(amOperator)
return New(fakeInformerFactory, k8sClient, ksClient, nil, nil, nil, amOperator, authorizer, nil, nil, nil) return New(fakeInformerFactory, k8sClient, ksClient, nil, nil, nil, amOperator, nil, authorizer, nil, nil, nil)
} }

View File

@@ -58,6 +58,7 @@ const (
GlobalRoleAnnotation = "iam.kubesphere.io/globalrole" GlobalRoleAnnotation = "iam.kubesphere.io/globalrole"
WorkspaceRoleAnnotation = "iam.kubesphere.io/workspacerole" WorkspaceRoleAnnotation = "iam.kubesphere.io/workspacerole"
ClusterRoleAnnotation = "iam.kubesphere.io/clusterrole" ClusterRoleAnnotation = "iam.kubesphere.io/clusterrole"
GrantedClustersAnnotation = "iam.kubesphere.io/granted-clusters"
UninitializedAnnotation = "iam.kubesphere.io/uninitialized" UninitializedAnnotation = "iam.kubesphere.io/uninitialized"
LastPasswordChangeTimeAnnotation = "iam.kubesphere.io/last-password-change-time" LastPasswordChangeTimeAnnotation = "iam.kubesphere.io/last-password-change-time"
RoleAnnotation = "iam.kubesphere.io/role" RoleAnnotation = "iam.kubesphere.io/role"