Skip to content

Commit

Permalink
state, filter: Do not panic on interpretation of ifaces names
Browse files Browse the repository at this point in the history
In scenarios where an interface name is composed of numbers in
scientific notation without a dot, the application panics with a failure
to extract a string type from a Go interface (which is actually a float64).

In order to fix the problem, the parsing of the interface name is performed
using a dedicated interface-state structure.

Note: this change does not solve the problem of incorrectly representing
valid scientific numeric values like `10e+02` as strings (they are now
represented back as full integers: "1000").
This is due to the YAML-to-JSON conversion which does not obey to
the defined member type.

ref: yaml/pyyaml#173

Signed-off-by: Edward Haas <[email protected]>
  • Loading branch information
EdDev committed Mar 3, 2021
1 parent 8165846 commit b1f539a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 10 deletions.
14 changes: 6 additions & 8 deletions pkg/state/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@ func filterOutDynamicAttributes(iface map[string]interface{}) {
delete(options, "hello-timer")
}

func filterOutInterfaces(ifaces []interface{}, interfacesFilterGlob glob.Glob) []interface{} {
filteredInterfaces := []interface{}{}
for _, iface := range ifaces {
name := iface.(map[string]interface{})["name"]
if !interfacesFilterGlob.Match(name.(string)) {
filterOutDynamicAttributes(iface.(map[string]interface{}))
func filterOutInterfaces(ifacesState []interfaceState, interfacesFilterGlob glob.Glob) []interfaceState {
filteredInterfaces := []interfaceState{}
for _, iface := range ifacesState {
if !interfacesFilterGlob.Match(iface.Name) {
filterOutDynamicAttributes(iface.Data)
filteredInterfaces = append(filteredInterfaces, iface)
}
}
Expand All @@ -87,8 +86,7 @@ func filterOutInterfaces(ifaces []interface{}, interfacesFilterGlob glob.Glob) [

func filterOut(currentState shared.State, interfacesFilterGlob glob.Glob) (shared.State, error) {
var state rootState
err := yaml.Unmarshal(currentState.Raw, &state)
if err != nil {
if err := yaml.Unmarshal(currentState.Raw, &state); err != nil {
return currentState, err
}

Expand Down
25 changes: 25 additions & 0 deletions pkg/state/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,29 @@ interfaces:
Expect(returnedState).To(MatchYAML(filteredState))
})
})

// See https://github.com/yaml/pyyaml/issues/173 for why this scenario is checked.
Context("when the interfaces names have numbers in scientific notation without dot", func() {
BeforeEach(func() {
state = nmstate.NewState(`
interfaces:
- name: eth0
- name: 10e+02
- name: 60e+02
`)
filteredState = nmstate.NewState(`
interfaces:
- name: eth0
- name: "1000"
- name: "6000"
`)
interfacesFilterGlob = glob.MustCompile("10e*")
})

It("does not filter out interfaces correctly and does not represent them correctly", func() {
returnedState, err := filterOut(state, interfacesFilterGlob)
Expect(err).NotTo(HaveOccurred())
Expect(returnedState).To(MatchYAML(filteredState))
})
})
})
40 changes: 38 additions & 2 deletions pkg/state/type.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
package state

import (
"encoding/json"
"fmt"

"sigs.k8s.io/yaml"
)

type rootState struct {
Interfaces []interface{} `json:"interfaces"`
Routes *routesState `json:"routes,omitempty"`
Interfaces []interfaceState `json:"interfaces"`
Routes *routesState `json:"routes,omitempty"`
}

type routesState struct {
Config []interface{} `json:"config"`
Running []interface{} `json:"running"`
}

type interfaceState struct {
interfaceFields
Data map[string]interface{}
}

// interfaceFields allows unmarshaling directly into the defined fields
type interfaceFields struct {
Name string `json:"name"`
}

func (i interfaceState) MarshalJSON() (output []byte, err error) {
i.Data["name"] = i.Name
return json.Marshal(i.Data)
}

func (i *interfaceState) UnmarshalJSON(b []byte) error {
if err := yaml.Unmarshal(b, &i.Data); err != nil {
return fmt.Errorf("failed Unmarshaling b: %w", err)
}

var ifaceFields interfaceFields
if err := yaml.Unmarshal(b, &ifaceFields); err != nil {
return fmt.Errorf("failed Unmarshaling raw: %w", err)
}
i.Data["name"] = ifaceFields.Name
i.Name = ifaceFields.Name
return nil
}

0 comments on commit b1f539a

Please sign in to comment.