From e3265bf424e3bf26f2fc4cc25978e880e64c405c Mon Sep 17 00:00:00 2001 From: Quique Llorente Date: Mon, 1 Feb 2021 15:08:28 +0100 Subject: [PATCH] Skip linux-bridge filtering if no "bridge" section We have found that at some envs the "bridge" section from linux-bridge is not present in case the bridge is down, this change ignore the filtering in this is the case to preveng a segmentation fault. Signed-off-by: Quique Llorente --- pkg/nmstatectl/remote.go | 68 ++++++++++++++++++++++++++++++++++++++++ pkg/state/filter.go | 19 +++++++++-- pkg/state/filter_test.go | 62 ++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 pkg/nmstatectl/remote.go diff --git a/pkg/nmstatectl/remote.go b/pkg/nmstatectl/remote.go new file mode 100644 index 0000000000..84631d5033 --- /dev/null +++ b/pkg/nmstatectl/remote.go @@ -0,0 +1,68 @@ +package nmstatectl + +import ( + "bytes" + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" +) + +func ShowAtNode(config *rest.Config, nodeName string) (string, error) { + cmd := []string{ + "sh", + "-c", + "nmstatectl", + "show", + } + + client, err := kubernetes.NewForConfig(config) + if err != nil { + return "", err + } + + //TODO: Don't hardcode namespace + //TODO: Use controller-runtime client ? + handlerPodList, err := client.CoreV1().Pods("nmstate").List(context.Background(), metav1.ListOptions{ + LabelSelector: "component=kubernetes-nmstate-handler", + FieldSelector: fmt.Sprintf("spec.nodeName=%s", nodeName), + }) + if err != nil { + return "", err + } + if len(handlerPodList.Items) == 0 { + return "", fmt.Errorf("No handler running at %s", nodeName) + } + //TODO: Don't hardcode namespace + req := client.CoreV1().RESTClient().Post().Resource("pods").Name(handlerPodList.Items[0].Name). + Namespace("nmstate").SubResource("exec") + option := &v1.PodExecOptions{ + Command: cmd, + Stdin: false, + Stdout: true, + Stderr: true, + TTY: false, + } + req.VersionedParams( + option, + scheme.ParameterCodec, + ) + exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) + if err != nil { + return "", err + } + var stdout, stderr bytes.Buffer + err = exec.Stream(remotecommand.StreamOptions{ + Stdout: &stdout, + Stderr: &stderr, + }) + if err != nil { + return "", err + } + return stdout.String(), nil +} diff --git a/pkg/state/filter.go b/pkg/state/filter.go index cb7d4c55f0..a98ad6a851 100644 --- a/pkg/state/filter.go +++ b/pkg/state/filter.go @@ -58,9 +58,24 @@ func filterOutDynamicAttributes(iface map[string]interface{}) { return } - bridge := iface["bridge"].(map[string]interface{}) + bridgeIface, ok := iface["bridge"] + if !ok { + return + } + bridge, ok := bridgeIface.(map[string]interface{}) + if !ok { + return + } + + optionsIface, ok := bridge["options"] + if !ok { + return + } + options, ok := optionsIface.(map[string]interface{}) + if !ok { + return + } - options := bridge["options"].(map[string]interface{}) delete(options, "gc-timer") delete(options, "hello-timer") } diff --git a/pkg/state/filter_test.go b/pkg/state/filter_test.go index 3f49f13a09..1549daab00 100644 --- a/pkg/state/filter_test.go +++ b/pkg/state/filter_test.go @@ -307,4 +307,66 @@ routes: Expect(returnedState).To(MatchYAML(filteredState)) }) }) + Context("when there is a linux bridge without 'bridge' options because is down", func() { + BeforeEach(func() { + state = nmstate.NewState(` +interfaces: +- name: eth1 + state: up + type: ethernet +- name: br1 + type: linux-bridge + state: down + ipv4: + enabled: false + ipv6: + enabled: false + lldp: + enabled: false + mac-address: A2:EE:84:7B:42:4C + mtu: 1500 +routes: + config: [] + running: + - destination: 0.0.0.0/0 + metric: 102 + next-hop-address: 192.168.66.2 + next-hop-interface: eth1 + table-id: 254 +`) + + filteredState = nmstate.NewState(` +interfaces: +- name: eth1 + state: up + type: ethernet +- name: br1 + type: linux-bridge + state: down + ipv4: + enabled: false + ipv6: + enabled: false + lldp: + enabled: false + mac-address: A2:EE:84:7B:42:4C + mtu: 1500 +routes: + config: [] + running: + - destination: 0.0.0.0/0 + metric: 102 + next-hop-address: 192.168.66.2 + next-hop-interface: eth1 + table-id: 254 +`) + interfacesFilterGlob = glob.MustCompile("") + }) + It("should keep the bridge as it is", func() { + returnedState, err := filterOut(state, interfacesFilterGlob) + Expect(err).ToNot(HaveOccurred()) + Expect(returnedState).To(MatchYAML(filteredState)) + }) + }) + })