improve IAM module

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-05-22 09:35:05 +08:00
parent 0d12529051
commit 8f93266ec0
640 changed files with 50221 additions and 18179 deletions

View File

@@ -73,7 +73,7 @@ type Interface interface {
func ObjectMetaExactlyMath(key, value string, item metav1.ObjectMeta) bool {
switch key {
case Name:
names := strings.Split(value, "|")
names := strings.Split(value, ",")
if !sliceutil.HasString(names, item.Name) {
return false
}

View File

@@ -40,13 +40,13 @@ func (d *applicationsGetter) Get(namespace, name string) (runtime.Object, error)
}
func (d *applicationsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := d.informer.App().V1beta1().Applications().Lister().Applications(namespace).List(query.Selector())
applications, err := d.informer.App().V1beta1().Applications().Lister().Applications(namespace).List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, app := range all {
for _, app := range applications {
result = append(result, app)
}

View File

@@ -20,7 +20,11 @@ func New(informers externalversions.SharedInformerFactory) v1alpha3.Interface {
}
func (c clustersGetter) Get(_, name string) (runtime.Object, error) {
return c.informers.Cluster().V1alpha1().Clusters().Lister().Get(name)
cluster, err := c.informers.Cluster().V1alpha1().Clusters().Lister().Get(name)
if err != nil {
return nil, err
}
return c.transform(cluster), nil
}
func (c clustersGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
@@ -30,11 +34,18 @@ func (c clustersGetter) List(_ string, query *query.Query) (*api.ListResult, err
}
var result []runtime.Object
for _, deploy := range clusters {
result = append(result, deploy)
for _, cluster := range clusters {
result = append(result, cluster)
}
return v1alpha3.DefaultList(result, query, c.compare, c.filter), nil
return v1alpha3.DefaultList(result, query, c.compare, c.filter, c.transform), nil
}
func (c clustersGetter) transform(obj runtime.Object) runtime.Object {
in := obj.(*clusterv1alpha1.Cluster)
out := in.DeepCopy()
out.Spec.Connection.KubeConfig = nil
return out
}
func (c clustersGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {

View File

@@ -18,57 +18,70 @@
package clusterrole
import (
"encoding/json"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type rolesGetter struct {
type clusterrolesGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &rolesGetter{sharedInformers: sharedInformers}
return &clusterrolesGetter{sharedInformers: sharedInformers}
}
func (d *rolesGetter) Get(namespace, name string) (runtime.Object, error) {
func (d *clusterrolesGetter) Get(namespace, name string) (runtime.Object, error) {
return d.sharedInformers.Rbac().V1().ClusterRoles().Lister().Get(name)
}
func (d *rolesGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
func (d *clusterrolesGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
var roles []*rbacv1.ClusterRole
var err error
if aggregateTo := query.Filters[iamv1alpha2.AggregateTo]; aggregateTo != "" {
roles, err = d.fetchAggregationRoles(string(aggregateTo))
delete(query.Filters, iamv1alpha2.AggregateTo)
} else {
roles, err = d.sharedInformers.Rbac().V1().ClusterRoles().Lister().List(query.Selector())
}
all, err := d.sharedInformers.Rbac().V1().ClusterRoles().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, clusterrole := range roles {
result = append(result, clusterrole)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *rolesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
func (d *clusterrolesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRole, ok := left.(*rbacv1.ClusterRole)
leftClusterRole, ok := left.(*rbacv1.ClusterRole)
if !ok {
return false
}
rightRole, ok := right.(*rbacv1.ClusterRole)
rightClusterRole, ok := right.(*rbacv1.ClusterRole)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRole.ObjectMeta, rightRole.ObjectMeta, field)
return v1alpha3.DefaultObjectMetaCompare(leftClusterRole.ObjectMeta, rightClusterRole.ObjectMeta, field)
}
func (d *rolesGetter) filter(object runtime.Object, filter query.Filter) bool {
func (d *clusterrolesGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*rbacv1.ClusterRole)
if !ok {
@@ -77,3 +90,38 @@ func (d *rolesGetter) filter(object runtime.Object, filter query.Filter) bool {
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}
func (d *clusterrolesGetter) fetchAggregationRoles(name string) ([]*rbacv1.ClusterRole, error) {
roles := make([]*rbacv1.ClusterRole, 0)
obj, err := d.Get("", name)
if err != nil {
if errors.IsNotFound(err) {
return roles, nil
}
return nil, err
}
if annotation := obj.(*rbacv1.ClusterRole).Annotations[iamv1alpha2.AggregationRolesAnnotation]; annotation != "" {
var roleNames []string
if err = json.Unmarshal([]byte(annotation), &roleNames); err == nil {
for _, roleName := range roleNames {
role, err := d.Get("", roleName)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("invalid aggregation role found: %s, %s", name, roleName)
continue
}
return nil, err
}
roles = append(roles, role.(*rbacv1.ClusterRole))
}
}
}
return roles, nil
}

View File

@@ -0,0 +1,80 @@
/*
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 clusterrolebinding
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type clusterrolebindingsGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &clusterrolebindingsGetter{sharedInformers: sharedInformers}
}
func (d *clusterrolebindingsGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Rbac().V1().ClusterRoleBindings().Lister().Get(name)
}
func (d *clusterrolebindingsGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
roleBindings, err := d.sharedInformers.Rbac().V1().ClusterRoleBindings().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, roleBinding := range roleBindings {
result = append(result, roleBinding)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *clusterrolebindingsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRoleBinding, ok := left.(*rbacv1.ClusterRoleBinding)
if !ok {
return false
}
rightRoleBinding, ok := right.(*rbacv1.ClusterRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRoleBinding.ObjectMeta, rightRoleBinding.ObjectMeta, field)
}
func (d *clusterrolebindingsGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*rbacv1.ClusterRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}

View File

@@ -0,0 +1,95 @@
package clusterrolebinding
import (
"github.com/google/go-cmp/cmp"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListRoles(t *testing.T) {
tests := []struct {
description string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: map[query.Field]query.Value{query.FieldName: query.Value("foo2")},
},
&api.ListResult{
Items: []interface{}{
foo2,
},
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
got, err := getter.List("", test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
clusterRoleBindings = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, clusterRoleBinding := range clusterRoleBindings {
informer.Rbac().V1().ClusterRoleBindings().Informer().GetIndexer().Add(clusterRoleBinding)
}
return New(informer)
}

View File

@@ -39,14 +39,14 @@ func (d *configmapsGetter) Get(namespace, name string) (runtime.Object, error) {
}
func (d *configmapsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := d.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(query.Selector())
configmaps, err := d.informer.Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, app := range all {
result = append(result, app)
for _, configmap := range configmaps {
result = append(result, configmap)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
@@ -54,17 +54,17 @@ func (d *configmapsGetter) List(namespace string, query *query.Query) (*api.List
func (d *configmapsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftConfigMap, ok := left.(*corev1.ConfigMap)
leftCM, ok := left.(*corev1.ConfigMap)
if !ok {
return false
}
rightConfigMap, ok := right.(*corev1.ConfigMap)
rightCM, ok := right.(*corev1.ConfigMap)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftConfigMap.ObjectMeta, rightConfigMap.ObjectMeta, field)
return v1alpha3.DefaultObjectMetaCompare(leftCM.ObjectMeta, rightCM.ObjectMeta, field)
}
func (d *configmapsGetter) filter(object runtime.Object, filter query.Filter) bool {

View File

@@ -30,8 +30,8 @@ func (c crdGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
}
var result []runtime.Object
for _, deploy := range crds {
result = append(result, deploy)
for _, crd := range crds {
result = append(result, crd)
}
return v1alpha3.DefaultList(result, query, c.compare, c.filter), nil

View File

@@ -49,14 +49,14 @@ func (d *deploymentsGetter) Get(namespace, name string) (runtime.Object, error)
func (d *deploymentsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
// first retrieves all deployments within given namespace
all, err := d.sharedInformers.Apps().V1().Deployments().Lister().Deployments(namespace).List(query.Selector())
deployments, err := d.sharedInformers.Apps().V1().Deployments().Lister().Deployments(namespace).List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, deployment := range deployments {
result = append(result, deployment)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil

View File

@@ -0,0 +1,57 @@
package devops
import (
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
"kubesphere.io/kubesphere/pkg/apiserver/query"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type devopsGetter struct {
informers ksinformers.SharedInformerFactory
}
func New(ksinformer ksinformers.SharedInformerFactory) v1alpha3.Interface {
return &devopsGetter{informers: ksinformer}
}
func (n devopsGetter) Get(_, name string) (runtime.Object, error) {
return n.informers.Devops().V1alpha3().DevOpsProjects().Lister().Get(name)
}
func (n devopsGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
projects, err := n.informers.Devops().V1alpha3().DevOpsProjects().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, project := range projects {
result = append(result, project)
}
return v1alpha3.DefaultList(result, query, n.compare, n.filter), nil
}
func (n devopsGetter) filter(item runtime.Object, filter query.Filter) bool {
devOpsProject, ok := item.(*devopsv1alpha3.DevOpsProject)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(devOpsProject.ObjectMeta, filter)
}
func (n devopsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftProject, ok := left.(*devopsv1alpha3.DevOpsProject)
if !ok {
return false
}
rightProject, ok := right.(*devopsv1alpha3.DevOpsProject)
if !ok {
return true
}
return v1alpha3.DefaultObjectMetaCompare(leftProject.ObjectMeta, rightProject.ObjectMeta, field)
}

View File

@@ -0,0 +1 @@
package devops

View File

@@ -18,7 +18,10 @@
package globalrole
import (
"encoding/json"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
@@ -40,14 +43,23 @@ func (d *globalrolesGetter) Get(_, name string) (runtime.Object, error) {
func (d *globalrolesGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
all, err := d.sharedInformers.Iam().V1alpha2().GlobalRoles().Lister().List(query.Selector())
var roles []*iamv1alpha2.GlobalRole
var err error
if aggregateTo := query.Filters[iamv1alpha2.AggregateTo]; aggregateTo != "" {
roles, err = d.fetchAggregationRoles(string(aggregateTo))
delete(query.Filters, iamv1alpha2.AggregateTo)
} else {
roles, err = d.sharedInformers.Iam().V1alpha2().GlobalRoles().Lister().List(query.Selector())
}
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, role := range roles {
result = append(result, role)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
@@ -77,3 +89,38 @@ func (d *globalrolesGetter) filter(object runtime.Object, filter query.Filter) b
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}
func (d *globalrolesGetter) fetchAggregationRoles(name string) ([]*iamv1alpha2.GlobalRole, error) {
roles := make([]*iamv1alpha2.GlobalRole, 0)
obj, err := d.Get("", name)
if err != nil {
if errors.IsNotFound(err) {
return roles, nil
}
return nil, err
}
if annotation := obj.(*iamv1alpha2.GlobalRole).Annotations[iamv1alpha2.AggregationRolesAnnotation]; annotation != "" {
var roleNames []string
if err = json.Unmarshal([]byte(annotation), &roleNames); err == nil {
for _, roleName := range roleNames {
role, err := d.Get("", roleName)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("invalid aggregation role found: %s, %s", name, roleName)
continue
}
return nil, err
}
roles = append(roles, role.(*iamv1alpha2.GlobalRole))
}
}
}
return roles, nil
}

View File

@@ -0,0 +1,80 @@
/*
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 globalrolebinding
import (
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type globalrolebindingsGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &globalrolebindingsGetter{sharedInformers: sharedInformers}
}
func (d *globalrolebindingsGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Iam().V1alpha2().GlobalRoleBindings().Lister().Get(name)
}
func (d *globalrolebindingsGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
globalRoleBindings, err := d.sharedInformers.Iam().V1alpha2().GlobalRoleBindings().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, globalRoleBinding := range globalRoleBindings {
result = append(result, globalRoleBinding)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *globalrolebindingsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRoleBinding, ok := left.(*iamv1alpha2.GlobalRoleBinding)
if !ok {
return false
}
rightRoleBinding, ok := right.(*iamv1alpha2.GlobalRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRoleBinding.ObjectMeta, rightRoleBinding.ObjectMeta, field)
}
func (d *globalrolebindingsGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*iamv1alpha2.GlobalRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}

View File

@@ -0,0 +1,95 @@
package globalrolebinding
import (
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListRoles(t *testing.T) {
tests := []struct {
description string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: map[query.Field]query.Value{query.FieldName: query.Value("foo2")},
},
&api.ListResult{
Items: []interface{}{
foo2,
},
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
got, err := getter.List("", test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
globalRoleBindings = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, globalRoleBinding := range globalRoleBindings {
informer.Iam().V1alpha2().GlobalRoleBindings().Informer().GetIndexer().Add(globalRoleBinding)
}
return New(informer)
}

View File

@@ -5,6 +5,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/constants"
"sort"
"strings"
)
@@ -22,7 +23,9 @@ type CompareFunc func(runtime.Object, runtime.Object, query.Field) bool
type FilterFunc func(runtime.Object, query.Filter) bool
func DefaultList(objects []runtime.Object, q *query.Query, compareFunc CompareFunc, filterFunc FilterFunc) *api.ListResult {
type TransformFunc func(runtime.Object) runtime.Object
func DefaultList(objects []runtime.Object, q *query.Query, compareFunc CompareFunc, filterFunc FilterFunc, transformFuncs ...TransformFunc) *api.ListResult {
// selected matched ones
var filtered []runtime.Object
for _, object := range objects {
@@ -35,6 +38,9 @@ func DefaultList(objects []runtime.Object, q *query.Query, compareFunc CompareFu
}
if selected {
for _, transform := range transformFuncs {
object = transform(object)
}
filtered = append(filtered, object)
}
}
@@ -84,6 +90,13 @@ func DefaultObjectMetaCompare(left, right metav1.ObjectMeta, sortBy query.Field)
// Default metadata filter
func DefaultObjectMetaFilter(item metav1.ObjectMeta, filter query.Filter) bool {
switch filter.Field {
case query.FieldNames:
for _, name := range strings.Split(string(filter.Value), ",") {
if item.Name == name || item.Annotations[constants.DisplayNameAnnotationKey] == name {
return true
}
}
return false
// /namespaces?page=1&limit=10&name=default
case query.FieldName:
return strings.Contains(item.Name, string(filter.Value))

View File

@@ -10,19 +10,19 @@ import (
"strings"
)
type namespaceGetter struct {
type namespacesGetter struct {
informers informers.SharedInformerFactory
}
func New(informers informers.SharedInformerFactory) v1alpha3.Interface {
return &namespaceGetter{informers: informers}
return &namespacesGetter{informers: informers}
}
func (n namespaceGetter) Get(_, name string) (runtime.Object, error) {
func (n namespacesGetter) Get(_, name string) (runtime.Object, error) {
return n.informers.Core().V1().Namespaces().Lister().Get(name)
}
func (n namespaceGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
func (n namespacesGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
ns, err := n.informers.Core().V1().Namespaces().Lister().List(query.Selector())
if err != nil {
return nil, err
@@ -36,7 +36,7 @@ func (n namespaceGetter) List(_ string, query *query.Query) (*api.ListResult, er
return v1alpha3.DefaultList(result, query, n.compare, n.filter), nil
}
func (n namespaceGetter) filter(item runtime.Object, filter query.Filter) bool {
func (n namespacesGetter) filter(item runtime.Object, filter query.Filter) bool {
namespace, ok := item.(*v1.Namespace)
if !ok {
return false
@@ -49,7 +49,7 @@ func (n namespaceGetter) filter(item runtime.Object, filter query.Filter) bool {
}
}
func (n namespaceGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
func (n namespacesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftNs, ok := left.(*v1.Namespace)
if !ok {
return false

View File

@@ -47,14 +47,14 @@ func (p *podsGetter) Get(namespace, name string) (runtime.Object, error) {
func (p *podsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := p.informer.Core().V1().Pods().Lister().Pods(namespace).List(query.Selector())
pods, err := p.informer.Core().V1().Pods().Lister().Pods(namespace).List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, app := range all {
result = append(result, app)
for _, pod := range pods {
result = append(result, pod)
}
return v1alpha3.DefaultList(result, query, p.compare, p.filter), nil

View File

@@ -25,28 +25,36 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/api"
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/application"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/cluster"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/clusterrole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/clusterrolebinding"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/configmap"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/customresourcedefinition"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/deployment"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/devops"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/globalrole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/globalrolebinding"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/namespace"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/networkpolicy"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/node"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/persistentvolumeclaim"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/pod"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/role"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/rolebinding"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/user"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/volumesnapshot"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspace"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspacerole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspacerolebinding"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspacetemplate"
)
var ErrResourceNotSupported = errors.New("resource is not supported")
@@ -65,12 +73,18 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
getters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "nodes"}] = node.New(factory.KubernetesSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "app.k8s.io", Version: "v1beta1", Resource: "applications"}] = application.New(factory.ApplicationSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "networkpolicies"}] = networkpolicy.New(factory.KubernetesSharedInformerFactory())
getters[devopsv1alpha3.SchemeGroupVersion.WithResource(devopsv1alpha3.ResourcePluralDevOpsProject)] = devops.New(factory.KubeSphereSharedInformerFactory())
getters[tenantv1alpha1.SchemeGroupVersion.WithResource(tenantv1alpha1.ResourcePluralWorkspace)] = workspace.New(factory.KubeSphereSharedInformerFactory())
getters[tenantv1alpha1.SchemeGroupVersion.WithResource(tenantv1alpha2.ResourcePluralWorkspaceTemplate)] = workspacetemplate.New(factory.KubeSphereSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralGlobalRole)] = globalrole.New(factory.KubeSphereSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralWorkspaceRole)] = workspacerole.New(factory.KubeSphereSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralUser)] = user.New(factory.KubeSphereSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource("roles")] = role.New(factory.KubernetesSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource("clusterroles")] = clusterrole.New(factory.KubernetesSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralUser)] = user.New(factory.KubeSphereSharedInformerFactory(), factory.KubernetesSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralGlobalRoleBinding)] = globalrolebinding.New(factory.KubeSphereSharedInformerFactory())
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralWorkspaceRoleBinding)] = workspacerolebinding.New(factory.KubeSphereSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralRole)] = role.New(factory.KubernetesSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRole)] = clusterrole.New(factory.KubernetesSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralRoleBinding)] = rolebinding.New(factory.KubernetesSharedInformerFactory())
getters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralClusterRoleBinding)] = clusterrolebinding.New(factory.KubernetesSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaims"}] = persistentvolumeclaim.New(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory())
getters[snapshotv1beta1.SchemeGroupVersion.WithResource("volumesnapshots")] = volumesnapshot.New(factory.SnapshotSharedInformerFactory())
getters[schema.GroupVersionResource{Group: "cluster.kubesphere.io", Version: "v1alpha1", Resource: "clusters"}] = cluster.New(factory.KubeSphereSharedInformerFactory())

View File

@@ -18,10 +18,14 @@
package role
import (
"encoding/json"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
@@ -39,15 +43,24 @@ func (d *rolesGetter) Get(namespace, name string) (runtime.Object, error) {
}
func (d *rolesGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
all, err := d.sharedInformers.Rbac().V1().Roles().Lister().Roles(namespace).List(query.Selector())
var roles []*rbacv1.Role
var err error
if aggregateTo := query.Filters[iamv1alpha2.AggregateTo]; aggregateTo != "" {
roles, err = d.fetchAggregationRoles(namespace, string(aggregateTo))
delete(query.Filters, iamv1alpha2.AggregateTo)
} else {
roles, err = d.sharedInformers.Rbac().V1().Roles().Lister().Roles(namespace).List(query.Selector())
}
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, role := range roles {
result = append(result, role)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
@@ -77,3 +90,38 @@ func (d *rolesGetter) filter(object runtime.Object, filter query.Filter) bool {
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}
func (d *rolesGetter) fetchAggregationRoles(namespace, name string) ([]*rbacv1.Role, error) {
roles := make([]*rbacv1.Role, 0)
obj, err := d.Get(namespace, name)
if err != nil {
if errors.IsNotFound(err) {
return roles, nil
}
return nil, err
}
if annotation := obj.(*rbacv1.Role).Annotations[iamv1alpha2.AggregationRolesAnnotation]; annotation != "" {
var roleNames []string
if err = json.Unmarshal([]byte(annotation), &roleNames); err == nil {
for _, roleName := range roleNames {
role, err := d.Get("", roleName)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("invalid aggregation role found: %s, %s", name, roleName)
continue
}
return nil, err
}
roles = append(roles, role.(*rbacv1.Role))
}
}
}
return roles, nil
}

View File

@@ -0,0 +1,80 @@
/*
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 rolebinding
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/informers"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type rolebindingsGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &rolebindingsGetter{sharedInformers: sharedInformers}
}
func (d *rolebindingsGetter) Get(namespace, name string) (runtime.Object, error) {
return d.sharedInformers.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).Get(name)
}
func (d *rolebindingsGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
roleBindings, err := d.sharedInformers.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, roleBinding := range roleBindings {
result = append(result, roleBinding)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *rolebindingsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRoleBinding, ok := left.(*rbacv1.RoleBinding)
if !ok {
return false
}
rightRoleBinding, ok := right.(*rbacv1.RoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRoleBinding.ObjectMeta, rightRoleBinding.ObjectMeta, field)
}
func (d *rolebindingsGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*rbacv1.RoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}

View File

@@ -0,0 +1,97 @@
package rolebinding
import (
"github.com/google/go-cmp/cmp"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListRoles(t *testing.T) {
tests := []struct {
description string
namespace string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
"bar",
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: map[query.Field]query.Value{query.FieldName: query.Value("foo2")},
},
&api.ListResult{
Items: []interface{}{
foo2,
},
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
got, err := getter.List(test.namespace, test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
roleBindings = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, roleBinding := range roleBindings {
informer.Rbac().V1().RoleBindings().Informer().GetIndexer().Add(roleBinding)
}
return New(informer)
}

View File

@@ -18,36 +18,66 @@
package user
import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
k8sinformers "k8s.io/client-go/informers"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/query"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type usersGetter struct {
sharedInformers informers.SharedInformerFactory
ksInformer ksinformers.SharedInformerFactory
k8sInformer k8sinformers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &usersGetter{sharedInformers: sharedInformers}
func New(ksinformer ksinformers.SharedInformerFactory, k8sinformer k8sinformers.SharedInformerFactory) v1alpha3.Interface {
return &usersGetter{ksInformer: ksinformer, k8sInformer: k8sinformer}
}
func (d *usersGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Iam().V1alpha2().Users().Lister().Get(name)
return d.ksInformer.Iam().V1alpha2().Users().Lister().Get(name)
}
func (d *usersGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
all, err := d.sharedInformers.Iam().V1alpha2().Users().Lister().List(query.Selector())
var users []*iamv1alpha2.User
var err error
if namespace := query.Filters[iamv1alpha2.ScopeNamespace]; namespace != "" {
role := query.Filters[iamv1alpha2.ResourcesSingularRole]
users, err = d.listAllUsersInNamespace(string(namespace), string(role))
delete(query.Filters, iamv1alpha2.ScopeNamespace)
delete(query.Filters, iamv1alpha2.ResourcesSingularRole)
} else if workspace := query.Filters[iamv1alpha2.ScopeWorkspace]; workspace != "" {
workspaceRole := query.Filters[iamv1alpha2.ResourcesSingularWorkspaceRole]
users, err = d.listAllUsersInWorkspace(string(workspace), string(workspaceRole))
delete(query.Filters, iamv1alpha2.ScopeWorkspace)
delete(query.Filters, iamv1alpha2.ResourcesSingularWorkspaceRole)
} else if cluster := query.Filters[iamv1alpha2.ScopeCluster]; cluster == iamv1alpha2.LocalCluster {
clusterRole := query.Filters[iamv1alpha2.ResourcesSingularClusterRole]
users, err = d.listAllUsersInCluster(string(clusterRole))
delete(query.Filters, iamv1alpha2.ScopeCluster)
delete(query.Filters, iamv1alpha2.ResourcesSingularClusterRole)
} else if globalRole := query.Filters[iamv1alpha2.ResourcesSingularGlobalRole]; globalRole != "" {
users, err = d.listAllUsersByGlobalRole(string(globalRole))
delete(query.Filters, iamv1alpha2.ResourcesSingularGlobalRole)
} else {
users, err = d.ksInformer.Iam().V1alpha2().Users().Lister().List(query.Selector())
}
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, user := range users {
result = append(result, user)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
@@ -55,25 +85,231 @@ func (d *usersGetter) List(_ string, query *query.Query) (*api.ListResult, error
func (d *usersGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRole, ok := left.(*iamv1alpha2.User)
leftUser, ok := left.(*iamv1alpha2.User)
if !ok {
return false
}
rightRole, ok := right.(*iamv1alpha2.User)
rightUser, ok := right.(*iamv1alpha2.User)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRole.ObjectMeta, rightRole.ObjectMeta, field)
return v1alpha3.DefaultObjectMetaCompare(leftUser.ObjectMeta, rightUser.ObjectMeta, field)
}
func (d *usersGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*iamv1alpha2.User)
user, ok := object.(*iamv1alpha2.User)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
switch filter.Field {
case iamv1alpha2.FieldEmail:
return user.Spec.Email == string(filter.Value)
default:
return v1alpha3.DefaultObjectMetaFilter(user.ObjectMeta, filter)
}
}
func (d *usersGetter) listAllUsersInWorkspace(workspace, role string) ([]*iamv1alpha2.User, error) {
var users []*iamv1alpha2.User
var err error
workspaceRoleBindings, err := d.ksInformer.Iam().V1alpha2().
WorkspaceRoleBindings().Lister().List(labels.SelectorFromValidatedSet(labels.Set{tenantv1alpha1.WorkspaceLabel: workspace}))
if err != nil {
klog.Error(err)
return nil, err
}
for _, roleBinding := range workspaceRoleBindings {
if role != "" && roleBinding.RoleRef.Name != role {
continue
}
for _, subject := range roleBinding.Subjects {
if subject.Kind == iamv1alpha2.ResourceKindUser {
if contains(users, subject.Name) {
klog.Warningf("conflict role binding found: %s, username:%s", roleBinding.ObjectMeta.String(), subject.Name)
continue
}
obj, err := d.Get("", subject.Name)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("orphan subject: %s", subject.String())
continue
}
klog.Error(err)
return nil, err
}
user := obj.(*iamv1alpha2.User)
user = user.DeepCopy()
if user.Annotations == nil {
user.Annotations = make(map[string]string, 0)
}
user.Annotations[iamv1alpha2.WorkspaceRoleAnnotation] = roleBinding.RoleRef.Name
users = append(users, user)
}
}
}
return users, nil
}
func (d *usersGetter) listAllUsersInNamespace(namespace, role string) ([]*iamv1alpha2.User, error) {
var users []*iamv1alpha2.User
var err error
roleBindings, err := d.k8sInformer.Rbac().V1().
RoleBindings().Lister().RoleBindings(namespace).List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
for _, roleBinding := range roleBindings {
if role != "" && roleBinding.RoleRef.Name != role {
continue
}
for _, subject := range roleBinding.Subjects {
if subject.Kind == iamv1alpha2.ResourceKindUser {
if contains(users, subject.Name) {
klog.Warningf("conflict role binding found: %s, username:%s", roleBinding.ObjectMeta.String(), subject.Name)
continue
}
obj, err := d.Get("", subject.Name)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("orphan subject: %s", subject.String())
continue
}
klog.Error(err)
return nil, err
}
user := obj.(*iamv1alpha2.User)
user = user.DeepCopy()
if user.Annotations == nil {
user.Annotations = make(map[string]string, 0)
}
user.Annotations[iamv1alpha2.RoleAnnotation] = roleBinding.RoleRef.Name
users = append(users, user)
}
}
}
return users, nil
}
func (d *usersGetter) listAllUsersByGlobalRole(globalRole string) ([]*iamv1alpha2.User, error) {
var users []*iamv1alpha2.User
var err error
globalRoleBindings, err := d.ksInformer.Iam().V1alpha2().
GlobalRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
for _, roleBinding := range globalRoleBindings {
if roleBinding.RoleRef.Name != globalRole {
continue
}
for _, subject := range roleBinding.Subjects {
if subject.Kind == iamv1alpha2.ResourceKindUser {
if contains(users, subject.Name) {
klog.Warningf("conflict role binding found: %s, username:%s", roleBinding.ObjectMeta.String(), subject.Name)
continue
}
obj, err := d.Get("", subject.Name)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("orphan subject: %s", subject.String())
continue
}
klog.Error(err)
return nil, err
}
user := obj.(*iamv1alpha2.User)
user = user.DeepCopy()
if user.Annotations == nil {
user.Annotations = make(map[string]string, 0)
}
user.Annotations[iamv1alpha2.GlobalRoleAnnotation] = roleBinding.RoleRef.Name
users = append(users, user)
}
}
}
return users, nil
}
func (d *usersGetter) listAllUsersInCluster(clusterRole string) ([]*iamv1alpha2.User, error) {
var users []*iamv1alpha2.User
var err error
roleBindings, err := d.k8sInformer.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
for _, roleBinding := range roleBindings {
if clusterRole != "" && roleBinding.RoleRef.Name != clusterRole {
continue
}
for _, subject := range roleBinding.Subjects {
if subject.Kind == iamv1alpha2.ResourceKindUser {
if contains(users, subject.Name) {
klog.Warningf("conflict role binding found: %s, username:%s", roleBinding.ObjectMeta.String(), subject.Name)
continue
}
obj, err := d.Get("", subject.Name)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("orphan subject: %s", subject.String())
continue
}
klog.Error(err)
return nil, err
}
user := obj.(*iamv1alpha2.User)
user = user.DeepCopy()
if user.Annotations == nil {
user.Annotations = make(map[string]string, 0)
}
user.Annotations[iamv1alpha2.ClusterRoleAnnotation] = roleBinding.RoleRef.Name
users = append(users, user)
}
}
}
return users, nil
}
func contains(users []*iamv1alpha2.User, username string) bool {
for _, user := range users {
if user.Name == username {
return true
}
}
return false
}

View File

@@ -90,5 +90,5 @@ func prepare() v1alpha3.Interface {
for _, user := range users {
informer.Iam().V1alpha2().Users().Informer().GetIndexer().Add(user)
}
return New(informer)
return New(informer, nil)
}

View File

@@ -40,14 +40,14 @@ func (d *workspaceGetter) Get(_, name string) (runtime.Object, error) {
func (d *workspaceGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
all, err := d.sharedInformers.Tenant().V1alpha1().Workspaces().Lister().List(query.Selector())
workspaces, err := d.sharedInformers.Tenant().V1alpha1().Workspaces().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, workspace := range workspaces {
result = append(result, workspace)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
@@ -55,17 +55,17 @@ func (d *workspaceGetter) List(_ string, query *query.Query) (*api.ListResult, e
func (d *workspaceGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRole, ok := left.(*tenantv1alpha1.Workspace)
leftWorkspace, ok := left.(*tenantv1alpha1.Workspace)
if !ok {
return false
}
rightRole, ok := right.(*tenantv1alpha1.Workspace)
rightWorkspace, ok := right.(*tenantv1alpha1.Workspace)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRole.ObjectMeta, rightRole.ObjectMeta, field)
return v1alpha3.DefaultObjectMetaCompare(leftWorkspace.ObjectMeta, rightWorkspace.ObjectMeta, field)
}
func (d *workspaceGetter) filter(object runtime.Object, filter query.Filter) bool {

View File

@@ -18,9 +18,13 @@
package workspacerole
import (
"encoding/json"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/query"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
@@ -38,19 +42,28 @@ func (d *workspacerolesGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Iam().V1alpha2().WorkspaceRoles().Lister().Get(name)
}
func (d *workspacerolesGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
func (d *workspacerolesGetter) List(_ string, queryParam *query.Query) (*api.ListResult, error) {
var roles []*iamv1alpha2.WorkspaceRole
var err error
if aggregateTo := queryParam.Filters[iamv1alpha2.AggregateTo]; aggregateTo != "" {
roles, err = d.fetchAggregationRoles(string(aggregateTo))
delete(queryParam.Filters, iamv1alpha2.AggregateTo)
} else {
roles, err = d.sharedInformers.Iam().V1alpha2().WorkspaceRoles().Lister().List(queryParam.Selector())
}
all, err := d.sharedInformers.Iam().V1alpha2().WorkspaceRoles().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, deploy := range all {
result = append(result, deploy)
for _, role := range roles {
result = append(result, role)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
return v1alpha3.DefaultList(result, queryParam, d.compare, d.filter), nil
}
func (d *workspacerolesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
@@ -75,5 +88,46 @@ func (d *workspacerolesGetter) filter(object runtime.Object, filter query.Filter
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
switch filter.Field {
case iamv1alpha2.ScopeWorkspace:
return role.Labels[tenantv1alpha1.WorkspaceLabel] == string(filter.Value)
default:
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}
}
func (d *workspacerolesGetter) fetchAggregationRoles(name string) ([]*iamv1alpha2.WorkspaceRole, error) {
roles := make([]*iamv1alpha2.WorkspaceRole, 0)
obj, err := d.Get("", name)
if err != nil {
if errors.IsNotFound(err) {
return roles, nil
}
return nil, err
}
if annotation := obj.(*iamv1alpha2.WorkspaceRole).Annotations[iamv1alpha2.AggregationRolesAnnotation]; annotation != "" {
var roleNames []string
if err = json.Unmarshal([]byte(annotation), &roleNames); err == nil {
for _, roleName := range roleNames {
role, err := d.Get("", roleName)
if err != nil {
if errors.IsNotFound(err) {
klog.Warningf("invalid aggregation role found: %s, %s", name, roleName)
continue
}
return nil, err
}
roles = append(roles, role.(*iamv1alpha2.WorkspaceRole))
}
}
}
return roles, nil
}

View File

@@ -0,0 +1,80 @@
/*
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 workspacerolebinding
import (
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type workspacerolebindingsGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &workspacerolebindingsGetter{sharedInformers: sharedInformers}
}
func (d *workspacerolebindingsGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Iam().V1alpha2().GlobalRoleBindings().Lister().Get(name)
}
func (d *workspacerolebindingsGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
globalRoleBindings, err := d.sharedInformers.Iam().V1alpha2().WorkspaceRoleBindings().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, globalRoleBinding := range globalRoleBindings {
result = append(result, globalRoleBinding)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *workspacerolebindingsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftRoleBinding, ok := left.(*iamv1alpha2.WorkspaceRoleBinding)
if !ok {
return false
}
rightRoleBinding, ok := right.(*iamv1alpha2.WorkspaceRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftRoleBinding.ObjectMeta, rightRoleBinding.ObjectMeta, field)
}
func (d *workspacerolebindingsGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*iamv1alpha2.WorkspaceRoleBinding)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}

View File

@@ -0,0 +1,95 @@
package workspacerolebinding
import (
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListRoles(t *testing.T) {
tests := []struct {
description string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: map[query.Field]query.Value{query.FieldName: query.Value("foo2")},
},
&api.ListResult{
Items: []interface{}{
foo2,
},
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
got, err := getter.List("", test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &iamv1alpha2.WorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: "bar",
},
}
foo2 = &iamv1alpha2.WorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: "bar",
},
}
bar1 = &iamv1alpha2.WorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Namespace: "bar",
},
}
workspaceRoleBindings = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, workspaceRoleBinding := range workspaceRoleBindings {
informer.Iam().V1alpha2().WorkspaceRoleBindings().Informer().GetIndexer().Add(workspaceRoleBinding)
}
return New(informer)
}

View File

@@ -0,0 +1,79 @@
/*
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 workspacetemplate
import (
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/api"
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
)
type workspaceGetter struct {
sharedInformers informers.SharedInformerFactory
}
func New(sharedInformers informers.SharedInformerFactory) v1alpha3.Interface {
return &workspaceGetter{sharedInformers: sharedInformers}
}
func (d *workspaceGetter) Get(_, name string) (runtime.Object, error) {
return d.sharedInformers.Tenant().V1alpha2().WorkspaceTemplates().Lister().Get(name)
}
func (d *workspaceGetter) List(_ string, query *query.Query) (*api.ListResult, error) {
workspaces, err := d.sharedInformers.Tenant().V1alpha2().WorkspaceTemplates().Lister().List(query.Selector())
if err != nil {
return nil, err
}
var result []runtime.Object
for _, workspace := range workspaces {
result = append(result, workspace)
}
return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil
}
func (d *workspaceGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool {
leftWorkspace, ok := left.(*tenantv1alpha2.WorkspaceTemplate)
if !ok {
return false
}
rightWorkspace, ok := right.(*tenantv1alpha2.WorkspaceTemplate)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaCompare(leftWorkspace.ObjectMeta, rightWorkspace.ObjectMeta, field)
}
func (d *workspaceGetter) filter(object runtime.Object, filter query.Filter) bool {
role, ok := object.(*tenantv1alpha2.WorkspaceTemplate)
if !ok {
return false
}
return v1alpha3.DefaultObjectMetaFilter(role.ObjectMeta, filter)
}

View File

@@ -0,0 +1,94 @@
package workspacetemplate
import (
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/api"
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"testing"
)
func TestListWorkspaces(t *testing.T) {
tests := []struct {
description string
namespace string
query *query.Query
expected *api.ListResult
expectedErr error
}{
{
"test name filter",
"bar",
&query.Query{
Pagination: &query.Pagination{
Limit: 1,
Offset: 0,
},
SortBy: query.FieldName,
Ascending: false,
Filters: map[query.Field]query.Value{query.FieldName: query.Value("foo2")},
},
&api.ListResult{
Items: []interface{}{
foo2,
},
TotalItems: 1,
},
nil,
},
}
getter := prepare()
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
got, err := getter.List(test.namespace, test.query)
if test.expectedErr != nil && err != test.expectedErr {
t.Errorf("expected error, got nothing")
} else if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})
}
}
var (
foo1 = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
},
}
foo2 = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
},
}
bar1 = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
},
}
workspaces = []interface{}{foo1, foo2, bar1}
)
func prepare() v1alpha3.Interface {
client := fake.NewSimpleClientset()
informer := informers.NewSharedInformerFactory(client, 0)
for _, workspace := range workspaces {
informer.Tenant().V1alpha2().WorkspaceTemplates().Informer().GetIndexer().Add(workspace)
}
return New(informer)
}