Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
水淹萌龙
kubesphere
提交
659316da
K
kubesphere
项目概览
水淹萌龙
/
kubesphere
与 Fork 源项目一致
Fork自
KubeSphere / kubesphere
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kubesphere
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
未验证
提交
659316da
编写于
7月 28, 2020
作者:
K
KubeSphere CI Bot
提交者:
GitHub
7月 28, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2661 from wansir/devops
fix: devops IAM bugs
上级
afcd0efe
bda48c24
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
305 addition
and
83 deletion
+305
-83
cmd/controller-manager/app/controllers.go
cmd/controller-manager/app/controllers.go
+1
-1
pkg/apiserver/authorization/authorizer/interfaces.go
pkg/apiserver/authorization/authorizer/interfaces.go
+8
-0
pkg/apiserver/authorization/authorizerfactory/rbac.go
pkg/apiserver/authorization/authorizerfactory/rbac.go
+30
-6
pkg/apiserver/filters/authorization.go
pkg/apiserver/filters/authorization.go
+1
-1
pkg/apiserver/request/requestinfo.go
pkg/apiserver/request/requestinfo.go
+28
-9
pkg/controller/devopsproject/devopsproject_controller.go
pkg/controller/devopsproject/devopsproject_controller.go
+57
-4
pkg/controller/devopsproject/devopsproject_controller_test.go
...controller/devopsproject/devopsproject_controller_test.go
+7
-3
pkg/controller/globalrolebinding/globalrolebinding_controller.go
...troller/globalrolebinding/globalrolebinding_controller.go
+18
-11
pkg/kapis/iam/v1alpha2/handler.go
pkg/kapis/iam/v1alpha2/handler.go
+2
-15
pkg/kapis/oauth/handler.go
pkg/kapis/oauth/handler.go
+1
-0
pkg/kapis/tenant/v1alpha2/handler.go
pkg/kapis/tenant/v1alpha2/handler.go
+23
-0
pkg/kapis/tenant/v1alpha2/register.go
pkg/kapis/tenant/v1alpha2/register.go
+14
-9
pkg/models/iam/am/am.go
pkg/models/iam/am/am.go
+15
-8
pkg/models/tenant/devops.go
pkg/models/tenant/devops.go
+99
-16
pkg/models/tenant/tenant.go
pkg/models/tenant/tenant.go
+1
-0
未找到文件。
cmd/controller-manager/app/controllers.go
浏览文件 @
659316da
...
...
@@ -122,7 +122,7 @@ func addControllers(
client
.
KubeSphere
(),
devopsClient
,
informerFactory
.
KubernetesSharedInformerFactory
()
.
Core
()
.
V1
()
.
Namespaces
(),
informerFactory
.
KubeSphereSharedInformerFactory
()
.
Devops
()
.
V1alpha3
()
.
DevOpsProjects
(),
)
informerFactory
.
KubeSphereSharedInformerFactory
()
.
Tenant
()
.
V1alpha1
()
.
Workspaces
()
)
devopsPipelineController
=
pipeline
.
NewController
(
client
.
Kubernetes
(),
client
.
KubeSphere
(),
...
...
pkg/apiserver/authorization/authorizer/interfaces.go
浏览文件 @
659316da
...
...
@@ -51,6 +51,9 @@ type Attributes interface {
// The namespace of the object, if a request is for a REST object.
GetNamespace
()
string
// The devops project of the object, if a request is for a REST object.
GetDevOps
()
string
// The kind of object, if a request is for a REST object.
GetResource
()
string
...
...
@@ -109,6 +112,7 @@ type AttributesRecord struct {
Cluster
string
Workspace
string
Namespace
string
DevOps
string
APIGroup
string
APIVersion
string
Resource
string
...
...
@@ -144,6 +148,10 @@ func (a AttributesRecord) GetNamespace() string {
return
a
.
Namespace
}
func
(
a
AttributesRecord
)
GetDevOps
()
string
{
return
a
.
DevOps
}
func
(
a
AttributesRecord
)
GetResource
()
string
{
return
a
.
Resource
}
...
...
pkg/apiserver/authorization/authorizerfactory/rbac.go
浏览文件 @
659316da
...
...
@@ -234,11 +234,21 @@ func (r *RBACAuthorizer) visitRulesFor(requestAttributes authorizer.Attributes,
}
}
if
requestAttributes
.
GetResourceScope
()
==
request
.
WorkspaceScope
||
requestAttributes
.
GetResourceScope
()
==
request
.
NamespaceScope
{
if
requestAttributes
.
GetResourceScope
()
==
request
.
WorkspaceScope
||
requestAttributes
.
GetResourceScope
()
==
request
.
NamespaceScope
||
requestAttributes
.
GetResourceScope
()
==
request
.
DevOpsScope
{
var
workspace
string
var
err
error
// all of resource under namespace and devops belong to workspace
if
requestAttributes
.
GetResourceScope
()
==
request
.
NamespaceScope
{
if
workspace
,
err
=
r
.
am
.
GetControlledWorkspace
(
requestAttributes
.
GetNamespace
());
err
!=
nil
{
if
workspace
,
err
=
r
.
am
.
GetNamespaceControlledWorkspace
(
requestAttributes
.
GetNamespace
());
err
!=
nil
{
if
!
visitor
(
nil
,
""
,
nil
,
err
)
{
return
}
}
}
else
if
requestAttributes
.
GetResourceScope
()
==
request
.
DevOpsScope
{
if
workspace
,
err
=
r
.
am
.
GetDevOpsControlledWorkspace
(
requestAttributes
.
GetDevOps
());
err
!=
nil
{
if
!
visitor
(
nil
,
""
,
nil
,
err
)
{
return
}
...
...
@@ -279,19 +289,33 @@ func (r *RBACAuthorizer) visitRulesFor(requestAttributes authorizer.Attributes,
}
}
if
requestAttributes
.
GetResourceScope
()
==
request
.
NamespaceScope
{
if
roleBindings
,
err
:=
r
.
am
.
ListRoleBindings
(
""
,
requestAttributes
.
GetNamespace
());
err
!=
nil
{
if
requestAttributes
.
GetResourceScope
()
==
request
.
NamespaceScope
||
requestAttributes
.
GetResourceScope
()
==
request
.
DevOpsScope
{
namespace
:=
requestAttributes
.
GetNamespace
()
// list devops role binding
if
requestAttributes
.
GetResourceScope
()
==
request
.
DevOpsScope
{
if
relatedNamespace
,
err
:=
r
.
am
.
GetDevOpsRelatedNamespace
(
requestAttributes
.
GetDevOps
());
err
!=
nil
{
if
!
visitor
(
nil
,
""
,
nil
,
err
)
{
return
}
}
else
{
namespace
=
relatedNamespace
}
}
if
roleBindings
,
err
:=
r
.
am
.
ListRoleBindings
(
""
,
namespace
);
err
!=
nil
{
if
!
visitor
(
nil
,
""
,
nil
,
err
)
{
return
}
}
else
{
sourceDescriber
:=
&
roleBindingDescriber
{}
for
_
,
roleBinding
:=
range
roleBindings
{
subjectIndex
,
applies
:=
appliesTo
(
requestAttributes
.
GetUser
(),
roleBinding
.
Subjects
,
requestAttributes
.
GetNamespace
()
)
subjectIndex
,
applies
:=
appliesTo
(
requestAttributes
.
GetUser
(),
roleBinding
.
Subjects
,
namespace
)
if
!
applies
{
continue
}
regoPolicy
,
rules
,
err
:=
r
.
am
.
GetRoleReferenceRules
(
roleBinding
.
RoleRef
,
requestAttributes
.
GetNamespace
()
)
regoPolicy
,
rules
,
err
:=
r
.
am
.
GetRoleReferenceRules
(
roleBinding
.
RoleRef
,
namespace
)
if
err
!=
nil
{
visitor
(
nil
,
""
,
nil
,
err
)
continue
...
...
pkg/apiserver/filters/authorization.go
浏览文件 @
659316da
...
...
@@ -82,12 +82,12 @@ func getAuthorizerAttributes(ctx context.Context) (authorizer.Attributes, error)
attribs
.
Cluster
=
requestInfo
.
Cluster
attribs
.
Workspace
=
requestInfo
.
Workspace
attribs
.
KubernetesRequest
=
requestInfo
.
IsKubernetesRequest
attribs
.
APIGroup
=
requestInfo
.
APIGroup
attribs
.
APIVersion
=
requestInfo
.
APIVersion
attribs
.
Resource
=
requestInfo
.
Resource
attribs
.
Subresource
=
requestInfo
.
Subresource
attribs
.
Namespace
=
requestInfo
.
Namespace
attribs
.
DevOps
=
requestInfo
.
DevOps
attribs
.
Name
=
requestInfo
.
Name
return
&
attribs
,
nil
...
...
pkg/apiserver/request/requestinfo.go
浏览文件 @
659316da
...
...
@@ -69,6 +69,9 @@ type RequestInfo struct {
// Cluster of requested resource, this is empty in single-cluster environment
Cluster
string
// DevOps project of requested resource
DevOps
string
// Scope of requested resource.
ResourceScope
string
}
...
...
@@ -195,15 +198,6 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
}
}
selector
:=
req
.
URL
.
Query
()
.
Get
(
"labelSelector"
)
// URL forms: /api/v1/watch/namespaces?labelSelector=kubesphere.io/workspace=system-workspace
if
strings
.
HasPrefix
(
selector
,
workspaceSelectorPrefix
)
{
workspace
:=
strings
.
TrimPrefix
(
selector
,
workspaceSelectorPrefix
)
// URL forms: /api/v1/watch/namespaces?labelSelector=kubesphere.io/workspace==system-workspace
workspace
=
strings
.
TrimPrefix
(
workspace
,
"="
)
requestInfo
.
Workspace
=
workspace
}
// URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
if
currentParts
[
0
]
==
"namespaces"
{
if
len
(
currentParts
)
>
1
{
...
...
@@ -215,8 +209,19 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
currentParts
=
currentParts
[
2
:
]
}
}
}
else
if
currentParts
[
0
]
==
"devops"
{
if
len
(
currentParts
)
>
1
{
requestInfo
.
DevOps
=
currentParts
[
1
]
// if there is another step after the devops name
// move currentParts to include it as a resource in its own right
if
len
(
currentParts
)
>
2
{
currentParts
=
currentParts
[
2
:
]
}
}
}
else
{
requestInfo
.
Namespace
=
metav1
.
NamespaceNone
requestInfo
.
DevOps
=
metav1
.
NamespaceNone
}
// parsing successful, so we now know the proper value for .Parts
...
...
@@ -260,6 +265,15 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
requestInfo
.
Verb
=
"list"
}
// URL forms: /api/v1/watch/namespaces?labelSelector=kubesphere.io/workspace=system-workspace
if
requestInfo
.
Verb
==
"watch"
{
selector
:=
req
.
URL
.
Query
()
.
Get
(
"labelSelector"
)
if
strings
.
HasPrefix
(
selector
,
workspaceSelectorPrefix
)
{
workspace
:=
strings
.
TrimPrefix
(
selector
,
workspaceSelectorPrefix
)
requestInfo
.
Workspace
=
workspace
}
}
if
opts
.
FieldSelector
!=
nil
{
if
name
,
ok
:=
opts
.
FieldSelector
.
RequiresExactMatch
(
"metadata.name"
);
ok
{
if
len
(
path
.
IsValidPathSegmentName
(
name
))
==
0
{
...
...
@@ -306,6 +320,7 @@ const (
ClusterScope
=
"Cluster"
WorkspaceScope
=
"Workspace"
NamespaceScope
=
"Namespace"
DevOpsScope
=
"DevOps"
workspaceSelectorPrefix
=
constants
.
WorkspaceLabelKey
+
"="
)
...
...
@@ -318,6 +333,10 @@ func (r *RequestInfoFactory) resolveResourceScope(request RequestInfo) string {
return
NamespaceScope
}
if
request
.
DevOps
!=
""
{
return
DevOpsScope
}
if
request
.
Workspace
!=
""
{
return
WorkspaceScope
}
...
...
pkg/controller/devopsproject/devopsproject_controller.go
浏览文件 @
659316da
...
...
@@ -18,6 +18,8 @@ import (
"k8s.io/klog"
devopsv1alpha3
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
tenantv1alpha1informers
"kubesphere.io/kubesphere/pkg/client/informers/externalversions/tenant/v1alpha1"
tenantv1alpha1listers
"kubesphere.io/kubesphere/pkg/client/listers/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
devopsClient
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
...
...
@@ -48,6 +50,9 @@ type Controller struct {
namespaceLister
corev1lister
.
NamespaceLister
namespaceSynced
cache
.
InformerSynced
workspaceLister
tenantv1alpha1listers
.
WorkspaceLister
workspaceSynced
cache
.
InformerSynced
workqueue
workqueue
.
RateLimitingInterface
workerLoopPeriod
time
.
Duration
...
...
@@ -59,7 +64,8 @@ func NewController(client clientset.Interface,
kubesphereClient
kubesphereclient
.
Interface
,
devopsClinet
devopsClient
.
Interface
,
namespaceInformer
corev1informer
.
NamespaceInformer
,
devopsInformer
devopsinformers
.
DevOpsProjectInformer
)
*
Controller
{
devopsInformer
devopsinformers
.
DevOpsProjectInformer
,
workspaceInformer
tenantv1alpha1informers
.
WorkspaceInformer
)
*
Controller
{
broadcaster
:=
record
.
NewBroadcaster
()
broadcaster
.
StartLogging
(
func
(
format
string
,
args
...
interface
{})
{
...
...
@@ -77,6 +83,8 @@ func NewController(client clientset.Interface,
devOpsProjectSynced
:
devopsInformer
.
Informer
()
.
HasSynced
,
namespaceLister
:
namespaceInformer
.
Lister
(),
namespaceSynced
:
namespaceInformer
.
Informer
()
.
HasSynced
,
workspaceLister
:
workspaceInformer
.
Lister
(),
workspaceSynced
:
workspaceInformer
.
Informer
()
.
HasSynced
,
workerLoopPeriod
:
time
.
Second
,
}
...
...
@@ -163,7 +171,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
klog
.
Info
(
"starting devops project controller"
)
defer
klog
.
Info
(
"shutting down devops project controller"
)
if
!
cache
.
WaitForCacheSync
(
stopCh
,
c
.
devOpsProjectSynced
)
{
if
!
cache
.
WaitForCacheSync
(
stopCh
,
c
.
devOpsProjectSynced
,
c
.
devOpsProjectSynced
,
c
.
workspaceSynced
)
{
return
fmt
.
Errorf
(
"failed to wait for caches to sync"
)
}
...
...
@@ -273,12 +281,18 @@ func (c *Controller) syncHandler(key string) error {
}
if
!
reflect
.
DeepEqual
(
copyProject
,
project
)
{
_
,
err
:
=
c
.
kubesphereClient
.
DevopsV1alpha3
()
.
DevOpsProjects
()
.
Update
(
copyProject
)
copyProject
,
err
=
c
.
kubesphereClient
.
DevopsV1alpha3
()
.
DevOpsProjects
()
.
Update
(
copyProject
)
if
err
!=
nil
{
klog
.
V
(
8
)
.
Info
(
err
,
fmt
.
Sprintf
(
"failed to update ns %s "
,
key
))
return
err
}
}
if
copyProject
,
err
=
c
.
bindWorkspace
(
copyProject
);
err
!=
nil
{
klog
.
Error
(
err
)
return
err
}
// Check project exists, otherwise we will create it.
_
,
err
:=
c
.
devopsClient
.
GetDevOpsProject
(
copyProject
.
Status
.
AdminNamespace
)
if
err
!=
nil
{
...
...
@@ -312,6 +326,38 @@ func (c *Controller) syncHandler(key string) error {
return
nil
}
func
(
c
*
Controller
)
bindWorkspace
(
project
*
devopsv1alpha3
.
DevOpsProject
)
(
*
devopsv1alpha3
.
DevOpsProject
,
error
)
{
workspaceName
:=
project
.
Labels
[
constants
.
WorkspaceLabelKey
]
if
workspaceName
==
""
{
return
project
,
nil
}
workspace
,
err
:=
c
.
workspaceLister
.
Get
(
workspaceName
)
if
err
!=
nil
{
// skip if workspace not found
if
errors
.
IsNotFound
(
err
)
{
return
project
,
nil
}
klog
.
Error
(
err
)
return
nil
,
err
}
if
!
metav1
.
IsControlledBy
(
project
,
workspace
)
{
project
.
OwnerReferences
=
nil
if
err
:=
controllerutil
.
SetControllerReference
(
workspace
,
project
,
scheme
.
Scheme
);
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
return
c
.
kubesphereClient
.
DevopsV1alpha3
()
.
DevOpsProjects
()
.
Update
(
project
)
}
return
project
,
nil
}
func
(
c
*
Controller
)
deleteDevOpsProjectInDevOps
(
project
*
devopsv1alpha3
.
DevOpsProject
)
error
{
err
:=
c
.
devopsClient
.
DeleteDevOpsProject
(
project
.
Status
.
AdminNamespace
)
...
...
@@ -330,9 +376,16 @@ func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject)
},
ObjectMeta
:
metav1
.
ObjectMeta
{
GenerateName
:
project
.
Name
,
Labels
:
map
[
string
]
string
{
constants
.
DevOpsProjectLabelKey
:
project
.
Name
},
Labels
:
map
[
string
]
string
{
constants
.
DevOpsProjectLabelKey
:
project
.
Name
,
},
},
}
if
creator
:=
project
.
Annotations
[
constants
.
CreatorAnnotationKey
];
creator
!=
""
{
ns
.
Annotations
=
map
[
string
]
string
{
constants
.
CreatorAnnotationKey
:
creator
}
}
controllerutil
.
SetControllerReference
(
project
,
ns
,
scheme
.
Scheme
)
return
ns
}
pkg/controller/devopsproject/devopsproject_controller_test.go
浏览文件 @
659316da
...
...
@@ -120,8 +120,10 @@ func (f *fixture) newController() (*Controller, informers.SharedInformerFactory,
k8sI
:=
kubeinformers
.
NewSharedInformerFactory
(
f
.
kubeclient
,
noResyncPeriodFunc
())
dI
:=
fakeDevOps
.
New
(
f
.
initDevOpsProject
...
)
c
:=
NewController
(
f
.
kubeclient
,
f
.
client
,
dI
,
k8sI
.
Core
()
.
V1
()
.
Namespaces
(),
i
.
Devops
()
.
V1alpha3
()
.
DevOpsProjects
())
c
:=
NewController
(
f
.
kubeclient
,
f
.
client
,
dI
,
k8sI
.
Core
()
.
V1
()
.
Namespaces
(),
i
.
Devops
()
.
V1alpha3
()
.
DevOpsProjects
(),
i
.
Tenant
()
.
V1alpha1
()
.
Workspaces
())
c
.
devOpsProjectSynced
=
alwaysReady
c
.
eventRecorder
=
&
record
.
FakeRecorder
{}
...
...
@@ -251,7 +253,9 @@ func filterInformerActions(actions []core.Action) []core.Action {
(
action
.
Matches
(
"list"
,
devopsprojects
.
ResourcePluralDevOpsProject
)
||
action
.
Matches
(
"watch"
,
devopsprojects
.
ResourcePluralDevOpsProject
)
||
action
.
Matches
(
"list"
,
"namespaces"
)
||
action
.
Matches
(
"watch"
,
"namespaces"
))
{
action
.
Matches
(
"watch"
,
"namespaces"
)
||
action
.
Matches
(
"watch"
,
"workspaces"
)
||
action
.
Matches
(
"list"
,
"workspaces"
))
{
continue
}
ret
=
append
(
ret
,
action
)
...
...
pkg/controller/globalrolebinding/globalrolebinding_controller.go
浏览文件 @
659316da
...
...
@@ -229,17 +229,16 @@ func (c *Controller) reconcile(key string) error {
}
if
globalRoleBinding
.
RoleRef
.
Name
==
iamv1alpha2
.
PlatformAdmin
{
if
err
:=
c
.
relateToClusterAdmin
(
globalRoleBinding
);
err
!=
nil
{
if
err
:=
c
.
assignClusterAdminRole
(
globalRoleBinding
);
err
!=
nil
{
klog
.
Error
(
err
)
return
err
}
if
c
.
devopsClient
!=
nil
{
username
:=
findExpectUsername
(
globalRoleBinding
)
err
=
c
.
devopsClient
.
AssignGlobalRole
(
modeldevops
.
JenkinsAdminRoleName
,
username
)
if
err
!=
nil
{
klog
.
Errorf
(
"%+v"
,
err
)
return
err
}
}
if
c
.
devopsClient
!=
nil
{
if
err
:=
c
.
assignDevOpsAdminRole
(
globalRoleBinding
);
err
!=
nil
{
klog
.
Error
(
err
)
return
err
}
}
...
...
@@ -299,11 +298,9 @@ func (c *Controller) multiClusterSync(globalRoleBinding *iamv1alpha2.GlobalRoleB
return
nil
}
func
(
c
*
Controller
)
relateToClusterAdmin
(
globalRoleBinding
*
iamv1alpha2
.
GlobalRoleBinding
)
error
{
func
(
c
*
Controller
)
assignClusterAdminRole
(
globalRoleBinding
*
iamv1alpha2
.
GlobalRoleBinding
)
error
{
username
:=
findExpectUsername
(
globalRoleBinding
)
// unexpected
if
username
==
""
{
return
nil
}
...
...
@@ -436,6 +433,16 @@ func (c *Controller) ensureNotControlledByKubefed(globalRoleBinding *iamv1alpha2
return
nil
}
func
(
c
*
Controller
)
assignDevOpsAdminRole
(
globalRoleBinding
*
iamv1alpha2
.
GlobalRoleBinding
)
error
{
if
username
:=
findExpectUsername
(
globalRoleBinding
);
username
!=
""
{
if
err
:=
c
.
devopsClient
.
AssignGlobalRole
(
modeldevops
.
JenkinsAdminRoleName
,
username
);
err
!=
nil
{
klog
.
Errorf
(
"%+v"
,
err
)
return
err
}
}
return
nil
}
func
ensureSubjectAPIVersionIsValid
(
subjects
[]
rbacv1
.
Subject
)
[]
rbacv1
.
Subject
{
validSubjects
:=
make
([]
rbacv1
.
Subject
,
0
)
for
_
,
subject
:=
range
subjects
{
...
...
pkg/kapis/iam/v1alpha2/handler.go
浏览文件 @
659316da
...
...
@@ -5,8 +5,6 @@ import (
"github.com/emicklei/go-restful"
rbacv1
"k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
...
...
@@ -1079,7 +1077,7 @@ func (h *iamHandler) resolveNamespace(namespace string, devops string) (string,
if
devops
==
""
{
return
namespace
,
nil
}
return
h
.
am
.
Get
Controll
edNamespace
(
devops
)
return
h
.
am
.
Get
DevOpsRelat
edNamespace
(
devops
)
}
func
(
h
*
iamHandler
)
PatchWorkspaceRole
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
...
...
@@ -1213,18 +1211,7 @@ func (h *iamHandler) updateGlobalRoleBinding(operator user.Info, user *iamv1alph
func
(
h
*
iamHandler
)
ListUserLoginRecords
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
username
:=
request
.
PathParameter
(
"user"
)
queryParam
:=
query
.
ParseQueryParameter
(
request
)
selector
,
_
:=
labels
.
Parse
(
queryParam
.
LabelSelector
)
if
selector
==
nil
{
selector
=
labels
.
NewSelector
()
}
requirement
,
err
:=
labels
.
NewRequirement
(
iamv1alpha2
.
UserReferenceLabel
,
selection
.
Equals
,
[]
string
{
username
})
if
err
!=
nil
{
klog
.
Error
(
err
)
handleError
(
request
,
response
,
err
)
return
}
selector
.
Add
(
*
requirement
)
queryParam
.
LabelSelector
=
selector
.
String
()
queryParam
.
Filters
[
query
.
FieldLabel
]
=
query
.
Value
(
fmt
.
Sprintf
(
"%s=%s"
,
iamv1alpha2
.
UserReferenceLabel
,
username
))
result
,
err
:=
h
.
im
.
ListLoginRecords
(
queryParam
)
if
err
!=
nil
{
klog
.
Error
(
err
)
...
...
pkg/kapis/oauth/handler.go
浏览文件 @
659316da
...
...
@@ -290,6 +290,7 @@ func (h *handler) passwordGrant(username string, password string, req *restful.R
return
default
:
response
.
WriteError
(
http
.
StatusInternalServerError
,
apierrors
.
NewInternalError
(
err
))
return
}
}
...
...
pkg/kapis/tenant/v1alpha2/handler.go
浏览文件 @
659316da
...
...
@@ -101,6 +101,29 @@ func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Respo
resp
.
WriteEntity
(
result
)
}
func
(
h
*
tenantHandler
)
ListDevOpsProjects
(
req
*
restful
.
Request
,
resp
*
restful
.
Response
)
{
user
,
ok
:=
request
.
UserFrom
(
req
.
Request
.
Context
())
queryParam
:=
query
.
ParseQueryParameter
(
req
)
if
!
ok
{
err
:=
fmt
.
Errorf
(
"cannot obtain user info"
)
klog
.
Errorln
(
err
)
api
.
HandleForbidden
(
resp
,
nil
,
err
)
return
}
workspace
:=
req
.
PathParameter
(
"workspace"
)
result
,
err
:=
h
.
tenant
.
ListDevOpsProjects
(
user
,
workspace
,
queryParam
)
if
err
!=
nil
{
api
.
HandleInternalError
(
resp
,
nil
,
err
)
return
}
resp
.
WriteEntity
(
result
)
}
func
(
h
*
tenantHandler
)
CreateNamespace
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
workspace
:=
request
.
PathParameter
(
"workspace"
)
var
namespace
corev1
.
Namespace
...
...
pkg/kapis/tenant/v1alpha2/register.go
浏览文件 @
659316da
...
...
@@ -27,7 +27,6 @@ import (
eventsv1alpha1
"kubesphere.io/kubesphere/pkg/api/events/v1alpha1"
loggingv1alpha2
"kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
tenantv1alpha2
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2"
typesv1beta1
"kubesphere.io/kubesphere/pkg/apis/types/v1beta1"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
kubesphere
"kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/constants"
...
...
@@ -105,31 +104,37 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s
To
(
handler
.
ListNamespaces
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the namespaces for the current user"
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
api
.
ListResult
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/federatednamespaces"
)
.
To
(
handler
.
ListFederatedNamespaces
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the federated namespaces for the current user"
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
typesv1beta1
.
FederatedNamespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
api
.
ListResult
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/workspaces/{workspace}/federatednamespaces"
)
.
To
(
handler
.
ListFederatedNamespaces
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the federated namespaces of the specified workspace for the current user"
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
typesv1beta1
.
FederatedNamespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
api
.
ListResult
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/workspaces/{workspace}/namespaces"
)
.
To
(
handler
.
ListNamespaces
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the namespaces of the specified workspace for the current user"
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
api
.
ListResult
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/workspaces/{workspace}/devops"
)
.
To
(
handler
.
ListDevOpsProjects
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the devops projects of the specified workspace for the current user"
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
api
.
ListResult
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/workspaces/{workspace}/namespaces/{namespace}"
)
.
To
(
handler
.
DescribeNamespace
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"Retrieve namespace details."
)
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
corev1
.
Namespace
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
DELETE
(
"/workspaces/{workspace}/namespaces/{namespace}"
)
.
To
(
handler
.
DeleteNamespace
)
.
...
...
@@ -142,20 +147,20 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Doc
(
"List the namespaces of the specified workspace for the current user"
)
.
Reads
(
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
corev1
.
Namespace
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
PUT
(
"/workspaces/{workspace}/namespaces/{namespace}"
)
.
To
(
handler
.
UpdateNamespace
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Reads
(
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
corev1
.
Namespace
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
PATCH
(
"/workspaces/{workspace}/namespaces/{namespace}"
)
.
To
(
handler
.
PatchNamespace
)
.
Consumes
(
mimePatch
...
)
.
Param
(
ws
.
PathParameter
(
"workspace"
,
"workspace name"
))
.
Reads
(
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
[]
corev1
.
Namespace
{})
.
Returns
(
http
.
StatusOK
,
api
.
StatusOK
,
corev1
.
Namespace
{})
.
Metadata
(
restfulspec
.
KeyOpenAPITags
,
[]
string
{
constants
.
TenantResourcesTag
}))
ws
.
Route
(
ws
.
GET
(
"/events"
)
.
...
...
pkg/models/iam/am/am.go
浏览文件 @
659316da
...
...
@@ -70,8 +70,9 @@ type AccessManagementInterface interface {
RemoveUserFromNamespace
(
username
string
,
namespace
string
)
error
CreateClusterRoleBinding
(
username
string
,
role
string
)
error
RemoveUserFromCluster
(
username
string
)
error
GetControlledNamespace
(
devops
string
)
(
string
,
error
)
GetControlledWorkspace
(
namespace
string
)
(
string
,
error
)
GetDevOpsRelatedNamespace
(
devops
string
)
(
string
,
error
)
GetNamespaceControlledWorkspace
(
namespace
string
)
(
string
,
error
)
GetDevOpsControlledWorkspace
(
devops
string
)
(
string
,
error
)
PatchNamespaceRole
(
namespace
string
,
role
*
rbacv1
.
Role
)
(
*
rbacv1
.
Role
,
error
)
PatchClusterRole
(
clusterRole
*
rbacv1
.
ClusterRole
)
(
*
rbacv1
.
ClusterRole
,
error
)
}
...
...
@@ -279,23 +280,19 @@ func (am *amOperator) ListGlobalRoleBindings(username string) ([]*iamv1alpha2.Gl
}
func
(
am
*
amOperator
)
ListRoleBindings
(
username
,
namespace
string
)
([]
*
rbacv1
.
RoleBinding
,
error
)
{
roleBindings
,
err
:=
am
.
resourceGetter
.
List
(
iamv1alpha2
.
ResourcesPluralRoleBinding
,
namespace
,
query
.
New
())
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
result
:=
make
([]
*
rbacv1
.
RoleBinding
,
0
)
for
_
,
obj
:=
range
roleBindings
.
Items
{
roleBinding
:=
obj
.
(
*
rbacv1
.
RoleBinding
)
if
contains
(
roleBinding
.
Subjects
,
username
)
{
result
=
append
(
result
,
roleBinding
)
}
}
return
result
,
nil
}
...
...
@@ -964,7 +961,7 @@ func (am *amOperator) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
}
return
obj
.
(
*
rbacv1
.
ClusterRole
),
nil
}
func
(
am
*
amOperator
)
Get
Controll
edNamespace
(
devops
string
)
(
string
,
error
)
{
func
(
am
*
amOperator
)
Get
DevOpsRelat
edNamespace
(
devops
string
)
(
string
,
error
)
{
obj
,
err
:=
am
.
resourceGetter
.
Get
(
devopsv1alpha3
.
ResourcePluralDevOpsProject
,
""
,
devops
)
if
err
!=
nil
{
klog
.
Error
(
err
)
...
...
@@ -975,7 +972,17 @@ func (am *amOperator) GetControlledNamespace(devops string) (string, error) {
return
devopsProject
.
Status
.
AdminNamespace
,
nil
}
func
(
am
*
amOperator
)
GetControlledWorkspace
(
namespace
string
)
(
string
,
error
)
{
func
(
am
*
amOperator
)
GetDevOpsControlledWorkspace
(
devops
string
)
(
string
,
error
)
{
obj
,
err
:=
am
.
resourceGetter
.
Get
(
devopsv1alpha3
.
ResourcePluralDevOpsProject
,
""
,
devops
)
if
err
!=
nil
{
klog
.
Error
(
err
)
return
""
,
err
}
devopsProject
:=
obj
.
(
*
devopsv1alpha3
.
DevOpsProject
)
return
devopsProject
.
Labels
[
tenantv1alpha1
.
WorkspaceLabel
],
nil
}
func
(
am
*
amOperator
)
GetNamespaceControlledWorkspace
(
namespace
string
)
(
string
,
error
)
{
obj
,
err
:=
am
.
resourceGetter
.
Get
(
"namespaces"
,
""
,
namespace
)
if
err
!=
nil
{
if
errors
.
IsNotFound
(
err
)
{
...
...
pkg/models/tenant/devops.go
浏览文件 @
659316da
...
...
@@ -17,26 +17,109 @@ limitations under the License.
package
tenant
import
(
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/server/params"
dsClient
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"fmt"
corev1
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
devopsv1alpha3
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
tenantv1alpha1
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/apiserver/request"
"kubesphere.io/kubesphere/pkg/constants"
resources
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type
DevOpsProjectLister
interface
{
ListDevOpsProjects
(
workspace
string
,
conditions
*
params
.
Conditions
,
orderBy
string
,
reverse
bool
,
limit
int
,
offset
int
)
(
*
models
.
PageableResponse
,
error
)
}
func
(
t
*
tenantOperator
)
ListDevOpsProjects
(
user
user
.
Info
,
workspace
string
,
queryParam
*
query
.
Query
)
(
*
api
.
ListResult
,
error
)
{
scope
:=
request
.
ClusterScope
if
workspace
!=
""
{
scope
=
request
.
WorkspaceScope
}
type
devopsProjectLister
struct
{
dsProject
dsClient
.
ProjectOperator
}
listDevOps
:=
authorizer
.
AttributesRecord
{
User
:
user
,
Verb
:
"list"
,
Workspace
:
workspace
,
Resource
:
"devops"
,
ResourceRequest
:
true
,
ResourceScope
:
scope
,
}
func
newProjectLister
(
client
dsClient
.
ProjectOperator
)
DevOpsProjectLister
{
return
&
devopsProjectLister
{
dsProject
:
client
,
decision
,
_
,
err
:=
t
.
authorizer
.
Authorize
(
listDevOps
)
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
}
func
(
o
*
devopsProjectLister
)
ListDevOpsProjects
(
workspace
string
,
conditions
*
params
.
Conditions
,
orderBy
string
,
reverse
bool
,
limit
int
,
offset
int
)
(
*
models
.
PageableResponse
,
error
)
{
//TODO: @runzexia use informer to impl it
return
nil
,
nil
// allowed list devops in the specified scope
if
decision
==
authorizer
.
DecisionAllow
{
// filter by workspace
if
workspace
!=
""
{
queryParam
.
Filters
[
query
.
FieldLabel
]
=
query
.
Value
(
fmt
.
Sprintf
(
"%s=%s"
,
tenantv1alpha1
.
WorkspaceLabel
,
workspace
))
}
result
,
err
:=
t
.
resourceGetter
.
List
(
devopsv1alpha3
.
ResourcePluralDevOpsProject
,
""
,
queryParam
)
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
return
result
,
nil
}
roleBindings
,
err
:=
t
.
am
.
ListRoleBindings
(
user
.
GetName
(),
""
)
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
devopsProjects
:=
make
([]
runtime
.
Object
,
0
)
for
_
,
roleBinding
:=
range
roleBindings
{
obj
,
err
:=
t
.
resourceGetter
.
Get
(
"namespaces"
,
""
,
roleBinding
.
Namespace
)
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
namespace
:=
obj
.
(
*
corev1
.
Namespace
)
controlledDevOpsProject
:=
namespace
.
Labels
[
constants
.
DevOpsProjectLabelKey
]
// skip if not controlled by devops project
if
controlledDevOpsProject
==
""
{
continue
}
devopsProject
,
err
:=
t
.
resourceGetter
.
Get
(
devopsv1alpha3
.
ResourcePluralDevOpsProject
,
""
,
controlledDevOpsProject
)
if
err
!=
nil
{
if
errors
.
IsNotFound
(
err
)
{
klog
.
Warning
(
"orphan devops project found "
,
devopsProject
)
continue
}
klog
.
Error
(
err
)
return
nil
,
err
}
// skip if not controlled by the specified workspace
if
workspace
!=
""
&&
devopsProject
.
(
*
devopsv1alpha3
.
DevOpsProject
)
.
Labels
[
tenantv1alpha1
.
WorkspaceLabel
]
!=
workspace
{
continue
}
if
!
contains
(
devopsProjects
,
devopsProject
)
{
devopsProjects
=
append
(
devopsProjects
,
namespace
)
}
}
result
:=
resources
.
DefaultList
(
devopsProjects
,
queryParam
,
func
(
left
runtime
.
Object
,
right
runtime
.
Object
,
field
query
.
Field
)
bool
{
return
resources
.
DefaultObjectMetaCompare
(
left
.
(
*
devopsv1alpha3
.
DevOpsProject
)
.
ObjectMeta
,
right
.
(
*
devopsv1alpha3
.
DevOpsProject
)
.
ObjectMeta
,
field
)
},
func
(
object
runtime
.
Object
,
filter
query
.
Filter
)
bool
{
devopsProject
:=
object
.
(
*
devopsv1alpha3
.
DevOpsProject
)
.
ObjectMeta
if
workspace
!=
""
{
if
workspaceLabel
,
ok
:=
devopsProject
.
Labels
[
tenantv1alpha1
.
WorkspaceLabel
];
!
ok
||
workspaceLabel
!=
workspace
{
return
false
}
}
return
resources
.
DefaultObjectMetaFilter
(
devopsProject
,
filter
)
})
return
result
,
nil
}
pkg/models/tenant/tenant.go
浏览文件 @
659316da
...
...
@@ -60,6 +60,7 @@ import (
type
Interface
interface
{
ListWorkspaces
(
user
user
.
Info
,
query
*
query
.
Query
)
(
*
api
.
ListResult
,
error
)
ListNamespaces
(
user
user
.
Info
,
workspace
string
,
query
*
query
.
Query
)
(
*
api
.
ListResult
,
error
)
ListDevOpsProjects
(
user
user
.
Info
,
workspace
string
,
query
*
query
.
Query
)
(
*
api
.
ListResult
,
error
)
ListFederatedNamespaces
(
info
user
.
Info
,
workspace
string
,
param
*
query
.
Query
)
(
*
api
.
ListResult
,
error
)
CreateNamespace
(
workspace
string
,
namespace
*
corev1
.
Namespace
)
(
*
corev1
.
Namespace
,
error
)
CreateWorkspace
(
workspace
*
tenantv1alpha2
.
WorkspaceTemplate
)
(
*
tenantv1alpha2
.
WorkspaceTemplate
,
error
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录