
including * enhance rbac-controller unit tests * add tenant-controller unit tests Change-Id: I8a803a9c9194bc27662373099e2be34793811311 Implements: blueprint auth-controller-test Signed-off-by: mozhuli <21621232@zju.edu.cn>
513 lines
15 KiB
Go
513 lines
15 KiB
Go
/*
|
|
Copyright (c) 2017 OpenStack Foundation.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package tenant
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
crv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
|
|
"git.openstack.org/openstack/stackube/pkg/auth-controller/rbacmanager/rbac"
|
|
crdClient "git.openstack.org/openstack/stackube/pkg/kubecrd"
|
|
"git.openstack.org/openstack/stackube/pkg/openstack"
|
|
"git.openstack.org/openstack/stackube/pkg/util"
|
|
apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
)
|
|
|
|
const (
|
|
password = "123456"
|
|
)
|
|
|
|
var systemTenant = &crv1.Tenant{
|
|
ObjectMeta: apismetav1.ObjectMeta{
|
|
Name: util.SystemTenant,
|
|
Namespace: util.SystemTenant,
|
|
},
|
|
Spec: crv1.TenantSpec{
|
|
UserName: util.SystemTenant,
|
|
Password: util.SystemPassword,
|
|
},
|
|
}
|
|
|
|
func newTenant(name, userName, password, tenantID string) *crv1.Tenant {
|
|
return &crv1.Tenant{
|
|
ObjectMeta: apismetav1.ObjectMeta{
|
|
Name: name,
|
|
},
|
|
Spec: crv1.TenantSpec{
|
|
UserName: userName,
|
|
Password: password,
|
|
TenantID: tenantID,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newNetwork(name string) *crv1.Network {
|
|
return &crv1.Network{
|
|
ObjectMeta: apismetav1.ObjectMeta{
|
|
Name: name,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newTenantController() (*TenantController, *crdClient.FakeCRDClient, *openstack.FakeOSClient, *fake.Clientset, error) {
|
|
kubeCRDClient, err := crdClient.NewFake()
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
osClient := openstack.NewFake(kubeCRDClient)
|
|
|
|
client := fake.NewSimpleClientset()
|
|
|
|
c := &TenantController{
|
|
kubeCRDClient: kubeCRDClient,
|
|
k8sClient: client,
|
|
openstackClient: osClient,
|
|
}
|
|
|
|
if err = c.createClusterRoles(); err != nil {
|
|
return nil, nil, nil, nil, fmt.Errorf("failed to create cluster roles to kube-apiserver: %v", err)
|
|
}
|
|
|
|
return c, kubeCRDClient, osClient, client, nil
|
|
}
|
|
|
|
func TestOperateNamespace(t *testing.T) {
|
|
testNamespace := "foo"
|
|
// Created a new fake TenantController.
|
|
controller, _, _, client, err := newTenantController()
|
|
if err != nil {
|
|
t.Fatalf("Failed start a new fake TenantController")
|
|
}
|
|
|
|
// test create namespace
|
|
err = controller.createNamespace(testNamespace)
|
|
if err != nil {
|
|
t.Fatalf("Create namespace %s error:%v", testNamespace, err)
|
|
}
|
|
ns, err := client.Core().Namespaces().Get(testNamespace, apismetav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatalf("Get namespace %v error: %v", testNamespace, err)
|
|
}
|
|
if ns.Name != testNamespace {
|
|
t.Errorf("Created namespce has incorrect parameters: %v", ns)
|
|
}
|
|
|
|
// test delete namespace
|
|
err = controller.deleteNamespace(testNamespace)
|
|
if err != nil {
|
|
t.Fatalf("Delete namespace %v error: %v", testNamespace, err)
|
|
}
|
|
_, err = client.Core().Namespaces().Get(testNamespace, apismetav1.GetOptions{})
|
|
if err.Error() != fmt.Errorf("namespaces %q not found", testNamespace).Error() {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateClusterRoles(t *testing.T) {
|
|
// Created a new fake TenantController.
|
|
controller, _, _, client, err := newTenantController()
|
|
if err != nil {
|
|
t.Fatalf("Failed start a new fake TenantController")
|
|
}
|
|
err = controller.createClusterRoles()
|
|
if err != nil {
|
|
t.Fatalf("Create cluster role error:%v", err)
|
|
}
|
|
|
|
clusterRole, err := client.Rbac().ClusterRoles().Get("namespace-creater", apismetav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatalf("Failed get cluster role: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(clusterRole, rbac.GenerateClusterRole()) {
|
|
t.Errorf("Created cluster role has incorrect parameters: %v", clusterRole)
|
|
}
|
|
}
|
|
|
|
func TestOnAdd(t *testing.T) {
|
|
var controller *TenantController
|
|
var kubeCRDClient *crdClient.FakeCRDClient
|
|
var osClient *openstack.FakeOSClient
|
|
var client *fake.Clientset
|
|
var err error
|
|
tenantID := "123"
|
|
|
|
testCases := []struct {
|
|
testName string
|
|
tenantName string
|
|
updateFn func(tenantName string)
|
|
expectedFn func(tenantName string) error
|
|
}{
|
|
{
|
|
testName: "Add default Tenant",
|
|
tenantName: "default",
|
|
updateFn: func(tenantName string) {
|
|
// Created a new fake TenantController.
|
|
controller, kubeCRDClient, osClient, client, err = newTenantController()
|
|
if err != nil {
|
|
t.Fatalf("Failed start a new fake TenantController")
|
|
}
|
|
// Add default tenant
|
|
controller.onAdd(systemTenant)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding created
|
|
err := testClusterRoleBindingCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test tenant created
|
|
tenant, ok := osClient.Tenants[tenantName]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s tenant to be created, got none", tenantName)
|
|
} else if tenant.Name != tenantName {
|
|
return fmt.Errorf("the created %s tenant has incorrect parameter: %v", tenantName, tenant)
|
|
}
|
|
// test user created
|
|
user, ok := osClient.Users[tenant.ID]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s user to be created, got none", tenantName)
|
|
} else if user.Name != tenantName &&
|
|
user.TenantID != tenant.ID {
|
|
return fmt.Errorf("the created %s user has incorrect parameters: %v", tenantName, user)
|
|
}
|
|
// test namespace created
|
|
err = testNamespaceCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
testName: "Add foo1 Tenant with no spec tenantID",
|
|
tenantName: "foo1",
|
|
updateFn: func(tenantName string) {
|
|
// Add tenant
|
|
tenant := newTenant(tenantName, tenantName, password, "")
|
|
controller.onAdd(tenant)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding created
|
|
err := testClusterRoleBindingCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test tenant created
|
|
tenant, ok := osClient.Tenants[tenantName]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s tenant to be created, got none", tenantName)
|
|
} else if tenant.Name != tenantName {
|
|
return fmt.Errorf("the created %s tenant has incorrect parameter: %v", tenantName, tenant)
|
|
}
|
|
// test user created
|
|
user, ok := osClient.Users[tenant.ID]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s user to be created, got none", tenantName)
|
|
} else if user.Name != tenantName &&
|
|
user.TenantID != tenant.ID {
|
|
return fmt.Errorf("the created %s user has incorrect parameters: %v", tenantName, user)
|
|
}
|
|
// test namespace created
|
|
err = testNamespaceCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
testName: "Add foo2 Tenant with spec tenantID",
|
|
tenantName: "foo2",
|
|
updateFn: func(tenantName string) {
|
|
|
|
tenant := newTenant(tenantName, tenantName, password, tenantID)
|
|
// Injects fake tenant.
|
|
osClient.SetTenant(tenantName, tenantID)
|
|
|
|
controller.onAdd(tenant)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding created
|
|
err := testClusterRoleBindingCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test user created
|
|
user, ok := osClient.Users[tenantID]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s user to be created, got none", tenantName)
|
|
} else if user.Name != tenantName &&
|
|
user.TenantID != tenantID {
|
|
return fmt.Errorf("the created %s user has incorrect parameters: %v", tenantName, user)
|
|
}
|
|
// test namespace created
|
|
err = testNamespaceCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
testName: "Add foo3 Tenant, and the tenant exist in openstack",
|
|
tenantName: "foo3",
|
|
updateFn: func(tenantName string) {
|
|
|
|
tenant := newTenant(tenantName, tenantName, password, "")
|
|
// Injects fake tenant.
|
|
osClient.SetTenant(tenantName, tenantID)
|
|
|
|
controller.onAdd(tenant)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding created
|
|
err := testClusterRoleBindingCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test user created
|
|
tenant, _ := osClient.Tenants[tenantName]
|
|
user, ok := osClient.Users[tenant.ID]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s user to be created, got none", tenantName)
|
|
} else if user.Name != tenantName &&
|
|
user.TenantID != tenant.ID {
|
|
return fmt.Errorf("the created %s user has incorrect parameters: %v", tenantName, user)
|
|
}
|
|
// test namespace created
|
|
err = testNamespaceCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
testName: "Add foo4 Tenant, and create user with error",
|
|
tenantName: "foo4",
|
|
updateFn: func(tenantName string) {
|
|
|
|
tenant := newTenant(tenantName, tenantName, password, "")
|
|
// Injects error.
|
|
osClient.InjectError("CreateUser", fmt.Errorf("Failed create user"))
|
|
|
|
controller.onAdd(tenant)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding created
|
|
err := testClusterRoleBindingCreated(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test no user created
|
|
tenant, _ := osClient.Tenants[tenantName]
|
|
user, ok := osClient.Users[tenant.ID]
|
|
if ok {
|
|
return fmt.Errorf("expected no user to be created, got %v", user)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
}
|
|
|
|
for tci, tc := range testCases {
|
|
tc.updateFn(tc.tenantName)
|
|
err := tc.expectedFn(tc.tenantName)
|
|
if err != nil {
|
|
t.Errorf("Case[%d]: %s %v", tci, tc.testName, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOnDelete(t *testing.T) {
|
|
var controller *TenantController
|
|
var kubeCRDClient *crdClient.FakeCRDClient
|
|
var osClient *openstack.FakeOSClient
|
|
var client *fake.Clientset
|
|
var err error
|
|
var tenantID string
|
|
|
|
testCases := []struct {
|
|
testName string
|
|
tenantName string
|
|
updateFn func(tenantName string)
|
|
expectedFn func(tenantName string) error
|
|
}{
|
|
{
|
|
testName: "fool Tenant with no spec tenantID",
|
|
tenantName: "foo1",
|
|
updateFn: func(tenantName string) {
|
|
// Created a new fake TenantController.
|
|
controller, kubeCRDClient, osClient, client, err = newTenantController()
|
|
if err != nil {
|
|
t.Fatalf("Failed start a new fake TenantController")
|
|
}
|
|
|
|
// Injects fake network
|
|
network := newNetwork(tenantName)
|
|
kubeCRDClient.SetNetworks(network)
|
|
// Add tenant
|
|
ns := newTenant(tenantName, tenantName, password, "")
|
|
controller.onAdd(ns)
|
|
tenantID = osClient.Tenants[tenantName].ID
|
|
// Delete tenant
|
|
controller.onDelete(ns)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding deleted
|
|
err := testClusterRoleBindingDeleted(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test network deleted
|
|
network, ok := kubeCRDClient.Networks[tenantName]
|
|
if ok {
|
|
return fmt.Errorf("expected %s network to be deleted, got %v", tenantName, network)
|
|
}
|
|
// test tenant deleted
|
|
tenant, ok := osClient.Tenants[tenantName]
|
|
if ok {
|
|
return fmt.Errorf("expected %s tenant to be deleted, got %v", tenantName, tenant)
|
|
}
|
|
// test user deleted
|
|
user, ok := osClient.Users[tenantID]
|
|
if ok {
|
|
return fmt.Errorf("expected %s user to be deleted, got %v", tenantName, user)
|
|
}
|
|
// test namespace deleted
|
|
err = testNamespaceDeleted(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
testName: "foo2 Tenant with spec tenantID",
|
|
tenantName: "foo2",
|
|
updateFn: func(tenantName string) {
|
|
// Created a new fake TenantController.
|
|
controller, kubeCRDClient, osClient, client, err = newTenantController()
|
|
if err != nil {
|
|
t.Fatalf("Failed start a new fake TenantController")
|
|
}
|
|
|
|
// Injects fake network
|
|
network := newNetwork(tenantName)
|
|
kubeCRDClient.SetNetworks(network)
|
|
|
|
tenantID = "123"
|
|
ns := newTenant(tenantName, tenantName, password, tenantID)
|
|
// Injects fake tenant
|
|
osClient.SetTenant(tenantName, tenantID)
|
|
// Add tenant
|
|
controller.onAdd(ns)
|
|
tenantID = osClient.Tenants[tenantName].ID
|
|
// Delete tenant
|
|
controller.onDelete(ns)
|
|
|
|
},
|
|
expectedFn: func(tenantName string) error {
|
|
// test ClusterRoleBinding deleted
|
|
err := testClusterRoleBindingDeleted(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// test network deleted
|
|
network, ok := kubeCRDClient.Networks[tenantName]
|
|
if ok {
|
|
return fmt.Errorf("expected %s network to be deleted, got %v", tenantName, network)
|
|
}
|
|
// test tenant remain existed
|
|
_, ok = osClient.Tenants[tenantName]
|
|
if !ok {
|
|
return fmt.Errorf("expected %s tenant remain existed, got none", tenantName)
|
|
}
|
|
// test user deleted
|
|
user, ok := osClient.Users[tenantID]
|
|
if ok {
|
|
return fmt.Errorf("expected %s user to be deleted, got %v", tenantName, user)
|
|
}
|
|
// test namespace deleted
|
|
err = testNamespaceDeleted(t, client, tenantName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
}
|
|
|
|
for tci, tc := range testCases {
|
|
tc.updateFn(tc.tenantName)
|
|
err := tc.expectedFn(tc.tenantName)
|
|
if err != nil {
|
|
t.Errorf("Case[%d]: %s %v", tci, tc.testName, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testClusterRoleBindingCreated(t *testing.T, client *fake.Clientset, tenantName string) error {
|
|
clusterRoleBinding, err := client.Rbac().ClusterRoleBindings().Get(tenantName+"-namespace-creater", apismetav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatalf("Failed get ClusterRoleBinding: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(clusterRoleBinding, rbac.GenerateClusterRoleBindingByTenant(tenantName)) {
|
|
return fmt.Errorf("created ClusterRoleBinding has incorrect parameters: %v", clusterRoleBinding)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func testClusterRoleBindingDeleted(t *testing.T, client *fake.Clientset, tenantName string) error {
|
|
_, err := client.Rbac().ClusterRoleBindings().Get(tenantName+"-namespace-creater", apismetav1.GetOptions{})
|
|
|
|
if err.Error() != fmt.Errorf("clusterrolebindings.rbac.authorization.k8s.io %q not found", tenantName+"-namespace-creater").Error() {
|
|
return fmt.Errorf("unexpected error: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func testNamespaceCreated(t *testing.T, client *fake.Clientset, namespace string) error {
|
|
ns, err := client.Core().Namespaces().Get(namespace, apismetav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatalf("Get namespace %v error: %v", namespace, err)
|
|
}
|
|
if ns.Name != namespace {
|
|
return fmt.Errorf("created namespce %v has incorrect parameters: %v", namespace, ns)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func testNamespaceDeleted(t *testing.T, client *fake.Clientset, namespace string) error {
|
|
_, err := client.Core().Namespaces().Get(namespace, apismetav1.GetOptions{})
|
|
if err.Error() != fmt.Errorf("namespaces %q not found", namespace).Error() {
|
|
return fmt.Errorf("unexpected error: %v", err)
|
|
}
|
|
return nil
|
|
}
|