stackube/pkg/auth-controller/tenant/tenant_controller_test.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
}