Skip to content

Commit

Permalink
state, filter: Fix interpretation of special numeric iface names
Browse files Browse the repository at this point in the history
This change solves the problem of incorrectly representing
valid numeric values like `0xfe` and `1.0` as strings (they have been
represented back as 254 and 1).

The problem originates from the YAML-to-JSON conversion which does not obey
to the defined member type.

Fixed by using the go-yaml package (which does not perform such a
conversion from YAML to JSON).
The go-yaml is used just to unmarshal the name from the original raw
byte stream and update the state structure with the proper name string.

Signed-off-by: Edward Haas <[email protected]>
  • Loading branch information
EdDev committed Mar 3, 2021
1 parent 1212087 commit be618a0
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
20 changes: 20 additions & 0 deletions pkg/state/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/nmstate/kubernetes-nmstate/api/shared"
"github.com/nmstate/kubernetes-nmstate/pkg/environment"

goyaml "gopkg.in/yaml.v2"
yaml "sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -90,6 +91,10 @@ func filterOut(currentState shared.State, interfacesFilterGlob glob.Glob) (share
return currentState, err
}

if err := normalizeInterfacesNames(currentState.Raw, &state); err != nil {
return currentState, err
}

state.Interfaces = filterOutInterfaces(state.Interfaces, interfacesFilterGlob)
if state.Routes != nil {
state.Routes.Running = filterOutRoutes(state.Routes.Running, interfacesFilterGlob)
Expand All @@ -102,3 +107,18 @@ func filterOut(currentState shared.State, interfacesFilterGlob glob.Glob) (share

return shared.NewState(string(filteredState)), nil
}

// normalizeInterfacesNames fixes the unmarshal of numeric values in the interfaces names
// Numeric values, including the ones with a base prefix (e.g. 0x123) should be stringify.
func normalizeInterfacesNames(rawState []byte, state *rootState) error {
var stateForNormalization rootState
if err := goyaml.Unmarshal(rawState, &stateForNormalization); err != nil {
return err
}
for i, iface := range stateForNormalization.Interfaces {
if isNumeric(iface.Name) {
state.Interfaces[i].Name = iface.Name
}
}
return nil
}
6 changes: 3 additions & 3 deletions pkg/state/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,13 @@ interfaces:
filteredState = nmstate.NewState(`
interfaces:
- name: eth0
- name: "0"
- name: "254"
- name: "0.0"
- name: "0xfe"
`)
interfacesFilterGlob = glob.MustCompile("1*")
})

It("should filter out interfaces correctly but they are not represented correctly", func() {
It("should filter out interfaces correctly", func() {
returnedState, err := filterOut(state, interfacesFilterGlob)
Expect(err).NotTo(HaveOccurred())
Expect(returnedState).To(MatchYAML(filteredState))
Expand Down
26 changes: 19 additions & 7 deletions pkg/state/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ package state
import (
"encoding/json"
"fmt"
"strconv"

"sigs.k8s.io/yaml"
)

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

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

type interfaceState struct {
interfaceFields
Data map[string]interface{}
interfaceFields `yaml:",inline"`
Data map[string]interface{}
}

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

func (i interfaceState) MarshalJSON() (output []byte, err error) {
Expand All @@ -45,3 +46,14 @@ func (i *interfaceState) UnmarshalJSON(b []byte) error {
i.Name = ifaceFields.Name
return nil
}

func isNumeric(s string) bool {
if _, err := strconv.ParseFloat(s, 64); err == nil {
return true
}
// Check for numerics with special prefixes: "0b", "0o", "0x",
if _, err := strconv.ParseInt(s, 0, 64); err == nil {
return true
}
return false
}

0 comments on commit be618a0

Please sign in to comment.