diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index 526d6b5dbc..05192de2ff 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -9,6 +9,7 @@ import ( "context" "encoding/json" "fmt" + "strconv" "strings" "kubesphere.io/kubesphere/pkg/constants" @@ -35,6 +36,7 @@ import ( "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" "kubesphere.io/kubesphere/pkg/apiserver/query" "kubesphere.io/kubesphere/pkg/apiserver/request" + clusterutils "kubesphere.io/kubesphere/pkg/controller/cluster/utils" "kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/im" resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" @@ -43,6 +45,11 @@ import ( jsonpatchutil "kubesphere.io/kubesphere/pkg/utils/josnpatchutil" ) +const ( + orphanFinalizer = "orphan.finalizers.kubesphere.io" + queryRoleBindingExists = "roleBindingExists" +) + type Interface interface { ListWorkspaces(user user.Info, queryParam *query.Query) (*api.ListResult, error) GetWorkspace(workspace string) (*tenantv1beta1.Workspace, error) @@ -543,6 +550,27 @@ func (t *tenantOperator) ListClusters(user user.Info, queryParam *query.Query) ( items = append(items, cluster) } + clusterByRoleBinding := false + if v, ok := queryParam.Filters[queryRoleBindingExists]; ok && v != "" { + clusterByRoleBinding, err = strconv.ParseBool(string(v)) + if err != nil { + return nil, err + } + } + + if clusterByRoleBinding { + byRoleBinding, err := t.getClusterByRoleBinding(context.Background(), user) + if err != nil { + return nil, err + } + for _, cluster := range byRoleBinding { + // duplicate cluster will not append to results + if !grantedClusters.Has(cluster.Name) { + items = append(items, cluster) + } + } + } + // apply additional labelSelector if queryParam.LabelSelector != "" { queryParam.Filters[query.FieldLabel] = query.Value(queryParam.LabelSelector) @@ -558,6 +586,35 @@ func (t *tenantOperator) ListClusters(user user.Info, queryParam *query.Query) ( return result, nil } +func (t *tenantOperator) getClusterByRoleBinding(ctx context.Context, user user.Info) ([]*clusterv1alpha1.Cluster, error) { + result := []*clusterv1alpha1.Cluster{} + clusters, err := t.clusterClient.ListClusters(ctx) + if err != nil { + return nil, err + } + + for _, cluster := range clusters { + if !clusterutils.IsClusterReady(&cluster) { + continue + } + rtClient, err := t.clusterClient.GetRuntimeClient(cluster.Name) + if err != nil { + return nil, err + } + + rbList := &iamv1beta1.RoleBindingList{} + err = rtClient.List(ctx, rbList, runtimeclient.MatchingLabels{iamv1beta1.UserReferenceLabel: user.GetName()}) + if err != nil { + return nil, err + } + if len(rbList.Items) != 0 { + result = append(result, &cluster) + } + + } + return result, nil +} + func (t *tenantOperator) DeleteWorkspaceTemplate(workspaceName string, opts metav1.DeleteOptions) error { workspace := &tenantv1beta1.WorkspaceTemplate{} if err := t.client.Get(context.Background(), types.NamespacedName{Name: workspaceName}, workspace); err != nil { @@ -597,6 +654,23 @@ func contains(objects []runtime.Object, object runtime.Object) bool { return false } +func stringSet(strs []string) map[string]struct{} { + m := make(map[string]struct{}) + for _, str := range strs { + m[str] = struct{}{} + } + return m +} + +func stringContains(str string, subStrs []string) bool { + for _, sub := range subStrs { + if strings.Contains(str, sub) { + return true + } + } + return false +} + func (t *tenantOperator) checkWorkspaceTemplatePermission(user user.Info, workspace string) error { deleteWST := authorizer.AttributesRecord{ User: user, diff --git a/pkg/utils/clusterclient/clusterclient.go b/pkg/utils/clusterclient/clusterclient.go index 1ace027ad8..4ad12e2a8f 100644 --- a/pkg/utils/clusterclient/clusterclient.go +++ b/pkg/utils/clusterclient/clusterclient.go @@ -125,9 +125,6 @@ func (c *clusterClients) addCluster(obj interface{}) (*ClusterClient, error) { if err != nil { return nil, err } - if err != nil { - return nil, err - } client, err := runtimeclient.New(restConfig, runtimeclient.Options{ HTTPClient: httpClient, Scheme: scheme.Scheme,