Add fake CRD client

Change-Id: I4748ce465b2886098cfab37277a18cc0b571c22b
Implements: blueprint enhance-unit-testing
Signed-off-by: mozhuli <21621232@zju.edu.cn>
This commit is contained in:
mozhulee 2017-08-25 20:54:39 +08:00 committed by mozhuli
parent 23c2da8286
commit 7fed3d210b
9 changed files with 647 additions and 176 deletions

View File

@ -41,13 +41,13 @@ const (
// Controller manages life cycle of namespace's rbac.
type Controller struct {
k8sclient *kubernetes.Clientset
kubeCRDClient *crdClient.CRDClient
kubeCRDClient crdClient.Interface
userCIDR string
userGateway string
}
// NewRBACController creates a new RBAC controller.
func NewRBACController(kubeClient *kubernetes.Clientset, kubeCRDClient *crdClient.CRDClient, userCIDR string,
func NewRBACController(kubeClient *kubernetes.Clientset, kubeCRDClient crdClient.Interface, userCIDR string,
userGateway string) (*Controller, error) {
c := &Controller{
k8sclient: kubeClient,

View File

@ -34,10 +34,10 @@ import (
"k8s.io/client-go/tools/cache"
)
// TenantController manages life cycle of Tenant.
// TenantController manages the life cycle of Tenant.
type TenantController struct {
k8sClient *kubernetes.Clientset
kubeCRDClient *crdClient.CRDClient
kubeCRDClient crdClient.Interface
openstackClient openstack.Interface
}
@ -64,16 +64,12 @@ func NewTenantController(kubeClient *kubernetes.Clientset,
return c, nil
}
func (c *TenantController) GetKubeCRDClient() *crdClient.CRDClient {
return c.kubeCRDClient
}
// Run the controller.
func (c *TenantController) Run(stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
source := cache.NewListWatchFromClient(
c.kubeCRDClient.Client,
c.kubeCRDClient.Client(),
crv1.TenantResourcePlural,
apiv1.NamespaceAll,
fields.Everything())
@ -97,7 +93,7 @@ func (c *TenantController) onAdd(obj interface{}) {
tenant := obj.(*crv1.Tenant)
glog.V(3).Infof("Tenant controller received new object %#v\n", tenant)
copyObj, err := c.kubeCRDClient.Scheme.Copy(tenant)
copyObj, err := c.kubeCRDClient.Scheme().Copy(tenant)
if err != nil {
glog.Errorf("ERROR creating a deep copy of tenant object: %#v\n", err)
return

View File

@ -30,12 +30,34 @@ import (
"github.com/golang/glog"
)
type CRDClient struct {
Client *rest.RESTClient
Scheme *runtime.Scheme
// Interface should be implemented by a CRD client.
type Interface interface {
// AddTenant adds Tenant CRD object by given object.
AddTenant(tenant *crv1.Tenant) error
// GetTenant returns Tenant CRD object by tenantName.
GetTenant(tenantName string) (*crv1.Tenant, error)
// UpdateTenant updates Tenant CRD object by given object.
UpdateTenant(tenant *crv1.Tenant) error
// AddNetwork adds Network CRD object by given object.
AddNetwork(network *crv1.Network) error
// UpdateNetwork updates Network CRD object by given object.
UpdateNetwork(network *crv1.Network) error
// DeleteNetwork deletes Network CRD object by networkName.
DeleteNetwork(networkName string) error
// Client returns the RESTClient.
Client() *rest.RESTClient
// Scheme returns runtime scheme.
Scheme() *runtime.Scheme
}
func NewCRDClient(cfg *rest.Config) (*CRDClient, error) {
// CRDClient implements the Interface.
type CRDClient struct {
client *rest.RESTClient
scheme *runtime.Scheme
}
// NewCRDClient returns a new CRD client.
func NewCRDClient(cfg *rest.Config) (Interface, error) {
scheme := runtime.NewScheme()
if err := crv1.AddToScheme(scheme); err != nil {
return nil, err
@ -53,14 +75,24 @@ func NewCRDClient(cfg *rest.Config) (*CRDClient, error) {
}
return &CRDClient{
Client: client,
Scheme: scheme,
client: client,
scheme: scheme,
}, nil
}
// UpdateNetwork updates Network CRD object by given object
func (c *CRDClient) UpdateNetwork(network *crv1.Network) {
err := c.Client.Put().
// Client returns the RESTClient.
func (c *CRDClient) Client() *rest.RESTClient {
return c.client
}
// Scheme returns runtime scheme.
func (c *CRDClient) Scheme() *runtime.Scheme {
return c.scheme
}
// UpdateNetwork updates Network CRD object by given object.
func (c *CRDClient) UpdateNetwork(network *crv1.Network) error {
err := c.client.Put().
Name(network.Name).
Namespace(network.Namespace).
Resource(crv1.NetworkResourcePlural).
@ -70,14 +102,15 @@ func (c *CRDClient) UpdateNetwork(network *crv1.Network) {
if err != nil {
glog.Errorf("ERROR updating network: %v\n", err)
} else {
glog.V(3).Infof("UPDATED network: %#v\n", network)
return err
}
glog.V(3).Infof("UPDATED network: %#v\n", network)
return nil
}
// UpdateTenant updates Network CRD object by given object
func (c *CRDClient) UpdateTenant(tenant *crv1.Tenant) {
err := c.Client.Put().
// UpdateTenant updates Network CRD object by given object.
func (c *CRDClient) UpdateTenant(tenant *crv1.Tenant) error {
err := c.client.Put().
Name(tenant.Name).
Namespace(util.SystemTenant).
Resource(crv1.TenantResourcePlural).
@ -87,17 +120,18 @@ func (c *CRDClient) UpdateTenant(tenant *crv1.Tenant) {
if err != nil {
glog.Errorf("ERROR updating tenant: %v\n", err)
} else {
glog.V(3).Infof("UPDATED tenant: %#v\n", tenant)
return err
}
glog.V(3).Infof("UPDATED tenant: %#v\n", tenant)
return nil
}
// GetTenant returns tenant from CRD
// NOTE: all tenant are stored under system namespace
// GetTenant returns Tenant CRD object by tenantName.
// NOTE: all tenant are stored under system namespace.
func (c *CRDClient) GetTenant(tenantName string) (*crv1.Tenant, error) {
tenant := crv1.Tenant{}
// tenant always has same name and namespace
err := c.Client.Get().
// tenant always has the same name with namespace
err := c.client.Get().
Resource(crv1.TenantResourcePlural).
Namespace(util.SystemTenant).
Name(tenantName).
@ -108,10 +142,10 @@ func (c *CRDClient) GetTenant(tenantName string) (*crv1.Tenant, error) {
return &tenant, nil
}
// AddTenant adds tenant to CRD
// NOTE: all tenant are added to system namespace
// AddTenant adds Tenant CRD object by given object.
// NOTE: all tenant are added to system namespace.
func (c *CRDClient) AddTenant(tenant *crv1.Tenant) error {
err := c.Client.Post().
err := c.client.Post().
Namespace(util.SystemTenant).
Resource(crv1.TenantResourcePlural).
Body(tenant).
@ -122,8 +156,9 @@ func (c *CRDClient) AddTenant(tenant *crv1.Tenant) error {
return nil
}
// AddNetwork adds Network CRD object by given object.
func (c *CRDClient) AddNetwork(network *crv1.Network) error {
err := c.Client.Post().
err := c.client.Post().
Resource(crv1.NetworkResourcePlural).
Namespace(network.GetNamespace()).
Body(network).
@ -134,12 +169,13 @@ func (c *CRDClient) AddNetwork(network *crv1.Network) error {
return nil
}
func (c *CRDClient) DeleteNetwork(namespace string) error {
// NOTE: the automatically created network for tenant use namespace as name
err := c.Client.Delete().
// DeleteNetwork deletes Network CRD object by networkName.
// NOTE: the automatically created network for tenant use namespace as name.
func (c *CRDClient) DeleteNetwork(networkName string) error {
err := c.client.Delete().
Resource(crv1.NetworkResourcePlural).
Namespace(namespace).
Name(namespace).
Namespace(networkName).
Name(networkName).
Do().Error()
if err != nil {
return fmt.Errorf("failed to delete Network: %v", err)

View File

@ -0,0 +1,245 @@
/*
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 kubecrd
import (
"fmt"
"sync"
crv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
)
// CalledDetail is the struct contains called function name and arguments.
type CalledDetail struct {
// Name of the function called.
Name string
// Argument of the function called.
Argument interface{}
}
// FakeCRDClient is a simple fake CRD client, so that stackube
// can be run for testing without requiring a real kubernetes setup.
type FakeCRDClient struct {
sync.Mutex
called []CalledDetail
errors map[string]error
Tenants map[string]*crv1.Tenant
Networks map[string]*crv1.Network
scheme *runtime.Scheme
}
var _ = Interface(&FakeCRDClient{})
// NewFake creates a new FakeCRDClient.
func NewFake() (*FakeCRDClient, error) {
scheme := runtime.NewScheme()
if err := crv1.AddToScheme(scheme); err != nil {
return nil, err
}
return &FakeCRDClient{
errors: make(map[string]error),
Tenants: make(map[string]*crv1.Tenant),
Networks: make(map[string]*crv1.Network),
scheme: scheme,
}, nil
}
func (f *FakeCRDClient) getError(op string) error {
err, ok := f.errors[op]
if ok {
delete(f.errors, op)
return err
}
return nil
}
// InjectError inject error for call
func (f *FakeCRDClient) InjectError(fn string, err error) {
f.Lock()
defer f.Unlock()
f.errors[fn] = err
}
// InjectErrors inject errors for calls
func (f *FakeCRDClient) InjectErrors(errs map[string]error) {
f.Lock()
defer f.Unlock()
for fn, err := range errs {
f.errors[fn] = err
}
}
// ClearErrors clear errors for call
func (f *FakeCRDClient) ClearErrors() {
f.Lock()
defer f.Unlock()
f.errors = make(map[string]error)
}
func (f *FakeCRDClient) appendCalled(name string, argument interface{}) {
call := CalledDetail{Name: name, Argument: argument}
f.called = append(f.called, call)
}
// GetCalledNames get names of call
func (f *FakeCRDClient) GetCalledNames() []string {
f.Lock()
defer f.Unlock()
names := []string{}
for _, detail := range f.called {
names = append(names, detail.Name)
}
return names
}
// GetCalledDetails get detail of each call.
func (f *FakeCRDClient) GetCalledDetails() []CalledDetail {
f.Lock()
defer f.Unlock()
// Copy the list and return.
return append([]CalledDetail{}, f.called...)
}
// SetTenants injects fake tenant.
func (f *FakeCRDClient) SetTenants(tenants []*crv1.Tenant) {
f.Lock()
defer f.Unlock()
for _, tenant := range tenants {
f.Tenants[tenant.Name] = tenant
}
}
// SetNetworks injects fake network.
func (f *FakeCRDClient) SetNetworks(networks []*crv1.Network) {
f.Lock()
defer f.Unlock()
for _, network := range networks {
f.Networks[network.Name] = network
}
}
// Client is a test implementation of Interface.Client.
func (f *FakeCRDClient) Client() *rest.RESTClient {
return nil
}
// Scheme is a test implementation of Interface.Scheme.
func (f *FakeCRDClient) Scheme() *runtime.Scheme {
return f.scheme
}
// AddTenant is a test implementation of Interface.AddTenant.
func (f *FakeCRDClient) AddTenant(tenant *crv1.Tenant) error {
f.Lock()
defer f.Unlock()
f.appendCalled("AddTenant", tenant)
if err := f.getError("AddTenant"); err != nil {
return err
}
if _, ok := f.Tenants[tenant.Name]; ok {
return nil
}
f.Tenants[tenant.Name] = tenant
return nil
}
// GetTenant is a test implementation of Interface.GetTenant.
func (f *FakeCRDClient) GetTenant(tenantName string) (*crv1.Tenant, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("GetTenant", tenantName)
if err := f.getError("GetTenant"); err != nil {
return nil, err
}
tenant, ok := f.Tenants[tenantName]
if !ok {
return nil, fmt.Errorf("Tenant %s not found", tenantName)
}
return tenant, nil
}
// AddNetwork is a test implementation of Interface.AddNetwork.
func (f *FakeCRDClient) AddNetwork(network *crv1.Network) error {
f.Lock()
defer f.Unlock()
f.appendCalled("AddNetwork", network)
if err := f.getError("AddNetwork"); err != nil {
return err
}
if _, ok := f.Networks[network.Name]; ok {
return nil
}
f.Networks[network.Name] = network
return nil
}
// UpdateTenant is a test implementation of Interface.UpdateTenant.
func (f *FakeCRDClient) UpdateTenant(tenant *crv1.Tenant) error {
f.Lock()
defer f.Unlock()
f.appendCalled("UpdateTenant", tenant)
if err := f.getError("UpdateTenant"); err != nil {
return err
}
if _, ok := f.Tenants[tenant.Name]; !ok {
return fmt.Errorf("Tenant %s not exist", tenant.Name)
}
f.Tenants[tenant.Name] = tenant
return nil
}
// UpdateNetwork is a test implementation of Interface.UpdateNetwork.
func (f *FakeCRDClient) UpdateNetwork(network *crv1.Network) error {
f.Lock()
defer f.Unlock()
f.appendCalled("UpdateNetwork", network)
if err := f.getError("UpdateNetwork"); err != nil {
return err
}
if _, ok := f.Networks[network.Name]; !ok {
return fmt.Errorf("Network %s not exist", network.Name)
}
f.Networks[network.Name] = network
return nil
}
// DeleteNetwork is a test implementation of Interface.DeleteNetwork.
func (f *FakeCRDClient) DeleteNetwork(networkName string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("DeleteNetwork", networkName)
if err := f.getError("DeleteNetwork"); err != nil {
return err
}
delete(f.Networks, networkName)
return nil
}

View File

@ -48,18 +48,15 @@ const (
defaultSideCarImage = "stackube/k8s-dns-sidecar-amd64:1.14.4"
)
// Watcher is an network of watching on resource create/update/delete events
// NetworkController manages the life cycle of Network.
type NetworkController struct {
k8sclient *kubernetes.Clientset
kubeCRDClient *kubecrd.CRDClient
kubeCRDClient kubecrd.Interface
driver openstack.Interface
networkInformer cache.Controller
}
func (c *NetworkController) GetKubeCRDClient() *kubecrd.CRDClient {
return c.kubeCRDClient
}
// Run the network controller.
func (c *NetworkController) Run(stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
@ -69,6 +66,7 @@ func (c *NetworkController) Run(stopCh <-chan struct{}) error {
return nil
}
// NewNetworkController creates a new NetworkController.
func NewNetworkController(kubeClient *kubernetes.Clientset, osClient openstack.Interface, kubeExtClient *apiextensionsclient.Clientset) (*NetworkController, error) {
// initialize CRD if it does not exist
_, err := kubecrd.CreateNetworkCRD(kubeExtClient)
@ -77,7 +75,7 @@ func NewNetworkController(kubeClient *kubernetes.Clientset, osClient openstack.I
}
source := cache.NewListWatchFromClient(
osClient.GetCRDClient().Client,
osClient.GetCRDClient().Client(),
crv1.NetworkResourcePlural,
apiv1.NamespaceAll,
fields.Everything())
@ -108,7 +106,7 @@ func (c *NetworkController) onAdd(obj interface{}) {
// NEVER modify objects from the store. It's a read-only, local cache.
// You can use networkScheme.Copy() to make a deep copy of original object and modify this copy
// Or create a copy manually for better performance
copyObj, err := c.GetKubeCRDClient().Scheme.Copy(network)
copyObj, err := c.kubeCRDClient.Scheme().Copy(network)
if err != nil {
glog.Errorf("ERROR creating a deep copy of network object: %v\n", err)
return

View File

@ -106,13 +106,14 @@ type Interface interface {
// EnsureLoadBalancerDeleted ensures a load balancer is deleted.
EnsureLoadBalancerDeleted(name string) error
// GetCRDClient returns the CRDClient.
GetCRDClient() *crdClient.CRDClient
GetCRDClient() crdClient.Interface
// GetPluginName returns the plugin name.
GetPluginName() string
// GetIntegrationBridge returns the integration bridge name.
GetIntegrationBridge() string
}
// Client implements the openstack client Interface.
type Client struct {
Identity *gophercloud.ServiceClient
Provider *gophercloud.ProviderClient
@ -121,7 +122,7 @@ type Client struct {
ExtNetID string
PluginName string
IntegrationBridge string
CRDClient *crdClient.CRDClient
CRDClient crdClient.Interface
}
type PluginOpts struct {
@ -129,6 +130,7 @@ type PluginOpts struct {
IntegrationBridge string `gcfg:"integration-bridge"`
}
// Config used to configure the openstack client.
type Config struct {
Global struct {
AuthUrl string `gcfg:"auth-url"`
@ -151,6 +153,7 @@ func toAuthOptions(cfg Config) gophercloud.AuthOptions {
}
}
// NewClient returns a new openstack client.
func NewClient(config string, kubeConfig string) (Interface, error) {
var opts gophercloud.AuthOptions
cfg, err := readConfig(config)
@ -221,7 +224,7 @@ func readConfig(config string) (Config, error) {
}
// GetCRDClient returns the CRDClient.
func (os *Client) GetCRDClient() *crdClient.CRDClient {
func (os *Client) GetCRDClient() crdClient.Interface {
return os.CRDClient
}
@ -466,6 +469,7 @@ func (os *Client) GetNetworkByName(networkName string) (*drivertypes.Network, er
return os.OSNetworktoProviderNetwork(osNetwork)
}
// OSNetworktoProviderNetwork transfers networks.Network to drivertypes.Network.
func (os *Client) OSNetworktoProviderNetwork(osNetwork *networks.Network) (*drivertypes.Network, error) {
var providerNetwork drivertypes.Network
var providerSubnets []*drivertypes.Subnet
@ -487,6 +491,7 @@ func (os *Client) OSNetworktoProviderNetwork(osNetwork *networks.Network) (*driv
return &providerNetwork, nil
}
// ToProviderStatus transfers networks.Network's status to drivertypes.Network's status.
func (os *Client) ToProviderStatus(status string) string {
switch status {
case "ACTIVE":

View File

@ -18,11 +18,10 @@ package openstack
import (
"crypto/sha1"
"errors"
"fmt"
"io"
"sync"
crv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
crdClient "git.openstack.org/openstack/stackube/pkg/kubecrd"
drivertypes "git.openstack.org/openstack/stackube/pkg/openstack/types"
"git.openstack.org/openstack/stackube/pkg/util"
@ -34,19 +33,27 @@ import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
)
var ErrAlreadyExist = errors.New("AlreadyExist")
// CalledDetail is the struct contains called function name and arguments.
type CalledDetail struct {
// Name of the function called.
Name string
// Argument of the function called.
Argument []interface{}
}
// FakeOSClient is a simple fake openstack client, so that stackube
// can be run for testing without requiring a real openstack setup.
type FakeOSClient struct {
sync.Mutex
called []CalledDetail
errors map[string]error
Tenants map[string]*tenants.Tenant
Users map[string]*users.User
Networks map[string]*drivertypes.Network
Subnets map[string]*subnets.Subnet
Routers map[string]*routers.Router
Ports map[string][]ports.Port
// TODO(mozhuli): Add fakeCRDClient.
CRDClient *crdClient.CRDClient
CRDClient crdClient.Interface
PluginName string
IntegrationBridge string
}
@ -54,50 +61,116 @@ type FakeOSClient struct {
var _ = Interface(&FakeOSClient{})
// NewFake creates a new FakeOSClient.
func NewFake() *FakeOSClient {
func NewFake(crdClient crdClient.Interface) *FakeOSClient {
return &FakeOSClient{
errors: make(map[string]error),
Tenants: make(map[string]*tenants.Tenant),
Users: make(map[string]*users.User),
Networks: make(map[string]*drivertypes.Network),
Subnets: make(map[string]*subnets.Subnet),
Routers: make(map[string]*routers.Router),
Ports: make(map[string][]ports.Port),
CRDClient: crdClient,
PluginName: "ovs",
IntegrationBridge: "bi-int",
}
}
func (f *FakeOSClient) getError(op string) error {
err, ok := f.errors[op]
if ok {
delete(f.errors, op)
return err
}
return nil
}
// InjectError inject error for call
func (f *FakeOSClient) InjectError(fn string, err error) {
f.Lock()
defer f.Unlock()
f.errors[fn] = err
}
// InjectErrors inject errors for calls
func (f *FakeOSClient) InjectErrors(errs map[string]error) {
f.Lock()
defer f.Unlock()
for fn, err := range errs {
f.errors[fn] = err
}
}
// ClearErrors clear errors for call
func (f *FakeOSClient) ClearErrors() {
f.Lock()
defer f.Unlock()
f.errors = make(map[string]error)
}
func (f *FakeOSClient) appendCalled(name string, argument ...interface{}) {
call := CalledDetail{Name: name, Argument: argument}
f.called = append(f.called, call)
}
// GetCalledNames get names of call
func (f *FakeOSClient) GetCalledNames() []string {
f.Lock()
defer f.Unlock()
names := []string{}
for _, detail := range f.called {
names = append(names, detail.Name)
}
return names
}
// GetCalledDetails get detail of each call.
func (f *FakeOSClient) GetCalledDetails() []CalledDetail {
f.Lock()
defer f.Unlock()
// Copy the list and return.
return append([]CalledDetail{}, f.called...)
}
// SetTenant injects fake tenant.
func (os *FakeOSClient) SetTenant(tenantName, tenantID string) {
func (f *FakeOSClient) SetTenant(tenantName, tenantID string) {
f.Lock()
defer f.Unlock()
tenant := &tenants.Tenant{
Name: tenantName,
ID: tenantID,
}
os.Tenants[tenantName] = tenant
f.Tenants[tenantName] = tenant
}
// SetUser injects fake user.
func (os *FakeOSClient) SetUser(userName, userID, tenantID string) {
func (f *FakeOSClient) SetUser(userName, userID, tenantID string) {
f.Lock()
defer f.Unlock()
user := &users.User{
Username: userName,
ID: userID,
TenantID: tenantID,
}
os.Users[tenantID] = user
f.Users[tenantID] = user
}
// SetNetwork injects fake network.
func (os *FakeOSClient) SetNetwork(networkName, networkID string) {
func (f *FakeOSClient) SetNetwork(networkName, networkID string) {
f.Lock()
defer f.Unlock()
network := &drivertypes.Network{
Name: networkName,
Uid: networkID,
}
os.Networks[networkName] = network
f.Networks[networkName] = network
}
// SetPort injects fake port.
func (os *FakeOSClient) SetPort(networkID, deviceOwner, deviceID string) {
netPorts, ok := os.Ports[networkID]
func (f *FakeOSClient) SetPort(networkID, deviceOwner, deviceID string) {
f.Lock()
defer f.Unlock()
netPorts, ok := f.Ports[networkID]
p := ports.Port{
NetworkID: networkID,
DeviceOwner: deviceOwner,
@ -106,10 +179,10 @@ func (os *FakeOSClient) SetPort(networkID, deviceOwner, deviceID string) {
if !ok {
var ps []ports.Port
ps = append(ps, p)
os.Ports[networkID] = ps
f.Ports[networkID] = ps
}
netPorts = append(netPorts, p)
os.Ports[networkID] = netPorts
f.Ports[networkID] = netPorts
}
func tenantIDHash(tenantName string) string {
@ -146,84 +219,129 @@ func idHash(data ...string) string {
return fmt.Sprintf("%x", h.Sum(nil))[:16]
}
// CreateTenant creates tenant by tenantname.
func (os *FakeOSClient) CreateTenant(tenantName string) (string, error) {
if t, ok := os.Tenants[tenantName]; ok {
// CreateTenant is a test implementation of Interface.CreateTenant.
func (f *FakeOSClient) CreateTenant(tenantName string) (string, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("CreateTenant", tenantName)
if err := f.getError("CreateTenant"); err != nil {
return "", err
}
if t, ok := f.Tenants[tenantName]; ok {
return t.ID, nil
}
tenant := &tenants.Tenant{
Name: tenantName,
ID: tenantIDHash(tenantName),
}
os.Tenants[tenantName] = tenant
f.Tenants[tenantName] = tenant
return tenant.ID, nil
}
// DeleteTenant deletes tenant by tenantName.
func (os *FakeOSClient) DeleteTenant(tenantName string) error {
delete(os.Tenants, tenantName)
// DeleteTenant is a test implementation of Interface.DeleteTenant.
func (f *FakeOSClient) DeleteTenant(tenantName string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("DeleteTenant", tenantName)
if err := f.getError("DeleteTenant"); err != nil {
return err
}
delete(f.Tenants, tenantName)
return nil
}
// GetTenantIDFromName gets tenantID by tenantName.
func (os *FakeOSClient) GetTenantIDFromName(tenantName string) (string, error) {
// GetTenantIDFromName is a test implementation of Interface.GetTenantIDFromName.
func (f *FakeOSClient) GetTenantIDFromName(tenantName string) (string, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("GetTenantIDFromName", tenantName)
if err := f.getError("GetTenantIDFromName"); err != nil {
return "", err
}
if util.IsSystemNamespace(tenantName) {
tenantName = util.SystemTenant
}
// If tenantID is specified, return it directly
var (
tenant *crv1.Tenant
err error
)
// TODO(mozhuli): use fakeCRDClient.
if tenant, err = os.CRDClient.GetTenant(tenantName); err != nil {
tenant, err := f.CRDClient.GetTenant(tenantName)
if err != nil {
return "", err
}
if tenant.Spec.TenantID != "" {
return tenant.Spec.TenantID, nil
}
t, ok := os.Tenants[tenantName]
t, ok := f.Tenants[tenantName]
if !ok {
return "", nil
return "", fmt.Errorf("Tenant %s not exist", tenantName)
}
return t.ID, nil
}
// CheckTenantByID checks tenant exist or not by tenantID.
func (os *FakeOSClient) CheckTenantByID(tenantID string) (bool, error) {
for _, tenent := range os.Tenants {
// CheckTenantByID is a test implementation of Interface.CheckTenantByID.
func (f *FakeOSClient) CheckTenantByID(tenantID string) (bool, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("CheckTenantByID", tenantID)
if err := f.getError("CheckTenantByID"); err != nil {
return false, err
}
for _, tenent := range f.Tenants {
if tenent.ID == tenantID {
return true, nil
}
}
return false, ErrNotFound
return false, fmt.Errorf("Tenant %s not exist", tenantID)
}
// CreateUser is a test implementation of Interface.CreateUser.
func (f *FakeOSClient) CreateUser(username, password, tenantID string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("CreateUser", username, password, tenantID)
if err := f.getError("CreateUser"); err != nil {
return err
}
// CreateUser creates user with username, password in the tenant.
func (os *FakeOSClient) CreateUser(username, password, tenantID string) error {
user := &users.User{
Name: username,
TenantID: tenantID,
ID: userIDHash(username, tenantID),
}
os.Users[tenantID] = user
f.Users[tenantID] = user
return nil
}
// DeleteAllUsersOnTenant deletes all users on the tenant.
func (os *FakeOSClient) DeleteAllUsersOnTenant(tenantName string) error {
tenant := os.Tenants[tenantName]
// DeleteAllUsersOnTenant is a test implementation of Interface.DeleteAllUsersOnTenant.
func (f *FakeOSClient) DeleteAllUsersOnTenant(tenantName string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("DeleteAllUsersOnTenant", tenantName)
if err := f.getError("DeleteAllUsersOnTenant"); err != nil {
return err
}
delete(os.Users, tenant.ID)
tenant := f.Tenants[tenantName]
delete(f.Users, tenant.ID)
return nil
}
func (os *FakeOSClient) createNetwork(networkName, tenantID string) error {
if _, ok := os.Networks[networkName]; ok {
return ErrAlreadyExist
func (f *FakeOSClient) createNetwork(networkName, tenantID string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("createNetwork", networkName, tenantID)
if err := f.getError("createNetwork"); err != nil {
return err
}
if _, ok := f.Networks[networkName]; ok {
return fmt.Errorf("Network %s already exist", networkName)
}
network := &drivertypes.Network{
@ -231,18 +349,32 @@ func (os *FakeOSClient) createNetwork(networkName, tenantID string) error {
Uid: networkIDHash(networkName),
TenantID: tenantID,
}
os.Networks[networkName] = network
f.Networks[networkName] = network
return nil
}
func (os *FakeOSClient) deleteNetwork(networkName string) error {
delete(os.Networks, networkName)
func (f *FakeOSClient) deleteNetwork(networkName string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("deleteNetwork", networkName)
if err := f.getError("deleteNetwork"); err != nil {
return err
}
delete(f.Networks, networkName)
return nil
}
func (os *FakeOSClient) createRouter(routerName, tenantID string) error {
if _, ok := os.Routers[routerName]; ok {
return ErrAlreadyExist
func (f *FakeOSClient) createRouter(routerName, tenantID string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("createRouter", routerName, tenantID)
if err := f.getError("createRouter"); err != nil {
return err
}
if _, ok := f.Routers[routerName]; ok {
return fmt.Errorf("Router %s already exist", routerName)
}
router := &routers.Router{
@ -250,18 +382,32 @@ func (os *FakeOSClient) createRouter(routerName, tenantID string) error {
TenantID: tenantID,
ID: routerIDHash(routerName),
}
os.Routers[routerName] = router
f.Routers[routerName] = router
return nil
}
func (os *FakeOSClient) deleteRouter(routerName string) error {
delete(os.Routers, routerName)
func (f *FakeOSClient) deleteRouter(routerName string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("deleteRouter", routerName)
if err := f.getError("deleteRouter"); err != nil {
return err
}
delete(f.Routers, routerName)
return nil
}
func (os *FakeOSClient) createSubnet(subnetName, networkID, tenantID string) error {
if _, ok := os.Subnets[subnetName]; ok {
return ErrAlreadyExist
func (f *FakeOSClient) createSubnet(subnetName, networkID, tenantID string) error {
f.Lock()
defer f.Unlock()
f.appendCalled("createSubnet", subnetName, networkID, tenantID)
if err := f.getError("createSubnet"); err != nil {
return err
}
if _, ok := f.Subnets[subnetName]; ok {
return fmt.Errorf("Subnet %s already exist", subnetName)
}
subnet := &subnets.Subnet{
@ -270,77 +416,98 @@ func (os *FakeOSClient) createSubnet(subnetName, networkID, tenantID string) err
NetworkID: networkID,
ID: subnetIDHash(subnetName),
}
os.Subnets[subnetName] = subnet
f.Subnets[subnetName] = subnet
return nil
}
// CreateNetwork creates network.
// TODO(mozhuli): make it more general.
func (os *FakeOSClient) CreateNetwork(network *drivertypes.Network) error {
// CreateNetwork is a test implementation of Interface.CreateNetwork.
func (f *FakeOSClient) CreateNetwork(network *drivertypes.Network) error {
f.Lock()
defer f.Unlock()
f.appendCalled("CreateNetwork", network)
if err := f.getError("CreateNetwork"); err != nil {
return err
}
if len(network.Subnets) == 0 {
return errors.New("Subnets is null")
return fmt.Errorf("Subnets is null")
}
// create network
err := os.createNetwork(network.Name, network.TenantID)
err := f.createNetwork(network.Name, network.TenantID)
if err != nil {
return errors.New("Create network failed")
return err
}
// create router, and use network name as router name for convenience.
err = os.createRouter(network.Name, network.TenantID)
err = f.createRouter(network.Name, network.TenantID)
if err != nil {
os.deleteNetwork(network.Name)
return errors.New("Create router failed")
f.deleteNetwork(network.Name)
return err
}
// create subnets and connect them to router
err = os.createSubnet(network.Subnets[0].Name, network.Uid, network.TenantID)
err = f.createSubnet(network.Subnets[0].Name, network.Uid, network.TenantID)
if err != nil {
os.deleteRouter(network.Name)
os.deleteNetwork(network.Name)
return errors.New("Create subnet failed")
f.deleteRouter(network.Name)
f.deleteNetwork(network.Name)
return err
}
return nil
}
// GetNetworkByID gets network by networkID.
func (os *FakeOSClient) GetNetworkByID(networkID string) (*drivertypes.Network, error) {
// CreateTenant is a test implementation of Interface.CreateTenant.
func (f *FakeOSClient) GetNetworkByID(networkID string) (*drivertypes.Network, error) {
return nil, nil
}
// GetNetworkByName get network by networkName
func (os *FakeOSClient) GetNetworkByName(networkName string) (*drivertypes.Network, error) {
network, ok := os.Networks[networkName]
// GetNetworkByName is a test implementation of Interface.GetNetworkByName.
func (f *FakeOSClient) GetNetworkByName(networkName string) (*drivertypes.Network, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("GetNetworkByName", networkName)
if err := f.getError("GetNetworkByName"); err != nil {
return nil, err
}
network, ok := f.Networks[networkName]
if !ok {
return nil, ErrNotFound
return nil, fmt.Errorf("Network %s not exist", networkName)
}
return network, nil
}
// DeleteNetwork deletes network by networkName.
func (os *FakeOSClient) DeleteNetwork(networkName string) error {
// DeleteNetwork is a test implementation of Interface.DeleteNetwork.
func (f *FakeOSClient) DeleteNetwork(networkName string) error {
return nil
}
// GetProviderSubnet gets provider subnet by id
func (os *FakeOSClient) GetProviderSubnet(osSubnetID string) (*drivertypes.Subnet, error) {
// GetProviderSubnet is a test implementation of Interface.GetProviderSubnet.
func (f *FakeOSClient) GetProviderSubnet(osSubnetID string) (*drivertypes.Subnet, error) {
return nil, nil
}
// CreatePort creates port by neworkID, tenantID and portName.
func (os *FakeOSClient) CreatePort(networkID, tenantID, portName string) (*portsbinding.Port, error) {
// CreatePort is a test implementation of Interface.CreatePort.
func (f *FakeOSClient) CreatePort(networkID, tenantID, portName string) (*portsbinding.Port, error) {
return nil, nil
}
// GetPort gets port by portName.
func (os *FakeOSClient) GetPort(name string) (*ports.Port, error) {
// GetPort is a test implementation of Interface.GetPort.
func (f *FakeOSClient) GetPort(name string) (*ports.Port, error) {
return nil, nil
}
// ListPorts list all ports which have the deviceOwner in the network.
func (os *FakeOSClient) ListPorts(networkID, deviceOwner string) ([]ports.Port, error) {
// ListPorts is a test implementation of Interface.ListPorts.
func (f *FakeOSClient) ListPorts(networkID, deviceOwner string) ([]ports.Port, error) {
f.Lock()
defer f.Unlock()
f.appendCalled("ListPorts", networkID, deviceOwner)
if err := f.getError("ListPorts"); err != nil {
return nil, err
}
var results []ports.Port
portList, ok := os.Ports[networkID]
portList, ok := f.Ports[networkID]
if !ok {
return results, nil
}
@ -353,48 +520,47 @@ func (os *FakeOSClient) ListPorts(networkID, deviceOwner string) ([]ports.Port,
return results, nil
}
// DeletePortByName deletes port by portName.
func (os *FakeOSClient) DeletePortByName(portName string) error {
// DeletePortByName is a test implementation of Interface.DeletePortByName.
func (f *FakeOSClient) DeletePortByName(portName string) error {
return nil
}
// DeletePortByID deletes port by portID.
func (os *FakeOSClient) DeletePortByID(portID string) error {
// DeletePortByID is a test implementation of Interface.DeletePortByID.
func (f *FakeOSClient) DeletePortByID(portID string) error {
return nil
}
// UpdatePortsBinding updates port binding.
func (os *FakeOSClient) UpdatePortsBinding(portID, deviceOwner string) error {
// UpdatePortsBinding is a test implementation of Interface.UpdatePortsBinding.
func (f *FakeOSClient) UpdatePortsBinding(portID, deviceOwner string) error {
return nil
}
// LoadBalancerExist returns whether a load balancer has already been exist.
func (os *FakeOSClient) LoadBalancerExist(name string) (bool, error) {
// LoadBalancerExist is a test implementation of Interface.LoadBalancerExist.
func (f *FakeOSClient) LoadBalancerExist(name string) (bool, error) {
return true, nil
}
// EnsureLoadBalancer ensures a load balancer is created.
func (os *FakeOSClient) EnsureLoadBalancer(lb *LoadBalancer) (*LoadBalancerStatus, error) {
// EnsureLoadBalancer is a test implementation of Interface.EnsureLoadBalancer.
func (f *FakeOSClient) EnsureLoadBalancer(lb *LoadBalancer) (*LoadBalancerStatus, error) {
return nil, nil
}
// EnsureLoadBalancerDeleted ensures a load balancer is deleted.
func (os *FakeOSClient) EnsureLoadBalancerDeleted(name string) error {
// EnsureLoadBalancerDeleted is a test implementation of Interface.EnsureLoadBalancerDeleted.
func (f *FakeOSClient) EnsureLoadBalancerDeleted(name string) error {
return nil
}
// GetCRDClient returns the CRDClient.
// TODO(mozhuli): use fakeCRDClient.
func (os *FakeOSClient) GetCRDClient() *crdClient.CRDClient {
return os.CRDClient
// GetCRDClient is a test implementation of Interface.GetCRDClient.
func (f *FakeOSClient) GetCRDClient() crdClient.Interface {
return f.CRDClient
}
// GetPluginName returns the plugin name.
func (os *FakeOSClient) GetPluginName() string {
return os.PluginName
// GetPluginName is a test implementation of Interface.GetPluginName.
func (f *FakeOSClient) GetPluginName() string {
return f.PluginName
}
// GetIntegrationBridge returns the integration bridge name.
func (os *FakeOSClient) GetIntegrationBridge() string {
return os.IntegrationBridge
// GetIntegrationBridge is a test implementation of Interface.GetIntegrationBridge.
func (f *FakeOSClient) GetIntegrationBridge() string {
return f.IntegrationBridge
}

View File

@ -19,6 +19,7 @@ package proxy
import (
"fmt"
"strings"
"sync"
)
const (
@ -35,6 +36,7 @@ type Rule map[string]string
// FakeIPTables have noop implementation of fake iptables function.
type FakeIPTables struct {
sync.Mutex
namespace string
NSLines map[string][]byte
}
@ -55,6 +57,8 @@ func (f *FakeIPTables) ensureRule(op, chain string, args []string) error {
}
func (f *FakeIPTables) restoreAll(data []byte) error {
f.Lock()
defer f.Unlock()
d := make([]byte, len(data))
copy(d, data)
f.NSLines[f.namespace] = d

View File

@ -24,6 +24,7 @@ import (
"github.com/davecgh/go-spew/spew"
crdClient "git.openstack.org/openstack/stackube/pkg/kubecrd"
"git.openstack.org/openstack/stackube/pkg/openstack"
"git.openstack.org/openstack/stackube/pkg/util"
@ -192,8 +193,13 @@ func TestClusterNoEndpoint(t *testing.T) {
// Creates fake iptables.
ipt := NewFake()
// Creates fake CRD client.
crdClient, err := crdClient.NewFake()
if err != nil {
t.Fatal("Failed init fake CRD client")
}
// Create a fake openstack client.
osClient := openstack.NewFake()
osClient := openstack.NewFake(crdClient)
// Injects fake network.
networkName := util.BuildNetworkName(testNamespace, testNamespace)
osClient.SetNetwork(networkName, "123")
@ -226,7 +232,7 @@ func TestClusterNoEndpoint(t *testing.T) {
}
}
func noClusterIPType(svcType v1.ServiceType) []Rule {
func noClusterIPType(t *testing.T, svcType v1.ServiceType) []Rule {
testNamespace := "test"
svcIP := "1.2.3.4"
svcPort := 80
@ -237,8 +243,13 @@ func noClusterIPType(svcType v1.ServiceType) []Rule {
// Creates fake iptables.
ipt := NewFake()
// Creates fake CRD client.
crdClient, err := crdClient.NewFake()
if err != nil {
t.Fatal("Failed init fake CRD client")
}
// Create a fake openstack client.
osClient := openstack.NewFake()
osClient := openstack.NewFake(crdClient)
// Injects fake network.
networkName := util.BuildNetworkName(testNamespace, testNamespace)
osClient.SetNetwork(networkName, "123")
@ -277,7 +288,7 @@ func TestNoClusterIPType(t *testing.T) {
}
for k, tc := range testCases {
got := noClusterIPType(tc)
got := noClusterIPType(t, tc)
if len(got) != 0 {
errorf(fmt.Sprintf("%v: unexpected rule for chain %v without ClusterIP service type", k, ChainSKPrerouting), got, t)
}
@ -295,8 +306,13 @@ func TestClusterIPEndpointsJump(t *testing.T) {
// Creates fake iptables.
ipt := NewFake()
// Creates fake CRD client.
crdClient, err := crdClient.NewFake()
if err != nil {
t.Fatal("Failed init fake CRD client")
}
// Create a fake openstack client.
osClient := openstack.NewFake()
osClient := openstack.NewFake(crdClient)
// Injects fake network.
networkName := util.BuildNetworkName(testNamespace, testNamespace)
osClient.SetNetwork(networkName, "123")
@ -365,8 +381,13 @@ func TestMultiNamespacesService(t *testing.T) {
// Creates fake iptables.
ipt := NewFake()
// Creates fake CRD client.
crdClient, err := crdClient.NewFake()
if err != nil {
t.Fatal("Failed init fake CRD client")
}
// Create a fake openstack client.
osClient := openstack.NewFake()
osClient := openstack.NewFake(crdClient)
// Injects fake network.
networkName1 := util.BuildNetworkName(ns1, ns1)
osClient.SetNetwork(networkName1, "123")