diff --git a/Gopkg.lock b/Gopkg.lock index 25bec80c0..4eafb9d44 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1971,7 +1971,6 @@ "github.com/spf13/pflag", "github.com/tidwall/gjson", "golang.org/x/tools/cmd/goimports", - "gopkg.in/yaml.v2", "k8s.io/api/core/v1", "k8s.io/apimachinery/pkg/api/errors", "k8s.io/apimachinery/pkg/apis/meta/v1", @@ -1982,6 +1981,7 @@ "k8s.io/client-go/kubernetes", "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/plugin/pkg/client/auth", + "k8s.io/client-go/util/retry", "k8s.io/code-generator/cmd/client-gen", "k8s.io/code-generator/cmd/conversion-gen", "k8s.io/code-generator/cmd/deepcopy-gen", diff --git a/Makefile b/Makefile index 1581f727f..3e67ea9fc 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,11 @@ E2E_TEST_ARGS ?= -test.v -test.timeout=40m -ginkgo.v -ginkgo.slowSpecThreshold=6 ifdef E2E_TEST_FOCUS E2E_TEST_ARGS += -ginkgo.focus $(E2E_TEST_FOCUS) endif +# Unless explicitly focused, always skip the cleanup test (it removes a node) ifdef E2E_TEST_SKIP - E2E_TEST_ARGS += -ginkgo.skip $(E2E_TEST_SKIP) + E2E_TEST_ARGS += -ginkgo.skip .*NNS.*cleanup.*|$(E2E_TEST_SKIP) +else + E2E_TEST_ARGS += -ginkgo.skip .*NNS.*cleanup.* endif ifdef E2E_TEST_EXTRA_ARGS E2E_TEST_ARGS += $(E2E_TEST_EXTRA_ARGS) diff --git a/automation/check-patch.k8s-1.14.6.node-removal.mounts b/automation/check-patch.k8s-1.14.6.node-removal.mounts new file mode 120000 index 000000000..c459a2524 --- /dev/null +++ b/automation/check-patch.k8s-1.14.6.node-removal.mounts @@ -0,0 +1 @@ +check-patch.mounts \ No newline at end of file diff --git a/automation/check-patch.k8s-1.14.6.node-removal.packages b/automation/check-patch.k8s-1.14.6.node-removal.packages new file mode 120000 index 000000000..3858aae7d --- /dev/null +++ b/automation/check-patch.k8s-1.14.6.node-removal.packages @@ -0,0 +1 @@ +check-patch.packages \ No newline at end of file diff --git a/automation/check-patch.k8s-1.14.6.node-removal.sh b/automation/check-patch.k8s-1.14.6.node-removal.sh new file mode 120000 index 000000000..a61652ade --- /dev/null +++ b/automation/check-patch.k8s-1.14.6.node-removal.sh @@ -0,0 +1 @@ +check-patch.sh \ No newline at end of file diff --git a/automation/check-patch.sh b/automation/check-patch.sh index 561a9e579..60522339a 100755 --- a/automation/check-patch.sh +++ b/automation/check-patch.sh @@ -7,6 +7,7 @@ main() { TARGET="${TARGET%.*}" TARGET="${TARGET#*.}" TARGET="${TARGET//[.]default-bridge/}" + TARGET="${TARGET//[.]node-removal/}" echo "TARGET=$TARGET" export TARGET echo "Setup Go paths" diff --git a/automation/test.sh b/automation/test.sh index 703791f82..89bff75e4 100755 --- a/automation/test.sh +++ b/automation/test.sh @@ -26,4 +26,8 @@ else skip_tests=".*move.*default.*IP.*" fi +if [[ $SCRIPT_NAME =~ node-removal ]]; then + focus_tests=".*NNS.*cleanup.*" +fi + make E2E_TEST_EXTRA_ARGS="$test_args" E2E_TEST_FOCUS="$focus_tests" E2E_TEST_SKIP="$skip_tests" test/e2e diff --git a/pkg/controller/node/node_controller.go b/pkg/controller/node/node_controller.go index ff9371ef8..17390b793 100644 --- a/pkg/controller/node/node_controller.go +++ b/pkg/controller/node/node_controller.go @@ -52,7 +52,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return nmstate.EventIsForThisNode(createEvent.Meta) }, DeleteFunc: func(event.DeleteEvent) bool { - return false // TODO: implement delete + return false }, UpdateFunc: func(event.UpdateEvent) bool { return false @@ -61,7 +61,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return false }, } - //TODO: Watch deletes too handling it correctly at Reconciler // Watch for changes to primary resource Node err = c.Watch(&source.Kind{Type: &corev1.Node{}}, &handler.EnqueueRequestForObject{}, onCreationForThisNode) if err != nil { @@ -104,13 +103,12 @@ func (r *ReconcileNode) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } - //TODO: Manage deletes _, err = nmstate.GetNodeNetworkState(r.client, request.Name) if err != nil { if !errors.IsNotFound(err) { return reconcile.Result{}, fmt.Errorf("error at node reconcile accessing NodeNetworkState: %v", err) } else { - err = nmstate.InitializeNodeNeworkState(r.client, request.Name) + err = nmstate.InitializeNodeNeworkState(r.client, instance, r.scheme) if err != nil { return reconcile.Result{}, fmt.Errorf("error at node reconcile creating NodeNetworkState: %v", err) } diff --git a/pkg/helper/client.go b/pkg/helper/client.go index 2665eb254..c9328b122 100644 --- a/pkg/helper/client.go +++ b/pkg/helper/client.go @@ -10,7 +10,9 @@ import ( "strings" "time" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" @@ -122,16 +124,20 @@ func GetNodeNetworkState(client client.Client, nodeName string) (nmstatev1alpha1 return nodeNetworkState, err } -func InitializeNodeNeworkState(client client.Client, nodeName string) error { +func InitializeNodeNeworkState(client client.Client, node *corev1.Node, scheme *runtime.Scheme) error { + ownerRefList := []metav1.OwnerReference{{Name: node.ObjectMeta.Name, Kind: "Node", APIVersion: "v1", UID: node.UID}} + nodeNetworkState := nmstatev1alpha1.NodeNetworkState{ // Create NodeNetworkState for this node ObjectMeta: metav1.ObjectMeta{ - Name: nodeName, + Name: node.ObjectMeta.Name, + OwnerReferences: ownerRefList, }, Spec: nmstatev1alpha1.NodeNetworkStateSpec{ - NodeName: nodeName, + NodeName: node.ObjectMeta.Name, }, } + err := client.Create(context.TODO(), &nodeNetworkState) if err != nil { return fmt.Errorf("error creating NodeNetworkState: %v, %+v", err, nodeNetworkState) diff --git a/stdci.yaml b/stdci.yaml index cadd7f90f..b27e4b1c0 100644 --- a/stdci.yaml +++ b/stdci.yaml @@ -1,5 +1,6 @@ sub-stages: - k8s-1.14.6.default-bridge + - k8s-1.14.6.node-removal - k8s-1.14.6 - os-3.11.0 diff --git a/test/e2e/nns_cleanup_test.go b/test/e2e/nns_cleanup_test.go new file mode 100644 index 000000000..24df40e96 --- /dev/null +++ b/test/e2e/nns_cleanup_test.go @@ -0,0 +1,47 @@ +package e2e + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + + framework "github.com/operator-framework/operator-sdk/pkg/test" + + nmstatev1alpha1 "github.com/nmstate/kubernetes-nmstate/pkg/apis/nmstate/v1alpha1" +) + +var _ = Describe("NNS cleanup", func() { + var nodeName types.NamespacedName + + BeforeEach(func() { + nodeName = types.NamespacedName{Name: nodes[0]} + + By("Checking that NNS exists") + Eventually(func() error { + return framework.Global.Client.Get(context.TODO(), nodeName, &nmstatev1alpha1.NodeNetworkState{}) + }, ReadTimeout, ReadInterval).ShouldNot(HaveOccurred()) + }) + + Context("after node removal", func() { + nodeToDelete := &corev1.Node{} + + BeforeEach(func() { + By("Getting the node we want to delete") + err := framework.Global.Client.Get(context.TODO(), nodeName, nodeToDelete) + Expect(err).To(BeNil()) + + By("Deleting the node") + err = framework.Global.Client.Delete(context.TODO(), nodeToDelete) + Expect(err).To(BeNil()) + }) + + It("should remove NNS of that node", func() { + Eventually(func() error { + return framework.Global.Client.Get(context.TODO(), nodeName, &nmstatev1alpha1.NodeNetworkState{}) + }, ReadTimeout, ReadInterval).Should(HaveOccurred()) + }) + }) +})