[WIP] API refactor (#1737)
* refactor openpitrix API Signed-off-by: hongming <talonwan@yunify.com> * add openpitrix mock client Signed-off-by: hongming <talonwan@yunify.com> * refactor tenant API Signed-off-by: hongming <talonwan@yunify.com> * refactor IAM API Signed-off-by: hongming <talonwan@yunify.com> * refactor IAM API Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/gojenkins/utils"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/devops"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
@@ -317,7 +318,7 @@ func CreateDevopsProject(username string, workspace string, req *v1alpha2.DevOps
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) {
|
||||
func GetUserDevopsSimpleRules(username, projectId string) ([]iam.SimpleRule, error) {
|
||||
role, err := devops.GetProjectUserRole(username, projectId)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
@@ -326,12 +327,12 @@ func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule,
|
||||
return GetDevopsRoleSimpleRules(role), nil
|
||||
}
|
||||
|
||||
func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
var rules []models.SimpleRule
|
||||
func GetDevopsRoleSimpleRules(role string) []iam.SimpleRule {
|
||||
var rules []iam.SimpleRule
|
||||
|
||||
switch role {
|
||||
case "developer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -339,7 +340,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "owner":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
@@ -348,7 +349,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "maintainer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -359,7 +360,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
case "reporter":
|
||||
fallthrough
|
||||
default:
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
@@ -32,11 +33,34 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type namespaceSearcher struct {
|
||||
type NamespaceInterface interface {
|
||||
Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error)
|
||||
CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error)
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
type namespaceSearcher struct {
|
||||
k8s kubernetes.Interface
|
||||
informers k8sinformers.SharedInformerFactory
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
if username != "" {
|
||||
namespace.Annotations[constants.CreatorAnnotationKey] = username
|
||||
}
|
||||
|
||||
namespace.Labels[constants.WorkspaceLabelKey] = workspace
|
||||
|
||||
return s.k8s.CoreV1().Namespaces().Create(namespace)
|
||||
}
|
||||
|
||||
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory) NamespaceInterface {
|
||||
return &namespaceSearcher{k8s: k8s, informers: informers}
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case v1alpha2.Name:
|
||||
@@ -58,7 +82,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
func (s *namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -74,7 +98,7 @@ func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
func (s *namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case "createTime":
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
@@ -85,7 +109,7 @@ func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
|
||||
func (s *namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
|
||||
@@ -93,7 +117,7 @@ func (*namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error
|
||||
return nil, err
|
||||
}
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
namespaceLister := s.informers.Core().V1().Namespaces().Lister()
|
||||
for _, role := range roles {
|
||||
namespace, err := namespaceLister.Get(role.Namespace)
|
||||
if err != nil {
|
||||
@@ -117,7 +141,7 @@ func containsNamespace(namespaces []*v1.Namespace, namespace *v1.Namespace) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
|
||||
func (s *namespaceSearcher) Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
|
||||
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
|
||||
@@ -128,7 +152,7 @@ func (s *namespaceSearcher) search(username string, conditions *params.Condition
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
|
||||
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"namespaces"}}) {
|
||||
namespaces, err = informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
namespaces, err = s.informers.Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
} else {
|
||||
namespaces, err = s.GetNamespaces(username)
|
||||
}
|
||||
@@ -148,12 +172,14 @@ func (s *namespaceSearcher) search(username string, conditions *params.Condition
|
||||
// order & reverse
|
||||
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 result, nil
|
||||
}
|
||||
|
||||
func CreateNamespace() {
|
||||
|
||||
}
|
||||
|
||||
@@ -19,49 +19,62 @@ package tenant
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
ws "kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
workspaces = workspaceSearcher{}
|
||||
namespaces = namespaceSearcher{}
|
||||
)
|
||||
|
||||
func CreateNamespace(workspaceName string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
if username != "" {
|
||||
namespace.Annotations[constants.CreatorAnnotationKey] = username
|
||||
}
|
||||
|
||||
namespace.Labels[constants.WorkspaceLabelKey] = workspaceName
|
||||
|
||||
return client.ClientSets().K8s().Kubernetes().CoreV1().Namespaces().Create(namespace)
|
||||
type Interface interface {
|
||||
CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
DescribeWorkspace(username, workspace string) (*v1alpha1.Workspace, error)
|
||||
ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
}
|
||||
|
||||
func DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
type tenantOperator struct {
|
||||
workspaces WorkspaceInterface
|
||||
namespaces NamespaceInterface
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
|
||||
return t.workspaces.DeleteNamespace(workspace, namespace)
|
||||
}
|
||||
|
||||
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
|
||||
return &tenantOperator{
|
||||
workspaces: newWorkspaceOperator(client, informers, ksinformers, db),
|
||||
namespaces: newNamespaceOperator(client, informers),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tenantOperator) CreateNamespace(workspaceName string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
return t.namespaces.CreateNamespace(workspaceName, namespace, username)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
workspace, err := t.workspaces.GetWorkspace(workspaceName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workspace = appendAnnotations(username, workspace)
|
||||
if username != "" {
|
||||
workspace = t.appendAnnotations(username, workspace)
|
||||
}
|
||||
|
||||
return workspace, nil
|
||||
}
|
||||
|
||||
func ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (t *tenantOperator) ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
workspaces, err := workspaces.search(username, conditions, orderBy, reverse)
|
||||
workspaces, err := t.workspaces.SearchWorkspace(username, conditions, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -71,7 +84,7 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
||||
result := make([]interface{}, 0)
|
||||
for i, workspace := range workspaces {
|
||||
if len(result) < limit && i >= offset {
|
||||
workspace := appendAnnotations(username, workspace)
|
||||
workspace := t.appendAnnotations(username, workspace)
|
||||
result = append(result, workspace)
|
||||
}
|
||||
}
|
||||
@@ -79,12 +92,12 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
||||
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
|
||||
}
|
||||
|
||||
func appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||
func (t *tenantOperator) appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||
workspace = workspace.DeepCopy()
|
||||
if workspace.Annotations == nil {
|
||||
workspace.Annotations = make(map[string]string)
|
||||
}
|
||||
ns, err := ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||
ns, err := t.ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
|
||||
}
|
||||
@@ -92,16 +105,18 @@ func appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
|
||||
}
|
||||
userCount, err := ws.WorkspaceUserCount(workspace.Name)
|
||||
|
||||
userCount, err := t.workspaces.CountUsersInWorkspace(workspace.Name)
|
||||
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/member-count"] = strconv.Itoa(userCount)
|
||||
}
|
||||
return workspace
|
||||
}
|
||||
|
||||
func ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (t *tenantOperator) ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
namespaces, err := namespaces.search(username, conditions, orderBy, reverse)
|
||||
namespaces, err := t.namespaces.Search(username, conditions, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,41 +1,241 @@
|
||||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
*
|
||||
* 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 tenant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
core "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/db"
|
||||
"kubesphere.io/kubesphere/pkg/models/devops"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
clientset "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type workspaceSearcher struct {
|
||||
type WorkspaceInterface interface {
|
||||
GetWorkspace(workspace string) (*v1alpha1.Workspace, error)
|
||||
SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error)
|
||||
ListNamespaces(workspace string) ([]*core.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
RemoveUser(user, workspace string) error
|
||||
AddUser(workspace string, user *iam.User) error
|
||||
CountDevopsProjectsInWorkspace(workspace string) (int, error)
|
||||
CountUsersInWorkspace(workspace string) (int, error)
|
||||
CountOrgRoles() (int, error)
|
||||
CountWorkspaces() (int, error)
|
||||
CountNamespacesInWorkspace(workspace string) (int, error)
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
func (*workspaceSearcher) match(match map[string]string, item *v1alpha1.Workspace) bool {
|
||||
type workspaceOperator struct {
|
||||
client kubernetes.Interface
|
||||
informers informers.SharedInformerFactory
|
||||
ksInformers externalversions.SharedInformerFactory
|
||||
|
||||
// TODO: use db interface instead of mysql client
|
||||
// we can refactor this after rewrite devops using crd
|
||||
db *mysql.Database
|
||||
}
|
||||
|
||||
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, db *mysql.Database) WorkspaceInterface {
|
||||
return &workspaceOperator{
|
||||
client: client,
|
||||
informers: informers,
|
||||
ksInformers: ksinformers,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) ListNamespaces(workspace string) ([]*core.Namespace, error) {
|
||||
namespaces, err := w.informers.Core().V1().Namespaces().Lister().List(labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspace}))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) DeleteNamespace(workspace string, namespace string) error {
|
||||
ns, err := w.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ns.Labels[constants.WorkspaceLabelKey] == workspace {
|
||||
deletePolicy := metav1.DeletePropagationBackground
|
||||
return w.client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
} else {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "workspace"}, workspace)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) RemoveUser(workspace string, username string) error {
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.deleteWorkspaceRoleBinding(workspace, username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) AddUser(workspaceName string, user *iam.User) error {
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("get workspace role failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
workspaceRoleName := fmt.Sprintf("workspace:%s:%s", workspaceName, strings.TrimPrefix(user.WorkspaceRole, "workspace-"))
|
||||
var currentWorkspaceRoleName string
|
||||
if workspaceRole != nil {
|
||||
currentWorkspaceRoleName = workspaceRole.Name
|
||||
}
|
||||
|
||||
if currentWorkspaceRoleName != workspaceRoleName && currentWorkspaceRoleName != "" {
|
||||
err := w.deleteWorkspaceRoleBinding(workspaceName, user.Username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
klog.Errorf("delete workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
} else if currentWorkspaceRoleName != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return w.createWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) createWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) {
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
|
||||
_, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
if err != nil {
|
||||
klog.Errorf("update workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
|
||||
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
|
||||
for i, v := range workspaceRoleBinding.Subjects {
|
||||
if v.Kind == v1.UserKind && v.Name == username {
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects[:i], workspaceRoleBinding.Subjects[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
workspaceRoleBinding, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) {
|
||||
if w.db == nil {
|
||||
return 0, clientset.ErrClientSetNotEnabled
|
||||
}
|
||||
|
||||
query := w.db.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.And(db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspaceName),
|
||||
db.Eq(devops.StatusColumn, devops.StatusActive)))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountUsersInWorkspace(workspace string) (int, error) {
|
||||
count, err := iam.WorkspaceUsersTotalCount(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountOrgRoles() (int, error) {
|
||||
return len(constants.WorkSpaceRoles), nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountNamespacesInWorkspace(workspace string) (int, error) {
|
||||
ns, err := w.ListNamespaces(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ns), nil
|
||||
}
|
||||
|
||||
func (*workspaceOperator) match(match map[string]string, item *v1alpha1.Workspace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case v1alpha2.Name:
|
||||
@@ -57,7 +257,7 @@ func (*workspaceSearcher) match(match map[string]string, item *v1alpha1.Workspac
|
||||
return true
|
||||
}
|
||||
|
||||
func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspace) bool {
|
||||
func (*workspaceOperator) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspace) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -73,7 +273,7 @@ func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspac
|
||||
return true
|
||||
}
|
||||
|
||||
func (*workspaceSearcher) compare(a, b *v1alpha1.Workspace, orderBy string) bool {
|
||||
func (*workspaceOperator) compare(a, b *v1alpha1.Workspace, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case v1alpha2.CreateTime:
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
@@ -84,7 +284,7 @@ func (*workspaceSearcher) compare(a, b *v1alpha1.Workspace, orderBy string) bool
|
||||
}
|
||||
}
|
||||
|
||||
func (s *workspaceSearcher) search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
|
||||
func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
|
||||
if err != nil {
|
||||
@@ -94,7 +294,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
workspaces := make([]*v1alpha1.Workspace, 0)
|
||||
|
||||
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"workspaces"}}) {
|
||||
workspaces, err = informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
workspaces, err = w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -104,7 +304,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
return nil, err
|
||||
}
|
||||
for k := range workspaceRoles {
|
||||
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(k)
|
||||
workspace, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -115,7 +315,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
result := make([]*v1alpha1.Workspace, 0)
|
||||
|
||||
for _, workspace := range workspaces {
|
||||
if s.match(conditions.Match, workspace) && s.fuzzy(conditions.Fuzzy, workspace) {
|
||||
if w.match(conditions.Match, workspace) && w.fuzzy(conditions.Fuzzy, workspace) {
|
||||
result = append(result, workspace)
|
||||
}
|
||||
}
|
||||
@@ -123,18 +323,16 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
// order & reverse
|
||||
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 w.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
return informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
func (w *workspaceOperator) GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
return w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
}
|
||||
|
||||
func contains(m map[string]string, key, value string) bool {
|
||||
@@ -149,3 +347,47 @@ func contains(m map[string]string, key, value string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: move to metrics package
|
||||
func GetAllProjectNums() (int, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
list, err := namespaceLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(list), nil
|
||||
}
|
||||
|
||||
func GetAllDevOpsProjectsNums() (int, error) {
|
||||
_, err := clientset.ClientSets().Devops()
|
||||
if _, notEnabled := err.(clientset.ClientSetNotEnabledError); notEnabled {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
dbconn, err := clientset.ClientSets().MySQL()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
query := dbconn.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.Eq(devops.StatusColumn, devops.StatusActive))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (w *workspaceOperator) CountWorkspaces() (int, error) {
|
||||
ws, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ws), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user