Fix node create after delete

node.ResourceVersion must not be set when creating a node.
This issue prevents vk from resolving issues after the vk node instance
has been deleted (for whatever reason).
This commit is contained in:
Brian Goff
2019-04-03 15:17:33 -07:00
parent af06b005b2
commit 99c07d487e
6 changed files with 127 additions and 5 deletions

View File

@@ -7,11 +7,10 @@ import (
"testing"
"time"
"k8s.io/api/core/v1"
"github.com/virtual-kubelet/virtual-kubelet/vkubelet"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
"github.com/virtual-kubelet/virtual-kubelet/vkubelet"
)
const (

View File

@@ -0,0 +1,58 @@
package framework
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
watchapi "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/watch"
)
// WaitUntilNodeCondition establishes a watch on the vk node.
// Then, it waits for the specified condition function to be verified.
func (f *Framework) WaitUntilNodeCondition(fn watch.ConditionFunc) error {
// Create a field selector that matches the specified Pod resource.
fs := fields.OneTermEqualSelector("metadata.name", f.NodeName).String()
// Create a ListWatch so we can receive events for the matched Pod resource.
lw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
options.FieldSelector = fs
return f.KubeClient.CoreV1().Nodes().List(options)
},
WatchFunc: func(options metav1.ListOptions) (watchapi.Interface, error) {
options.FieldSelector = fs
return f.KubeClient.CoreV1().Nodes().Watch(options)
},
}
// Watch for updates to the Pod resource until fn is satisfied, or until the timeout is reached.
ctx, cancel := context.WithTimeout(context.Background(), defaultWatchTimeout)
defer cancel()
last, err := watch.UntilWithSync(ctx, lw, &corev1.Node{}, nil, fn)
if err != nil {
return err
}
if last == nil {
return fmt.Errorf("no events received for node %q", f.NodeName)
}
return nil
}
// WaitUntilNodeAdded is a watch condition which waits until the VK node object
// is added.
func (f *Framework) WaitUntilNodeAdded(event watchapi.Event) (bool, error) {
if event.Type != watchapi.Added {
return false, nil
}
return event.Object.(*corev1.Node).Name == f.NodeName, nil
}
// DeleteNode deletes the vk node used by the framework
func (f *Framework) DeleteNode() error {
return f.KubeClient.CoreV1().Nodes().Delete(f.NodeName, nil)
}

51
test/e2e/node_test.go Normal file
View File

@@ -0,0 +1,51 @@
// +build e2e
package e2e
import (
"testing"
"time"
"gotest.tools/assert"
watchapi "k8s.io/apimachinery/pkg/watch"
)
// TestNodeCreateAfterDelete makes sure that a node is automatically recreated
// if it is deleted while VK is running.
func TestNodeCreateAfterDelete(t *testing.T) {
chErr := make(chan error, 1)
chDone := make(chan struct{})
defer close(chDone)
go func() {
var deleted bool
wait := func(e watchapi.Event) (bool, error) {
select {
case <-chDone:
return true, nil
default:
}
if deleted {
return f.WaitUntilNodeAdded(e)
}
if e.Type == watchapi.Deleted {
deleted = true
}
return false, nil
}
chErr <- f.WaitUntilNodeCondition(wait)
}()
assert.NilError(t, f.DeleteNode())
timer := time.NewTimer(60 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
t.Fatal("timeout waiting for node to be recreated")
case err := <-chErr:
assert.NilError(t, err)
}
}