Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ping external ip to verify connectivity #202

Merged
merged 1 commit into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM fedora:30

RUN sudo dnf install -y nmstate iproute && \
RUN sudo dnf install -y nmstate iproute iputils && \
sudo dnf clean all

# TODO: Delete this line after we update nmstate to include the change
Expand Down
41 changes: 41 additions & 0 deletions pkg/helper/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
yaml "sigs.k8s.io/yaml"

"github.com/tidwall/gjson"

"github.com/gobwas/glob"
nmstatev1alpha1 "github.com/nmstate/kubernetes-nmstate/pkg/apis/nmstate/v1alpha1"
)
Expand Down Expand Up @@ -159,6 +161,34 @@ func UpdateCurrentState(client client.Client, nodeNetworkState *nmstatev1alpha1.
return nil
}

func ping(target string) (string, error) {
cmd := exec.Command("ping", "-c", "3", target)
var outputBuffer bytes.Buffer
cmd.Stdout = &outputBuffer
cmd.Stderr = &outputBuffer
return outputBuffer.String(), cmd.Run()
}

func defaultGw() (string, error) {
observedStateRaw, err := show()
if err != nil {
return "", fmt.Errorf("error running nmstatectl show: %v", err)
}

currentState, err := yaml.YAMLToJSON([]byte(observedStateRaw))
qinqon marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return "", fmt.Errorf("Impossible to convert current state to JSON")
}

defaultGw := gjson.ParseBytes([]byte(currentState)).
qinqon marked this conversation as resolved.
Show resolved Hide resolved
Get("routes.running.#(destination==\"0.0.0.0/0\").next-hop-address").String()
if defaultGw == "" {
return "", fmt.Errorf("Impossible to retrieve default gw")
}

return defaultGw, nil
qinqon marked this conversation as resolved.
Show resolved Hide resolved
}

func ApplyDesiredState(nodeNetworkState *nmstatev1alpha1.NodeNetworkState) (string, error) {
desiredState := string(nodeNetworkState.Spec.DesiredState)
if len(desiredState) == 0 {
Expand Down Expand Up @@ -188,10 +218,21 @@ func ApplyDesiredState(nodeNetworkState *nmstatev1alpha1.NodeNetworkState) (stri
}
}

defaultGw, err := defaultGw()
if err != nil {
return commandOutput, rollback(err)
}

pingOutput, err := ping(defaultGw)
if err != nil {
return pingOutput, rollback(fmt.Errorf("error pinging external address after network reconfiguration: %v", err))
}

_, err = commit()
if err != nil {
return commandOutput, rollback(err)
}

qinqon marked this conversation as resolved.
Show resolved Hide resolved
commandOutput += fmt.Sprintf("setOutput: %s \n", setOutput)
return commandOutput, nil
}
Expand Down
21 changes: 0 additions & 21 deletions test/e2e/default_bridged_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ package e2e

import (
"context"
"fmt"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/tidwall/gjson"

yaml "sigs.k8s.io/yaml"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"

Expand Down Expand Up @@ -118,31 +115,13 @@ var _ = Describe("NodeNetworkConfigurationPolicy default bridged network", func(
})
})

func currentStateJSON(node string) []byte {
key := types.NamespacedName{Name: node}
currentState := nodeNetworkState(key).Status.CurrentState
currentStateJson, err := yaml.YAMLToJSON([]byte(currentState))
ExpectWithOffset(1, err).ToNot(HaveOccurred())
return currentStateJson
}

func ipv4Address(node string, name string) string {
path := fmt.Sprintf("interfaces.#(name==\"%s\").ipv4.address.0.ip", name)
return gjson.ParseBytes(currentStateJSON(node)).Get(path).String()
}

func defaultRouteNextHopInterface(node string) AsyncAssertion {
return Eventually(func() string {
path := "routes.running.#(destination==\"0.0.0.0/0\").next-hop-interface"
return gjson.ParseBytes(currentStateJSON(node)).Get(path).String()
}, 15*time.Second, 1*time.Second)
}

func dhcpFlag(node string, name string) bool {
path := fmt.Sprintf("interfaces.#(name==\"%s\").ipv4.dhcp", name)
return gjson.ParseBytes(currentStateJSON(node)).Get(path).Bool()
}

func nodeReadyConditionStatus(nodeName string) (corev1.ConditionStatus, error) {
key := types.NamespacedName{Name: nodeName}
node := corev1.Node{}
Expand Down
54 changes: 53 additions & 1 deletion test/e2e/rollback_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,30 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

nmstatev1alpha1 "github.com/nmstate/kubernetes-nmstate/pkg/apis/nmstate/v1alpha1"
)

func badDefaultGw(address string, nic string) nmstatev1alpha1.State {
return nmstatev1alpha1.State(fmt.Sprintf(`interfaces:
- name: %s
type: ethernet
state: up
ipv4:
dhcp: false
enabled: true
address:
- ip: %s
prefix-length: 24
routes:
config:
- destination: 0.0.0.0/0
metric: 150
next-hop-address: 192.0.2.1
next-hop-interface: %s
`, nic, address, nic))
}

var _ = Describe("rollback", func() {
Context("when an error happens during state configuration", func() {
BeforeEach(func() {
Expand All @@ -26,11 +48,41 @@ var _ = Describe("rollback", func() {
for _, node := range nodes {
By(fmt.Sprintf("Check that %s has being rolled back", bridge1))
interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bridge1))
By("Check reconcile re-apply desiredState")
By("Check that desiredState is applied")
interfacesNameForNodeEventually(node).Should(ContainElement(bridge1))
By(fmt.Sprintf("Check that %s is rolled back again", bridge1))
interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bridge1))
}
})
})
Context("when connectivity to default gw is lost after state configuration", func() {
BeforeEach(func() {
By("Configure a invalid default gw")
for _, node := range nodes {
var address string
Eventually(func() string {
address = ipv4Address(node, "eth0")
return address
}, ReadTimeout, ReadInterval).ShouldNot(BeEmpty())
updateDesiredStateAtNode(node, badDefaultGw(address, "eth0"))
}
})
AfterEach(func() {
By("Clean up desired state")
resetDesiredStateForNodes()
})
It("should rollback to a good gw configuration", func() {
for _, node := range nodes {
By("Check that desiredState is applied")
Eventually(func() bool {
return dhcpFlag(node, "eth0")
}, ReadTimeout, ReadInterval).Should(BeFalse())

By("Check that eth0 is rolled back")
Eventually(func() bool {
return dhcpFlag(node, "eth0")
}, ReadTimeout, ReadInterval).Should(BeTrue())
}
})
})
})
21 changes: 19 additions & 2 deletions test/e2e/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func updateDesiredStateAtNode(node string, desiredState nmstatev1alpha1.State) {
}
state.Spec.DesiredState = desiredState
return framework.Global.Client.Update(context.TODO(), &state)
}, ReadTimeout, ReadInterval).ShouldNot(HaveOccurred())
}, ReadTimeout, ReadInterval).ShouldNot(HaveOccurred(), string(desiredState))
}

func updateDesiredState(desiredState nmstatev1alpha1.State) {
Expand Down Expand Up @@ -315,7 +315,6 @@ func deleteConnectionAtNodes(name string) []error {
}

func interfaces(state nmstatev1alpha1.State) []interface{} {
By("unmarshal state yaml into unstructured golang")
var stateUnstructured map[string]interface{}
err := yaml.Unmarshal(state, &stateUnstructured)
Expect(err).ToNot(HaveOccurred(), "Should parse correctly yaml: %s", state)
Expand Down Expand Up @@ -475,3 +474,21 @@ func nextBond() string {
bridgeCounter++
return fmt.Sprintf("bond%d", bondConunter)
}

func currentStateJSON(node string) []byte {
qinqon marked this conversation as resolved.
Show resolved Hide resolved
key := types.NamespacedName{Name: node}
currentState := nodeNetworkState(key).Status.CurrentState
currentStateJson, err := yaml.YAMLToJSON([]byte(currentState))
ExpectWithOffset(1, err).ToNot(HaveOccurred())
return currentStateJson
}

func dhcpFlag(node string, name string) bool {
path := fmt.Sprintf("interfaces.#(name==\"%s\").ipv4.dhcp", name)
return gjson.ParseBytes(currentStateJSON(node)).Get(path).Bool()
}

func ipv4Address(node string, name string) string {
path := fmt.Sprintf("interfaces.#(name==\"%s\").ipv4.address.0.ip", name)
return gjson.ParseBytes(currentStateJSON(node)).Get(path).String()
}