This is a huge commit, it does following things: (#1942)

1. Remove ks-iam standalone binary, move it to ks-apiserver
2. Generate all devops apis inside kubesphere repository, no need to
import s2ioperator.
3. Reorganize ldap code, make it more flexible to use.
This commit is contained in:
zryfish
2020-03-10 13:50:17 +08:00
committed by GitHub
parent 7270307b66
commit 641615b299
235 changed files with 5538 additions and 38064 deletions

View File

@@ -24,6 +24,7 @@ import (
"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/constants"
"kubesphere.io/kubesphere/pkg/models"
@@ -33,7 +34,6 @@ import (
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
)
@@ -62,8 +62,9 @@ type AccessManagementInterface interface {
}
type amOperator struct {
informers informers.SharedInformerFactory
resources resource.ResourceGetter
informers informers.SharedInformerFactory
resources resource.ResourceGetter
kubeClient kubernetes.Interface
}
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
@@ -90,11 +91,15 @@ func (am *amOperator) UnBindAllRoles(username string) error {
panic("implement me")
}
func NewAMOperator(informers informers.SharedInformerFactory) *amOperator {
func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) *amOperator {
resourceGetter := resource.ResourceGetter{}
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
return &amOperator{informers: informers, resources: resourceGetter}
return &amOperator{
informers: informers,
resources: resourceGetter,
kubeClient: kubeClient,
}
}
func (am *amOperator) GetDevopsRoleSimpleRules(role string) []policy.SimpleRule {
@@ -560,7 +565,7 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
found, err := clusterRoleBindingLister.Get(username)
if apierrors.IsNotFound(err) {
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln("create cluster role binding", err)
return err
@@ -575,12 +580,12 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
deletePolicy := metav1.DeletePropagationBackground
gracePeriodSeconds := int64(0)
deleteOption := &metav1.DeleteOptions{PropagationPolicy: &deletePolicy, GracePeriodSeconds: &gracePeriodSeconds}
err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
err = am.kubeClient.RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
if err != nil {
klog.Errorln(err)
return err
}
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln(err)
return err
@@ -590,7 +595,7 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
if !ContainsUser(found.Subjects, username) {
found.Subjects = clusterRoleBinding.Subjects
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(found)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Update(found)
if err != nil {
klog.Errorln("update cluster role binding", err)
return err

View File

@@ -20,216 +20,96 @@ package iam
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/go-ldap/ldap"
"github.com/go-redis/redis"
"github.com/pkg/errors"
"golang.org/x/oauth2"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/server/params"
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
"strconv"
"strings"
"time"
)
type IdentityManagementInterface interface {
CreateUser(user *User) (*User, error)
CreateUser(user *iam.User) (*iam.User, error)
DeleteUser(username string) error
DescribeUser(username string) (*User, error)
DescribeUser(username string) (*iam.User, error)
Login(username, password, ip string) (*oauth2.Token, error)
ModifyUser(user *User) (*User, error)
ModifyUser(user *iam.User) (*iam.User, error)
ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
GetUserRoles(username string) ([]*rbacv1.Role, error)
GetUserRole(namespace string, username string) (*rbacv1.Role, error)
}
type Config struct {
authRateLimit string
maxAuthFailed int
authTimeInterval time.Duration
tokenIdleTimeout time.Duration
enableMultiLogin bool
}
type imOperator struct {
config Config
ldap ldappool.Client
redis redis.Client
authenticateOptions *iam.AuthenticationOptions
ldapClient ldap.Interface
cacheClient cache.Interface
}
const (
authRateLimitRegex = `(\d+)/(\d+[s|m|h])`
defaultMaxAuthFailed = 5
defaultAuthTimeInterval = 30 * time.Minute
mailAttribute = "mail"
uidAttribute = "uid"
descriptionAttribute = "description"
preferredLanguageAttribute = "preferredLanguage"
createTimestampAttribute = "createTimestampAttribute"
dateTimeLayout = "20060102150405Z"
)
var (
AuthRateLimitExceeded = errors.New("user auth rate limit exceeded")
UserAlreadyExists = errors.New("user already exists")
UserNotExists = errors.New("user not exists")
)
func NewIMOperator(ldap ldappool.Client, config Config) *imOperator {
imOperator := &imOperator{ldap: ldap, config: config}
return imOperator
func NewIMOperator(ldapClient ldap.Interface, cacheClient cache.Interface, options *iam.AuthenticationOptions) *imOperator {
return &imOperator{ldapClient: ldapClient, cacheClient: cacheClient, authenticateOptions: options}
}
// TODO init in controller
func (im *imOperator) Init() error {
userSearchBase := &ldap.AddRequest{
DN: im.ldap.UserSearchBase(),
Attributes: []ldap.Attribute{{
Type: "objectClass",
Vals: []string{"organizationalUnit", "top"},
}, {
Type: "ou",
Vals: []string{"Users"},
}},
Controls: nil,
}
err := im.createIfNotExists(userSearchBase)
func (im *imOperator) ModifyUser(user *iam.User) (*iam.User, error) {
err := im.ldapClient.Update(user)
if err != nil {
return err
}
groupSearchBase := &ldap.AddRequest{
DN: im.ldap.GroupSearchBase(),
Attributes: []ldap.Attribute{{
Type: "objectClass",
Vals: []string{"organizationalUnit", "top"},
}, {
Type: "ou",
Vals: []string{"Groups"},
}},
Controls: nil,
}
err = im.createIfNotExists(groupSearchBase)
if err != nil {
return err
}
return nil
}
func (im *imOperator) createIfNotExists(createRequest *ldap.AddRequest) error {
conn, err := im.ldap.NewConn()
if err != nil {
return err
}
defer conn.Close()
searchRequest := ldap.NewSearchRequest(
createRequest.DN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(objectClass=*)",
nil,
nil,
)
_, err = conn.Search(searchRequest)
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
err = conn.Add(createRequest)
}
if err != nil {
klog.Errorln(err)
return err
}
return nil
}
func (im *imOperator) ModifyUser(user *User) (*User, error) {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
defer conn.Close()
dn := fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase())
userModifyRequest := ldap.NewModifyRequest(dn, nil)
if user.Description != "" {
userModifyRequest.Replace("description", []string{user.Description})
}
if user.Lang != "" {
userModifyRequest.Replace("preferredLanguage", []string{user.Lang})
}
if user.Password != "" {
userModifyRequest.Replace("userPassword", []string{user.Password})
}
err = conn.Modify(userModifyRequest)
if err != nil {
klog.Error(err)
return nil, err
}
// clear auth failed record
if user.Password != "" {
records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", user.Username)).Result()
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Username, "*"))
if err == nil {
im.redis.Del(records...)
im.cacheClient.Del(records...)
}
}
return im.DescribeUser(user.Username)
return im.ldapClient.Get(user.Username)
}
func authenticationFailedKeyForUsername(username, failedTimestamp string) string {
return fmt.Sprintf("kubesphere:authfailed:%s:%s", username, failedTimestamp)
}
func tokenKeyForUsername(username, token string) string {
return fmt.Sprintf("kubesphere:users:%s:token:%s", username, token)
}
func loginKeyForUsername(username, loginTimestamp, ip string) string {
return fmt.Sprintf("kubesphere:users:%s:login-log:%s:%s", username, loginTimestamp, ip)
}
func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error) {
records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", username)).Result()
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(username, "*"))
if err != nil {
klog.Error(err)
return nil, err
}
if len(records) >= im.config.maxAuthFailed {
if len(records) >= im.authenticateOptions.MaxAuthenticateRetries {
return nil, AuthRateLimitExceeded
}
user, err := im.DescribeUser(username)
conn, err := im.ldap.NewConn()
user, err := im.ldapClient.Get(username)
if err != nil {
klog.Error(err)
return nil, err
}
defer conn.Close()
dn := fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase())
// bind as the user to verify their password
err = conn.Bind(dn, password)
err = im.ldapClient.Verify(user.Username, password)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
cacheKey := fmt.Sprintf("kubesphere:authfailed:%s:%d", user.Username, time.Now().UnixNano())
im.redis.Set(cacheKey, "", im.config.authTimeInterval)
if err == ldap.ErrInvalidCredentials {
im.cacheClient.Set(authenticationFailedKeyForUsername(username, fmt.Sprintf("%d", time.Now().UnixNano())), "", 30*time.Minute)
}
return nil, err
}
@@ -243,30 +123,25 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
}
token := jwtutil.MustSigned(claims)
if !im.config.enableMultiLogin {
tokenKey := tokenKeyForUsername(user.Username, "*")
if !im.authenticateOptions.MultipleLogin {
// multi login not allowed, remove the previous token
cacheKey := fmt.Sprintf("kubesphere:users:%s:token:*", user.Username)
sessions, err := im.redis.Keys(cacheKey).Result()
sessions, err := im.cacheClient.Keys(tokenKey)
if err != nil {
klog.Errorln(err)
return nil, err
}
if len(sessions) > 0 {
klog.V(4).Infoln("revoke token", sessions)
err = im.redis.Del(sessions...).Err()
err = im.cacheClient.Del(sessions...)
if err != nil {
klog.Errorln(err)
return nil, err
}
}
}
// cache token with expiration time
cacheKey := fmt.Sprintf("kubesphere:users:%s:token:%s", user.Username, token)
if err = im.redis.Set(cacheKey, token, im.config.tokenIdleTimeout).Err(); err != nil {
klog.Errorln(err)
if err = im.cacheClient.Set(tokenKey, token, im.authenticateOptions.TokenExpiration); err != nil {
return nil, err
}
@@ -277,153 +152,39 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
func (im *imOperator) loginRecord(username, ip string, loginTime time.Time) {
if ip != "" {
im.redis.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", username), fmt.Sprintf("%s,%s", loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip))
im.redis.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1)
_ = im.cacheClient.Set(loginKeyForUsername(username, loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip), "", 30*24*time.Hour)
}
}
func (im *imOperator) LoginHistory(username string) ([]string, error) {
data, err := im.redis.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1).Result()
keys, err := im.cacheClient.Keys(loginKeyForUsername(username, "*", "*"))
if err != nil {
return nil, err
}
return data, nil
return keys, nil
}
func (im *imOperator) ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
panic("implement me")
}
func (im *imOperator) DescribeUser(username string) (*User, error) {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
defer conn.Close()
filter := fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=%s)(mail=%s)))", username, username)
searchRequest := ldap.NewSearchRequest(
im.ldap.UserSearchBase(),
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter,
[]string{mailAttribute, descriptionAttribute, preferredLanguageAttribute, createTimestampAttribute},
nil,
)
result, err := conn.Search(searchRequest)
if err != nil {
klog.Errorln(err)
return nil, err
}
if len(result.Entries) != 1 {
return nil, UserNotExists
}
entry := result.Entries[0]
return convertLdapEntryToUser(entry), nil
}
func convertLdapEntryToUser(entry *ldap.Entry) *User {
username := entry.GetAttributeValue(uidAttribute)
email := entry.GetAttributeValue(mailAttribute)
description := entry.GetAttributeValue(descriptionAttribute)
lang := entry.GetAttributeValue(preferredLanguageAttribute)
createTimestamp, err := time.Parse(dateTimeLayout, entry.GetAttributeValue(createTimestampAttribute))
if err != nil {
klog.Errorln(err)
}
return &User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
func (im *imOperator) DescribeUser(username string) (*iam.User, error) {
return im.ldapClient.Get(username)
}
func (im *imOperator) getLastLoginTime(username string) string {
cacheKey := fmt.Sprintf("kubesphere:users:%s:login-log", username)
lastLogin, err := im.redis.LRange(cacheKey, -1, -1).Result()
if err != nil {
return ""
}
if len(lastLogin) > 0 {
return strings.Split(lastLogin[0], ",")[0]
}
return ""
}
func (im *imOperator) DeleteUser(username string) error {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return err
}
defer conn.Close()
deleteRequest := ldap.NewDelRequest(fmt.Sprintf("uid=%s,%s", username, im.ldap.UserSearchBase()), nil)
if err = conn.Del(deleteRequest); err != nil {
klog.Errorln(err)
return err
}
return nil
return im.ldapClient.Delete(username)
}
func (im *imOperator) CreateUser(user *User) (*User, error) {
user.Username = strings.TrimSpace(user.Username)
user.Email = strings.TrimSpace(user.Email)
user.Password = strings.TrimSpace(user.Password)
user.Description = strings.TrimSpace(user.Description)
existed, err := im.DescribeUser(user.Username)
func (im *imOperator) CreateUser(user *iam.User) (*iam.User, error) {
err := im.ldapClient.Create(user)
if err != nil {
klog.Errorln(err)
return nil, err
}
if existed != nil {
return nil, UserAlreadyExists
}
uidNumber := im.uidNumberNext()
createRequest := ldap.NewAddRequest(fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase()), nil)
createRequest.Attribute("objectClass", []string{"inetOrgPerson", "posixAccount", "top"})
createRequest.Attribute("cn", []string{user.Username}) // RFC4519: common name(s) for which the entity is known by
createRequest.Attribute("sn", []string{" "}) // RFC2256: last (family) name(s) for which the entity is known by
createRequest.Attribute("gidNumber", []string{"500"}) // RFC2307: An integer uniquely identifying a group in an administrative domain
createRequest.Attribute("homeDirectory", []string{"/home/" + user.Username}) // The absolute path to the home directory
createRequest.Attribute("uid", []string{user.Username}) // RFC4519: user identifier
createRequest.Attribute("uidNumber", []string{strconv.Itoa(uidNumber)}) // RFC2307: An integer uniquely identifying a user in an administrative domain
createRequest.Attribute("mail", []string{user.Email}) // RFC1274: RFC822 Mailbox
createRequest.Attribute("userPassword", []string{user.Password}) // RFC4519/2307: password of user
if user.Lang != "" {
createRequest.Attribute("preferredLanguage", []string{user.Lang})
}
if user.Description != "" {
createRequest.Attribute("description", []string{user.Description}) // RFC4519: descriptive information
}
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
err = conn.Add(createRequest)
if err != nil {
klog.Errorln(err)
return nil, err
}

View File

@@ -17,39 +17,3 @@
*/
package iam
import (
"github.com/golang/mock/gomock"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"testing"
)
func TestIMOperator(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ldappool, err := ldap.NewMockClient(&ldap.Options{
Host: "192.168.0.7:30389",
ManagerDN: "cn=admin,dc=kubesphere,dc=io",
ManagerPassword: "admin",
UserSearchBase: "ou=Users,dc=kubesphere,dc=io",
GroupSearchBase: "ou=Groups,dc=kubesphere,dc=io",
InitialCap: 8,
MaxCap: 64,
}, ctrl, func(client *ldap.MockClient) {
client.EXPECT().Search(gomock.Any()).AnyTimes()
})
if err != nil {
t.Fatal(err)
}
defer ldappool.Close()
im := NewIMOperator(ldappool, Config{})
err = im.Init()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,80 +0,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 iam
import (
"fmt"
"kubesphere.io/kubesphere/pkg/simple/client"
"regexp"
"strings"
)
func convertDNToPath(dn string) string {
paths := regexp.MustCompile("cn=[a-z0-9]([-a-z0-9]*[a-z0-9])?").FindAllString(dn, -1)
if len(paths) > 1 {
for i := 0; i < len(paths); i++ {
paths[i] = strings.Replace(paths[i], "cn=", "", 1)
}
for i, j := 0, len(paths)-1; i < j; i, j = i+1, j-1 {
paths[i], paths[j] = paths[j], paths[i]
}
return strings.Join(paths, ":")
} else if len(paths) == 1 {
return strings.Replace(paths[0], "cn=", "", -1)
} else {
return ""
}
}
func splitPath(path string) (searchBase string, cn string) {
ldapClient, err := client.ClientSets().Ldap()
if err != nil {
return "", ""
}
paths := strings.Split(path, ":")
length := len(paths)
if length > 2 {
cn = paths[length-1]
basePath := paths[:length-1]
for i := 0; i < len(basePath); i++ {
basePath[i] = fmt.Sprintf("cn=%s", basePath[i])
}
for i, j := 0, length-2; i < j; i, j = i+1, j-1 {
basePath[i], basePath[j] = basePath[j], basePath[i]
}
searchBase = fmt.Sprintf("%s,%s", strings.Join(basePath, ","), ldapClient.GroupSearchBase())
} else if length == 2 {
searchBase = fmt.Sprintf("cn=%s,%s", paths[0], ldapClient.GroupSearchBase())
cn = paths[1]
} else {
searchBase = ldapClient.GroupSearchBase()
if paths[0] == "" {
cn = "*"
} else {
cn = paths[0]
}
}
return
}

View File

@@ -1,37 +0,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.
* /
*/
package iam
import (
"time"
)
const (
KindTokenReview = "TokenReview"
)
type User struct {
Username string `json:"username"`
Email string `json:"email"`
Lang string `json:"lang,omitempty"`
Description string `json:"description"`
CreateTime time.Time `json:"create_time"`
Groups []string `json:"groups,omitempty"`
Password string `json:"password,omitempty"`
}

View File

@@ -20,6 +20,7 @@ package iam
import (
rbacv1 "k8s.io/api/rbac/v1"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"strings"
)
@@ -194,15 +195,15 @@ func ContainsUser(subjects interface{}, username string) bool {
return true
}
}
case []User:
for _, u := range subjects.([]User) {
case []iam.User:
for _, u := range subjects.([]iam.User) {
if u.Username == username {
return true
}
}
case []*User:
for _, u := range subjects.([]*User) {
case []*iam.User:
for _, u := range subjects.([]*iam.User) {
if u.Username == username {
return true
}

View File

@@ -77,9 +77,9 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.HorizontalPodAutoscalers] = hpa.NewHpaSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilders] = s2ibuilder.NewS2iBuilderSearcher(factory.S2iSharedInformerFactory())
resourceGetters[v1alpha2.S2iRuns] = s2irun.NewS2iRunSearcher(factory.S2iSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilderTemplates] = s2buildertemplate.NewS2iBuidlerTemplateSearcher(factory.S2iSharedInformerFactory())
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())

View File

@@ -18,8 +18,8 @@
package s2buildertemplate
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"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"

View File

@@ -19,9 +19,9 @@
package s2ibuilder
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"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"

View File

@@ -19,19 +19,15 @@
package s2irun
import (
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"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"
"kubesphere.io/kubesphere/pkg/server/params"
"k8s.io/apimachinery/pkg/labels"
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
)
type s2iRunSearcher struct {

View File

@@ -108,7 +108,7 @@ func TestListDeployments(t *testing.T) {
},
api.ListResult{
Items: []interface{}{
v1.Deployment{
&v1.Deployment{
ObjectMeta: metaV1.ObjectMeta{
Name: "foo-2",
Namespace: "bar",
@@ -141,7 +141,7 @@ func TestListDeployments(t *testing.T) {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
if diff := cmp.Diff(got.Items, test.expected.Items); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})

View File

@@ -77,7 +77,7 @@ func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
}
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
amOperator := iam.NewAMOperator(informers)
amOperator := iam.NewAMOperator(client, informers)
return &tenantOperator{
workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db),
namespaces: newNamespaceOperator(client, informers, amOperator),

View File

@@ -33,7 +33,6 @@ import (
"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/sliceutil"
"sort"
@@ -43,10 +42,12 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
iamapi "kubesphere.io/kubesphere/pkg/api/iam"
)
type InWorkspaceUser struct {
*iam.User
*iamapi.User
WorkspaceRole string `json:"workspaceRole"`
}
@@ -203,10 +204,6 @@ func (w *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username strin
}
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),