Commit 29d225e9 authored by Renaud Gaubert's avatar Renaud Gaubert

Update pluginwatcher tests

parent 4d18aa63
package(default_visibility = ["//visibility:public"]) load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library( go_library(
name = "go_default_library", name = "go_default_library",
...@@ -12,8 +6,10 @@ go_library( ...@@ -12,8 +6,10 @@ go_library(
"example_handler.go", "example_handler.go",
"example_plugin.go", "example_plugin.go",
"plugin_watcher.go", "plugin_watcher.go",
"types.go",
], ],
importpath = "k8s.io/kubernetes/pkg/kubelet/util/pluginwatcher", importpath = "k8s.io/kubernetes/pkg/kubelet/util/pluginwatcher",
visibility = ["//visibility:public"],
deps = [ deps = [
"//pkg/kubelet/apis/pluginregistration/v1alpha1:go_default_library", "//pkg/kubelet/apis/pluginregistration/v1alpha1:go_default_library",
"//pkg/kubelet/util/pluginwatcher/example_plugin_apis/v1beta1:go_default_library", "//pkg/kubelet/util/pluginwatcher/example_plugin_apis/v1beta1:go_default_library",
...@@ -27,6 +23,16 @@ go_library( ...@@ -27,6 +23,16 @@ go_library(
], ],
) )
go_test(
name = "go_default_test",
srcs = ["plugin_watcher_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubelet/apis/pluginregistration/v1alpha1:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
],
)
filegroup( filegroup(
name = "package-srcs", name = "package-srcs",
srcs = glob(["**"]), srcs = glob(["**"]),
...@@ -44,14 +50,3 @@ filegroup( ...@@ -44,14 +50,3 @@ filegroup(
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
go_test(
name = "go_default_test",
srcs = ["plugin_watcher_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubelet/apis/pluginregistration/v1alpha1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
],
)
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/golang/glog"
"golang.org/x/net/context" "golang.org/x/net/context"
v1beta1 "k8s.io/kubernetes/pkg/kubelet/util/pluginwatcher/example_plugin_apis/v1beta1" v1beta1 "k8s.io/kubernetes/pkg/kubelet/util/pluginwatcher/example_plugin_apis/v1beta1"
...@@ -30,41 +31,61 @@ import ( ...@@ -30,41 +31,61 @@ import (
) )
type exampleHandler struct { type exampleHandler struct {
registeredPlugins map[string]struct{} SupportedVersions []string
mutex sync.Mutex ExpectedNames map[string]int
chanForHandlerAckErrors chan error // for testing
eventChans map[string]chan examplePluginEvent // map[pluginName]eventChan
m sync.Mutex
count int
} }
type examplePluginEvent int
const (
exampleEventValidate examplePluginEvent = 0
exampleEventRegister examplePluginEvent = 1
exampleEventDeRegister examplePluginEvent = 2
exampleEventError examplePluginEvent = 3
)
// NewExampleHandler provide a example handler // NewExampleHandler provide a example handler
func NewExampleHandler() *exampleHandler { func NewExampleHandler(supportedVersions []string) *exampleHandler {
return &exampleHandler{ return &exampleHandler{
chanForHandlerAckErrors: make(chan error), SupportedVersions: supportedVersions,
registeredPlugins: make(map[string]struct{}), ExpectedNames: make(map[string]int),
eventChans: make(map[string]chan examplePluginEvent),
} }
} }
func (h *exampleHandler) Cleanup() error { func (p *exampleHandler) ValidatePlugin(pluginName string, endpoint string, versions []string) error {
h.mutex.Lock() p.SendEvent(pluginName, exampleEventValidate)
defer h.mutex.Unlock()
h.registeredPlugins = make(map[string]struct{})
return nil
}
func (h *exampleHandler) Handler(pluginName string, endpoint string, versions []string, sockPath string) (chan bool, error) { n, ok := p.DecreasePluginCount(pluginName)
if !ok && n > 0 {
return fmt.Errorf("pluginName('%s') wasn't expected (count is %d)", pluginName, n)
}
// check for supported versions if !reflect.DeepEqual(versions, p.SupportedVersions) {
if !reflect.DeepEqual([]string{"v1beta1", "v1beta2"}, versions) { return fmt.Errorf("versions('%v') != supported versions('%v')", versions, p.SupportedVersions)
return nil, fmt.Errorf("not the supported versions: %s", versions)
} }
// this handler expects non-empty endpoint as an example // this handler expects non-empty endpoint as an example
if len(endpoint) == 0 { if len(endpoint) == 0 {
return nil, errors.New("expecting non empty endpoint") return errors.New("expecting non empty endpoint")
} }
_, conn, err := dial(sockPath) return nil
}
func (p *exampleHandler) RegisterPlugin(pluginName, endpoint string) error {
p.SendEvent(pluginName, exampleEventRegister)
// Verifies the grpcServer is ready to serve services.
_, conn, err := dial(endpoint, time.Second)
if err != nil { if err != nil {
return nil, err return fmt.Errorf("Failed dialing endpoint (%s): %v", endpoint, err)
} }
defer conn.Close() defer conn.Close()
...@@ -73,33 +94,54 @@ func (h *exampleHandler) Handler(pluginName string, endpoint string, versions [] ...@@ -73,33 +94,54 @@ func (h *exampleHandler) Handler(pluginName string, endpoint string, versions []
v1beta2Client := v1beta2.NewExampleClient(conn) v1beta2Client := v1beta2.NewExampleClient(conn)
// Tests v1beta1 GetExampleInfo // Tests v1beta1 GetExampleInfo
if _, err = v1beta1Client.GetExampleInfo(context.Background(), &v1beta1.ExampleRequest{}); err != nil { _, err = v1beta1Client.GetExampleInfo(context.Background(), &v1beta1.ExampleRequest{})
return nil, err if err != nil {
return fmt.Errorf("Failed GetExampleInfo for v1beta2Client(%s): %v", endpoint, err)
}
// Tests v1beta1 GetExampleInfo
_, err = v1beta2Client.GetExampleInfo(context.Background(), &v1beta2.ExampleRequest{})
if err != nil {
return fmt.Errorf("Failed GetExampleInfo for v1beta2Client(%s): %v", endpoint, err)
} }
// Tests v1beta2 GetExampleInfo return nil
if _, err = v1beta2Client.GetExampleInfo(context.Background(), &v1beta2.ExampleRequest{}); err != nil { }
return nil, err
func (p *exampleHandler) DeRegisterPlugin(pluginName string) {
p.SendEvent(pluginName, exampleEventDeRegister)
}
func (p *exampleHandler) EventChan(pluginName string) chan examplePluginEvent {
return p.eventChans[pluginName]
}
func (p *exampleHandler) SendEvent(pluginName string, event examplePluginEvent) {
glog.V(2).Infof("Sending %v for plugin %s over chan %v", event, pluginName, p.eventChans[pluginName])
p.eventChans[pluginName] <- event
}
func (p *exampleHandler) AddPluginName(pluginName string) {
p.m.Lock()
defer p.m.Unlock()
v, ok := p.ExpectedNames[pluginName]
if !ok {
p.eventChans[pluginName] = make(chan examplePluginEvent)
v = 1
} }
// handle registered plugin p.ExpectedNames[pluginName] = v
h.mutex.Lock() }
if _, exist := h.registeredPlugins[pluginName]; exist {
h.mutex.Unlock() func (p *exampleHandler) DecreasePluginCount(pluginName string) (old int, ok bool) {
return nil, fmt.Errorf("plugin %s already registered", pluginName) p.m.Lock()
defer p.m.Unlock()
v, ok := p.ExpectedNames[pluginName]
if !ok {
v = -1
} }
h.registeredPlugins[pluginName] = struct{}{}
h.mutex.Unlock() return v, ok
chanForAckOfNotification := make(chan bool)
go func() {
select {
case <-chanForAckOfNotification:
// TODO: handle the negative scenario
close(chanForAckOfNotification)
case <-time.After(time.Second):
h.chanForHandlerAckErrors <- errors.New("Timed out while waiting for notification ack")
}
}()
return chanForAckOfNotification, nil
} }
...@@ -18,7 +18,9 @@ package pluginwatcher ...@@ -18,7 +18,9 @@ package pluginwatcher
import ( import (
"errors" "errors"
"fmt"
"net" "net"
"os"
"sync" "sync"
"time" "time"
...@@ -39,6 +41,7 @@ type examplePlugin struct { ...@@ -39,6 +41,7 @@ type examplePlugin struct {
endpoint string // for testing endpoint string // for testing
pluginName string pluginName string
pluginType string pluginType string
versions []string
} }
type pluginServiceV1Beta1 struct { type pluginServiceV1Beta1 struct {
...@@ -73,12 +76,13 @@ func NewExamplePlugin() *examplePlugin { ...@@ -73,12 +76,13 @@ func NewExamplePlugin() *examplePlugin {
} }
// NewTestExamplePlugin returns an initialized examplePlugin instance for testing // NewTestExamplePlugin returns an initialized examplePlugin instance for testing
func NewTestExamplePlugin(pluginName string, pluginType string, endpoint string) *examplePlugin { func NewTestExamplePlugin(pluginName string, pluginType string, endpoint string, advertisedVersions ...string) *examplePlugin {
return &examplePlugin{ return &examplePlugin{
pluginName: pluginName, pluginName: pluginName,
pluginType: pluginType, pluginType: pluginType,
registrationStatus: make(chan registerapi.RegistrationStatus),
endpoint: endpoint, endpoint: endpoint,
versions: advertisedVersions,
registrationStatus: make(chan registerapi.RegistrationStatus),
} }
} }
...@@ -88,36 +92,48 @@ func (e *examplePlugin) GetInfo(ctx context.Context, req *registerapi.InfoReques ...@@ -88,36 +92,48 @@ func (e *examplePlugin) GetInfo(ctx context.Context, req *registerapi.InfoReques
Type: e.pluginType, Type: e.pluginType,
Name: e.pluginName, Name: e.pluginName,
Endpoint: e.endpoint, Endpoint: e.endpoint,
SupportedVersions: []string{"v1beta1", "v1beta2"}, SupportedVersions: e.versions,
}, nil }, nil
} }
func (e *examplePlugin) NotifyRegistrationStatus(ctx context.Context, status *registerapi.RegistrationStatus) (*registerapi.RegistrationStatusResponse, error) { func (e *examplePlugin) NotifyRegistrationStatus(ctx context.Context, status *registerapi.RegistrationStatus) (*registerapi.RegistrationStatusResponse, error) {
glog.Errorf("Registration is: %v\n", status)
if e.registrationStatus != nil { if e.registrationStatus != nil {
e.registrationStatus <- *status e.registrationStatus <- *status
} }
if !status.PluginRegistered {
glog.Errorf("Registration failed: %s\n", status.Error)
}
return &registerapi.RegistrationStatusResponse{}, nil return &registerapi.RegistrationStatusResponse{}, nil
} }
// Serve starts example plugin grpc server // Serve starts a pluginwatcher server and one or more of the plugin services
func (e *examplePlugin) Serve(socketPath string) error { func (e *examplePlugin) Serve(services ...string) error {
glog.Infof("starting example server at: %s\n", socketPath) glog.Infof("starting example server at: %s\n", e.endpoint)
lis, err := net.Listen("unix", socketPath) lis, err := net.Listen("unix", e.endpoint)
if err != nil { if err != nil {
return err return err
} }
glog.Infof("example server started at: %s\n", socketPath)
glog.Infof("example server started at: %s\n", e.endpoint)
e.grpcServer = grpc.NewServer() e.grpcServer = grpc.NewServer()
// Registers kubelet plugin watcher api. // Registers kubelet plugin watcher api.
registerapi.RegisterRegistrationServer(e.grpcServer, e) registerapi.RegisterRegistrationServer(e.grpcServer, e)
// Registers services for both v1beta1 and v1beta2 versions.
v1beta1 := &pluginServiceV1Beta1{server: e} for _, service := range services {
v1beta1.RegisterService() switch service {
v1beta2 := &pluginServiceV1Beta2{server: e} case "v1beta1":
v1beta2.RegisterService() v1beta1 := &pluginServiceV1Beta1{server: e}
v1beta1.RegisterService()
break
case "v1beta2":
v1beta2 := &pluginServiceV1Beta2{server: e}
v1beta2.RegisterService()
break
default:
return fmt.Errorf("Unsupported service: '%s'", service)
}
}
// Starts service // Starts service
e.wg.Add(1) e.wg.Add(1)
...@@ -128,22 +144,30 @@ func (e *examplePlugin) Serve(socketPath string) error { ...@@ -128,22 +144,30 @@ func (e *examplePlugin) Serve(socketPath string) error {
glog.Errorf("example server stopped serving: %v", err) glog.Errorf("example server stopped serving: %v", err)
} }
}() }()
return nil return nil
} }
func (e *examplePlugin) Stop() error { func (e *examplePlugin) Stop() error {
glog.Infof("Stopping example server\n") glog.Infof("Stopping example server at: %s\n", e.endpoint)
e.grpcServer.Stop() e.grpcServer.Stop()
c := make(chan struct{}) c := make(chan struct{})
go func() { go func() {
defer close(c) defer close(c)
e.wg.Wait() e.wg.Wait()
}() }()
select { select {
case <-c: case <-c:
return nil break
case <-time.After(time.Second): case <-time.After(time.Second):
glog.Errorf("Timed out on waiting for stop completion")
return errors.New("Timed out on waiting for stop completion") return errors.New("Timed out on waiting for stop completion")
} }
if err := os.Remove(e.endpoint); err != nil && !os.IsNotExist(err) {
return err
}
return nil
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment