Merge pull request #2191 from wansir/tenant-api

add tenant resource API
This commit is contained in:
KubeSphere CI Bot
2020-06-12 13:20:39 +08:00
committed by GitHub
7 changed files with 711 additions and 510 deletions

View File

@@ -32,7 +32,6 @@ import (
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"net/http"
)
type AccessManagementInterface interface {
@@ -44,16 +43,14 @@ type AccessManagementInterface interface {
ListClusterRoles(query *query.Query) (*api.ListResult, error)
ListWorkspaceRoles(query *query.Query) (*api.ListResult, error)
ListGlobalRoles(query *query.Query) (*api.ListResult, error)
ListGlobalRoleBindings(username string) ([]*iamv1alpha2.GlobalRoleBinding, error)
ListClusterRoleBindings(username string) ([]*rbacv1.ClusterRoleBinding, error)
ListWorkspaceRoleBindings(username, workspace string) ([]*iamv1alpha2.WorkspaceRoleBinding, error)
ListRoleBindings(username, namespace string) ([]*rbacv1.RoleBinding, error)
GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) (string, []rbacv1.PolicyRule, error)
GetGlobalRole(globalRole string) (*iamv1alpha2.GlobalRole, error)
GetWorkspaceRole(workspace string, name string) (*iamv1alpha2.WorkspaceRole, error)
CreateOrUpdateGlobalRoleBinding(username string, globalRole string) error
CreateGlobalRoleBinding(username string, globalRole string) error
CreateOrUpdateWorkspaceRole(workspace string, workspaceRole *iamv1alpha2.WorkspaceRole) (*iamv1alpha2.WorkspaceRole, error)
CreateOrUpdateGlobalRole(globalRole *iamv1alpha2.GlobalRole) (*iamv1alpha2.GlobalRole, error)
DeleteWorkspaceRole(workspace string, name string) error
@@ -64,11 +61,11 @@ type AccessManagementInterface interface {
GetNamespaceRole(namespace string, name string) (*rbacv1.Role, error)
CreateOrUpdateNamespaceRole(namespace string, role *rbacv1.Role) (*rbacv1.Role, error)
DeleteNamespaceRole(namespace string, name string) error
CreateOrUpdateWorkspaceRoleBinding(username string, workspace string, role string) error
CreateWorkspaceRoleBinding(username string, workspace string, role string) error
RemoveUserFromWorkspace(username string, workspace string) error
CreateOrUpdateNamespaceRoleBinding(username string, namespace string, role string) error
CreateNamespaceRoleBinding(username string, namespace string, role string) error
RemoveUserFromNamespace(username string, namespace string) error
CreateOrUpdateClusterRoleBinding(username string, role string) error
CreateClusterRoleBinding(username string, role string) error
RemoveUserFromCluster(username string) error
GetControlledNamespace(devops string) (string, error)
GetControlledWorkspace(namespace string) (string, error)
@@ -116,17 +113,8 @@ func (am *amOperator) GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalR
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindGlobalRoleBinding,
},
Message: fmt.Sprintf("global role binding not found for %s", username),
}}
err = errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularGlobalRoleBinding), username)
klog.Error(err)
return nil, err
}
@@ -159,17 +147,8 @@ func (am *amOperator) GetWorkspaceRoleOfUser(username, workspace string) (*iamv1
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindWorkspaceRoleBinding,
},
Message: fmt.Sprintf("workspace role binding not found for %s", username),
}}
err = errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularWorkspaceRoleBinding), username)
klog.Error(err)
return nil, err
}
@@ -199,17 +178,8 @@ func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: rbacv1.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindRoleBinding,
},
Message: fmt.Sprintf("role binding not found for %s in %s", username, namespace),
}}
err = errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularRoleBinding), username)
klog.Error(err)
return nil, err
}
@@ -239,17 +209,9 @@ func (am *amOperator) GetClusterRoleOfUser(username string) (*rbacv1.ClusterRole
out.Annotations[iamv1alpha2.ClusterRoleAnnotation] = role.Name
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: rbacv1.SchemeGroupVersion.Group,
Kind: "ClusterRoleBinding",
},
Message: fmt.Sprintf("cluster role binding not found for %s", username),
}}
err = errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularClusterRoleBinding), username)
klog.Error(err)
return nil, err
}
@@ -371,7 +333,7 @@ func (am *amOperator) GetGlobalRole(globalRole string) (*iamv1alpha2.GlobalRole,
return obj.(*iamv1alpha2.GlobalRole), nil
}
func (am *amOperator) CreateOrUpdateGlobalRoleBinding(username string, globalRole string) error {
func (am *amOperator) CreateGlobalRoleBinding(username string, globalRole string) error {
_, err := am.GetGlobalRole(globalRole)
@@ -428,11 +390,9 @@ func (am *amOperator) CreateOrUpdateGlobalRoleBinding(username string, globalRol
}
func (am *amOperator) CreateOrUpdateWorkspaceRole(workspace string, workspaceRole *iamv1alpha2.WorkspaceRole) (*iamv1alpha2.WorkspaceRole, error) {
if workspaceRole.Labels == nil {
workspaceRole.Labels = make(map[string]string, 0)
}
workspaceRole.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
workspaceRole.Rules = make([]rbacv1.PolicyRule, 0)
@@ -452,15 +412,10 @@ func (am *amOperator) CreateOrUpdateWorkspaceRole(workspace string, workspaceRol
}
}
old, err := am.GetWorkspaceRole("", workspaceRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *iamv1alpha2.WorkspaceRole
if old != nil {
var err error
if workspaceRole.ResourceVersion != "" {
created, err = am.ksclient.IamV1alpha2().WorkspaceRoles().Update(workspaceRole)
} else {
created, err = am.ksclient.IamV1alpha2().WorkspaceRoles().Create(workspaceRole)
@@ -469,7 +424,7 @@ func (am *amOperator) CreateOrUpdateWorkspaceRole(workspace string, workspaceRol
return created, err
}
func (am *amOperator) CreateOrUpdateWorkspaceRoleBinding(username string, workspace string, role string) error {
func (am *amOperator) CreateWorkspaceRoleBinding(username string, workspace string, role string) error {
_, err := am.GetWorkspaceRole(workspace, role)
@@ -526,7 +481,7 @@ func (am *amOperator) CreateOrUpdateWorkspaceRoleBinding(username string, worksp
return nil
}
func (am *amOperator) CreateOrUpdateClusterRoleBinding(username string, role string) error {
func (am *amOperator) CreateClusterRoleBinding(username string, role string) error {
_, err := am.GetClusterRole(role)
@@ -582,7 +537,7 @@ func (am *amOperator) CreateOrUpdateClusterRoleBinding(username string, role str
return nil
}
func (am *amOperator) CreateOrUpdateNamespaceRoleBinding(username string, namespace string, role string) error {
func (am *amOperator) CreateNamespaceRoleBinding(username string, namespace string, role string) error {
_, err := am.GetNamespaceRole(namespace, role)
@@ -727,15 +682,10 @@ func (am *amOperator) CreateOrUpdateGlobalRole(globalRole *iamv1alpha2.GlobalRol
}
}
old, err := am.GetGlobalRole(globalRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *iamv1alpha2.GlobalRole
if old != nil {
var err error
if globalRole.ResourceVersion != "" {
created, err = am.ksclient.IamV1alpha2().GlobalRoles().Update(globalRole)
} else {
created, err = am.ksclient.IamV1alpha2().GlobalRoles().Create(globalRole)
@@ -763,16 +713,9 @@ func (am *amOperator) CreateOrUpdateClusterRole(clusterRole *rbacv1.ClusterRole)
clusterRole.Rules = append(clusterRole.Rules, role.Rules...)
}
}
old, err := am.GetClusterRole(clusterRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *rbacv1.ClusterRole
if old != nil {
var err error
if clusterRole.ResourceVersion != "" {
created, err = am.k8sclient.RbacV1().ClusterRoles().Update(clusterRole)
} else {
created, err = am.k8sclient.RbacV1().ClusterRoles().Create(clusterRole)
@@ -801,16 +744,9 @@ func (am *amOperator) CreateOrUpdateNamespaceRole(namespace string, role *rbacv1
role.Rules = append(role.Rules, role.Rules...)
}
}
old, err := am.GetNamespaceRole(namespace, role.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *rbacv1.Role
if old != nil {
var err error
if role.ResourceVersion != "" {
created, err = am.k8sclient.RbacV1().Roles(namespace).Update(role)
} else {
created, err = am.k8sclient.RbacV1().Roles(namespace).Create(role)

View File

@@ -17,12 +17,14 @@ limitations under the License.
package tenant
import (
"encoding/json"
"fmt"
"io"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
@@ -36,6 +38,7 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/apiserver/request"
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/auditing"
@@ -61,11 +64,15 @@ type Interface interface {
UpdateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
DescribeWorkspace(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error)
ListWorkspaceClusters(workspace string) (*api.ListResult, error)
Events(user user.Info, queryParam *eventsv1alpha1.Query) (*eventsv1alpha1.APIResponse, error)
QueryLogs(user user.Info, query *loggingv1alpha2.Query) (*loggingv1alpha2.APIResponse, error)
ExportLogs(user user.Info, query *loggingv1alpha2.Query, writer io.Writer) error
Auditing(user user.Info, queryParam *auditingv1alpha1.Query) (*auditingv1alpha1.APIResponse, error)
DescribeNamespace(workspace, namespace string) (*corev1.Namespace, error)
DeleteNamespace(workspace, namespace string) error
UpdateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error)
PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error)
PatchWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
}
type tenantOperator struct {
@@ -99,10 +106,10 @@ func (t *tenantOperator) ListWorkspaces(user user.Info, queryParam *query.Query)
listWS := authorizer.AttributesRecord{
User: user,
Verb: "list",
APIGroup: "tenant.kubesphere.io",
APIVersion: "v1alpha2",
APIGroup: "*",
Resource: "workspaces",
ResourceRequest: true,
ResourceScope: request.GlobalScope,
}
decision, _, err := t.authorizer.Authorize(listWS)
@@ -154,9 +161,9 @@ func (t *tenantOperator) ListWorkspaces(user user.Info, queryParam *query.Query)
}
result := resources.DefaultList(workspaces, queryParam, func(left runtime.Object, right runtime.Object, field query.Field) bool {
return resources.DefaultObjectMetaCompare(left.(*tenantv1alpha1.Workspace).ObjectMeta, right.(*tenantv1alpha1.Workspace).ObjectMeta, field)
return resources.DefaultObjectMetaCompare(left.(*tenantv1alpha2.WorkspaceTemplate).ObjectMeta, right.(*tenantv1alpha2.WorkspaceTemplate).ObjectMeta, field)
}, func(workspace runtime.Object, filter query.Filter) bool {
return resources.DefaultObjectMetaFilter(workspace.(*tenantv1alpha1.Workspace).ObjectMeta, filter)
return resources.DefaultObjectMetaFilter(workspace.(*tenantv1alpha2.WorkspaceTemplate).ObjectMeta, filter)
})
return result, nil
@@ -167,11 +174,10 @@ func (t *tenantOperator) ListNamespaces(user user.Info, workspace string, queryP
listNSInWS := authorizer.AttributesRecord{
User: user,
Verb: "list",
APIGroup: "",
APIVersion: "v1",
Workspace: workspace,
Resource: "namespaces",
ResourceRequest: true,
ResourceScope: request.WorkspaceScope,
}
decision, _, err := t.authorizer.Authorize(listNSInWS)
@@ -238,22 +244,80 @@ func (t *tenantOperator) ListNamespaces(user user.Info, workspace string, queryP
}
func (t *tenantOperator) CreateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) {
_, err := t.resourceGetter.Get(tenantv1alpha1.ResourcePluralWorkspace, "", workspace)
if err != nil {
return nil, err
}
if namespace.Annotations == nil {
namespace.Annotations = make(map[string]string, 0)
}
namespace.Annotations[tenantv1alpha1.WorkspaceLabel] = workspace
namespace = appendWorkspaceLabel(namespace, workspace)
return t.k8sclient.CoreV1().Namespaces().Create(namespace)
}
func appendWorkspaceLabel(namespace *corev1.Namespace, workspace string) *corev1.Namespace {
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
return namespace
}
func (t *tenantOperator) DescribeNamespace(workspace, namespace string) (*corev1.Namespace, error) {
obj, err := t.resourceGetter.Get("namespaces", "", namespace)
if err != nil {
return nil, err
}
ns := obj.(*corev1.Namespace)
if ns.Labels[tenantv1alpha1.WorkspaceLabel] != workspace {
err := errors.NewNotFound(corev1.Resource("namespace"), namespace)
klog.Error(err)
return nil, err
}
return ns, nil
}
func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
_, err := t.DescribeNamespace(workspace, namespace)
if err != nil {
return err
}
return t.k8sclient.CoreV1().Namespaces().Delete(namespace, metav1.NewDeleteOptions(0))
}
func (t *tenantOperator) UpdateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) {
_, err := t.DescribeNamespace(workspace, namespace.Name)
if err != nil {
return nil, err
}
namespace = appendWorkspaceLabel(namespace, workspace)
return t.k8sclient.CoreV1().Namespaces().Update(namespace)
}
func (t *tenantOperator) PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) {
_, err := t.DescribeNamespace(workspace, namespace.Name)
if err != nil {
return nil, err
}
if namespace.Labels != nil {
namespace.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
}
data, err := json.Marshal(namespace)
if err != nil {
return nil, err
}
return t.k8sclient.CoreV1().Namespaces().Patch(namespace.Name, types.MergePatchType, data)
}
func (t *tenantOperator) PatchWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
_, err := t.DescribeWorkspace(workspace.Name)
if err != nil {
return nil, err
}
data, err := json.Marshal(workspace)
if err != nil {
return nil, err
}
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Patch(workspace.Name, types.MergePatchType, data)
}
func (t *tenantOperator) CreateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Create(workspace)
}

View File

@@ -22,7 +22,9 @@ import (
fakeistio "istio.io/client-go/pkg/clientset/versioned/fake"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/user"
fakek8s "k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/api"
@@ -32,41 +34,130 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/query"
fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
"kubesphere.io/kubesphere/pkg/informers"
"reflect"
"testing"
)
func TestTenantOperator_ListWorkspaces(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
name string
result *api.ListResult
username string
expectError error
}{
{
name: "list workspace",
username: "admin",
username: admin.Name,
result: &api.ListResult{
Items: workspaces,
TotalItems: len(workspaces),
Items: workspaceTemplates,
TotalItems: len(workspaceTemplates),
},
},
{
name: "list workspaces",
username: "regular",
username: tester2.Name,
result: &api.ListResult{
Items: []interface{}{workspaceBar},
Items: []interface{}{systemWorkspaceTmpl},
TotalItems: 1,
},
},
}
for _, test := range tests {
for i, test := range tests {
result, err := tenantOperator.ListWorkspaces(&user.DefaultInfo{Name: test.username}, query.New())
if err != nil {
if test.expectError != err {
t.Error(err)
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("got %#v, expected %#v", err, test.expectError)
}
continue
}
if diff := cmp.Diff(result, test.result); diff != "" {
t.Errorf("case %d,%s", i, diff)
}
}
}
func TestTenantOperator_ListNamespaces(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
result *api.ListResult
username string
workspace string
expectError error
}{
{
workspace: systemWorkspace.Name,
username: admin.Name,
result: &api.ListResult{
Items: []interface{}{kubesphereSystem, defaultNamespace},
TotalItems: 2,
},
},
{
workspace: systemWorkspace.Name,
username: tester1.Name,
result: &api.ListResult{
Items: []interface{}{},
TotalItems: 0,
},
},
{
workspace: testWorkspace.Name,
username: tester2.Name,
result: &api.ListResult{
Items: []interface{}{testNamespace},
TotalItems: 1,
},
},
}
for i, test := range tests {
result, err := tenantOperator.ListNamespaces(&user.DefaultInfo{Name: test.username}, test.workspace, query.New())
if err != nil {
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("got %#v, expected %#v", err, test.expectError)
}
continue
}
if diff := cmp.Diff(result, test.result); diff != "" {
t.Errorf("case %d, %s", i, diff)
}
}
}
func TestTenantOperator_DescribeNamespace(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
result *corev1.Namespace
username string
workspace string
namespace string
expectError error
}{
{
result: testNamespace,
username: tester2.Name,
workspace: testWorkspace.Name,
namespace: testNamespace.Name,
expectError: nil,
},
{
result: testNamespace,
username: tester2.Name,
workspace: systemWorkspace.Name,
namespace: testNamespace.Name,
expectError: errors.NewNotFound(corev1.Resource("namespace"), testNamespace.Name),
},
}
for _, test := range tests {
result, err := tenantOperator.DescribeNamespace(test.workspace, test.namespace)
if err != nil {
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("got %#v, expected %#v", err, test.expectError)
}
continue
}
@@ -77,50 +168,157 @@ func TestTenantOperator_ListWorkspaces(t *testing.T) {
}
}
func TestTenantOperator_ListNamespaces(t *testing.T) {
func TestTenantOperator_CreateNamespace(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
name string
result *api.ListResult
username string
result *corev1.Namespace
workspace string
namespace *corev1.Namespace
expectError error
}{
{
name: "list namespaces",
workspace: "foo",
username: "admin",
result: &api.ListResult{
Items: []interface{}{foo2, foo1},
TotalItems: 2,
result: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: testWorkspace.Name},
},
},
},
{
name: "list namespaces",
workspace: "foo",
username: "regular",
result: &api.ListResult{
Items: []interface{}{},
TotalItems: 0,
},
},
{
name: "list namespaces",
workspace: "bar",
username: "regular",
result: &api.ListResult{
Items: []interface{}{bar1},
TotalItems: 1,
workspace: testWorkspace.Name,
namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
},
expectError: nil,
},
}
for _, test := range tests {
result, err := tenantOperator.ListNamespaces(&user.DefaultInfo{Name: test.username}, test.workspace, query.New())
for i, test := range tests {
result, err := tenantOperator.CreateNamespace(test.workspace, test.namespace)
if err != nil {
if test.expectError != err {
t.Error(err)
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("case %d, got %#v, expected %#v", i, err, test.expectError)
}
continue
}
if diff := cmp.Diff(result, test.result); diff != "" {
t.Error(diff)
}
}
}
func TestTenantOperator_DeleteNamespace(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
workspace string
namespace string
expectError error
}{
{
workspace: testWorkspace.Name,
namespace: kubesphereSystem.Name,
expectError: errors.NewNotFound(corev1.Resource("namespace"), kubesphereSystem.Name),
},
{
workspace: testWorkspace.Name,
namespace: testNamespace.Name,
expectError: nil,
},
}
for i, test := range tests {
err := tenantOperator.DeleteNamespace(test.workspace, test.namespace)
if err != nil {
if test.expectError != nil && test.expectError.Error() == err.Error() {
continue
} else {
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("case %d, got %#v, expected %#v", i, err, test.expectError)
}
}
}
}
}
func TestTenantOperator_UpdateNamespace(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
result *corev1.Namespace
workspace string
namespace *corev1.Namespace
expectError error
}{
{
result: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test-namespace",
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: testWorkspace.Name},
},
},
workspace: testWorkspace.Name,
namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test-namespace",
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: testWorkspace.Name},
},
},
expectError: nil,
},
}
for i, test := range tests {
result, err := tenantOperator.UpdateNamespace(test.workspace, test.namespace)
if err != nil {
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("case %d, got %#v, expected %#v", i, err, test.expectError)
}
continue
}
if diff := cmp.Diff(result, test.result); diff != "" {
t.Error(diff)
}
}
}
func TestTenantOperator_PatchNamespace(t *testing.T) {
tenantOperator := prepare()
tests := []struct {
result *corev1.Namespace
workspace string
patch *corev1.Namespace
expectError error
}{
{
result: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test-namespace",
Annotations: map[string]string{"test": "test2"},
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: testWorkspace.Name},
},
},
workspace: testWorkspace.Name,
patch: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test-namespace",
Annotations: map[string]string{"test": "test2"},
},
},
expectError: nil,
},
}
for i, test := range tests {
result, err := tenantOperator.PatchNamespace(test.workspace, test.patch)
if err != nil {
if !reflect.DeepEqual(err, test.expectError) {
t.Errorf("case %d, got %#v, expected %#v", i, err, test.expectError)
}
continue
}
@@ -132,28 +330,56 @@ func TestTenantOperator_ListNamespaces(t *testing.T) {
}
var (
foo1 = &corev1.Namespace{
admin = user.DefaultInfo{
Name: "admin",
}
tester1 = user.DefaultInfo{
Name: "tester1",
}
tester2 = user.DefaultInfo{
Name: "tester2",
}
systemWorkspaceTmpl = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: "foo"},
Name: "system-workspace",
},
}
foo2 = &corev1.Namespace{
testWorkspaceTmpl = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: "foo"},
Name: "test-workspace",
},
}
bar1 = &corev1.Namespace{
systemWorkspace = &tenantv1alpha1.Workspace{
ObjectMeta: metav1.ObjectMeta{
Name: "bar1",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: "bar"},
Name: "system-workspace",
},
}
adminGlobalRole = &iamv1alpha2.GlobalRole{
testWorkspace = &tenantv1alpha1.Workspace{
ObjectMeta: metav1.ObjectMeta{
Name: "global-admin",
Name: "test-workspace",
},
}
kubesphereSystem = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "kubesphere-system",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: systemWorkspace.Name},
},
}
defaultNamespace = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: systemWorkspace.Name},
},
}
testNamespace = &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "test-namespace",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: testWorkspace.Name},
},
}
platformAdmin = &iamv1alpha2.GlobalRole{
ObjectMeta: metav1.ObjectMeta{
Name: "platform-admin",
},
Rules: []rbacv1.PolicyRule{
{
@@ -163,79 +389,67 @@ var (
},
},
}
regularGlobalRole = &iamv1alpha2.GlobalRole{
platformRegular = &iamv1alpha2.GlobalRole{
ObjectMeta: metav1.ObjectMeta{
Name: "regular",
},
Rules: []rbacv1.PolicyRule{
{
Verbs: []string{},
APIGroups: []string{},
Resources: []string{},
},
Name: "platform-regular",
},
Rules: []rbacv1.PolicyRule{},
}
reguarWorksapceRole = &iamv1alpha2.WorkspaceRole{
systemWorkspaceRegular = &iamv1alpha2.WorkspaceRole{
ObjectMeta: metav1.ObjectMeta{
Name: "workspace-regular",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: "bar"},
},
Rules: []rbacv1.PolicyRule{
{
Verbs: []string{},
APIGroups: []string{},
Resources: []string{},
},
Name: "system-workspace-regular",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: systemWorkspace.Name},
},
Rules: []rbacv1.PolicyRule{},
}
adminGlobalRoleBinding = &iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "global-admin",
Name: admin.Name + "-" + platformAdmin.Name,
},
Subjects: []rbacv1.Subject{{
Kind: "User",
Name: "admin",
Name: admin.Name,
}},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.String(),
Kind: iamv1alpha2.ResourceKindGlobalRole,
Name: "global-admin",
Name: platformAdmin.Name,
},
}
regularGlobalRoleBinding = &iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "regular",
Name: tester1.Name + "-" + platformRegular.Name,
},
Subjects: []rbacv1.Subject{{
Kind: "User",
Name: "regular",
Name: tester1.Name,
}},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.String(),
Kind: iamv1alpha2.ResourceKindGlobalRole,
Name: "regular",
Name: platformRegular.Name,
},
}
regularWorkspaceRoleBinding = &iamv1alpha2.WorkspaceRoleBinding{
systemWorkspaceRegularRoleBinding = &iamv1alpha2.WorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "workspace-regular",
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: "bar"},
Name: tester2.Name + "-" + systemWorkspaceRegular.Name,
Labels: map[string]string{tenantv1alpha1.WorkspaceLabel: systemWorkspace.Name},
},
Subjects: []rbacv1.Subject{{
Kind: "User",
Name: "regular",
Name: tester2.Name,
}},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.String(),
Kind: iamv1alpha2.ResourceKindGlobalRole,
Name: "workspace-regular",
Name: systemWorkspaceRegular.Name,
},
}
bar1NamespaceRole = &rbacv1.Role{
testNamespaceAdmin = &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: "admin",
Namespace: "bar1",
Namespace: testNamespace.Name,
},
Rules: []rbacv1.PolicyRule{
{
@@ -245,52 +459,48 @@ var (
},
},
}
bar1NamespaceRoleBinding = &rbacv1.RoleBinding{
testNamespaceAdminRoleBinding = &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "admin",
Namespace: "bar1",
Namespace: testNamespace.Name,
},
Subjects: []rbacv1.Subject{{
Kind: "User",
Name: "regular",
Name: tester2.Name,
}},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.SchemeGroupVersion.String(),
Kind: "Role",
Name: "admin",
},
}
workspaceFoo = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
}
workspaceBar = &tenantv1alpha2.WorkspaceTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Name: testNamespaceAdmin.Name,
},
}
workspaces = []interface{}{workspaceFoo, workspaceBar}
namespaces = []interface{}{foo1, foo2, bar1}
globalRoles = []interface{}{adminGlobalRole, regularGlobalRole}
workspaces = []interface{}{systemWorkspace, testWorkspace}
workspaceTemplates = []interface{}{testWorkspaceTmpl, systemWorkspaceTmpl}
namespaces = []interface{}{kubesphereSystem, defaultNamespace, testNamespace}
globalRoles = []interface{}{platformAdmin, platformRegular}
globalRoleBindings = []interface{}{adminGlobalRoleBinding, regularGlobalRoleBinding}
workspaceRoles = []interface{}{regularGlobalRole}
workspaceRoleBindings = []interface{}{regularWorkspaceRoleBinding}
namespaceRoles = []interface{}{bar1NamespaceRole}
namespaceRoleBindings = []interface{}{bar1NamespaceRoleBinding}
workspaceRoles = []interface{}{systemWorkspaceRegular}
workspaceRoleBindings = []interface{}{systemWorkspaceRegularRoleBinding}
namespaceRoles = []interface{}{testNamespaceAdmin}
namespaceRoleBindings = []interface{}{testNamespaceAdminRoleBinding}
)
func prepare() Interface {
ksClient := fakeks.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
ksClient := fakeks.NewSimpleClientset([]runtime.Object{testWorkspace, systemWorkspace}...)
k8sClient := fakek8s.NewSimpleClientset([]runtime.Object{testNamespace, kubesphereSystem}...)
istioClient := fakeistio.NewSimpleClientset()
appClient := fakeapp.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient, nil, nil)
for _, workspace := range workspaces {
fakeInformerFactory.KubeSphereSharedInformerFactory().Tenant().V1alpha1().
Workspaces().Informer().GetIndexer().Add(workspace)
}
for _, workspaceTmpl := range workspaceTemplates {
fakeInformerFactory.KubeSphereSharedInformerFactory().Tenant().V1alpha2().
WorkspaceTemplates().Informer().GetIndexer().Add(workspace)
WorkspaceTemplates().Informer().GetIndexer().Add(workspaceTmpl)
}
for _, namespace := range namespaces {
@@ -328,5 +538,5 @@ func prepare() Interface {
RoleBindings().Informer().GetIndexer().Add(roleBinding)
}
return New(fakeInformerFactory, nil, nil, nil, nil, nil)
return New(fakeInformerFactory, k8sClient, ksClient, nil, nil, nil)
}