diff --git a/pkg/util/cmdline.go b/pkg/util/cmdline.go index dae26b1e1..460504256 100644 --- a/pkg/util/cmdline.go +++ b/pkg/util/cmdline.go @@ -83,19 +83,67 @@ func toNetworkInterfaces(data map[string]interface{}) error { outDetails := make([]interface{}, 0, len(ifDetails)) for _, v := range ifDetails { - tmpStrings := strings.SplitN(v, ":", 2) - n := make(map[string]interface{}) - err := json.Unmarshal([]byte(fmt.Sprintf("{\"%s\":\"%s\"}", tmpStrings[0], strings.ReplaceAll(tmpStrings[1], " ", ""))), &n) + n, err := parseIfDetails(v) if err != nil { return err } - outDetails = append(outDetails, n) + outDetails = append(outDetails, *n) } values.PutValue(data, outDetails, "install", "management_interface", "interfaces") return nil } +// parseIfDetails accepts strings in the form of: +// - "hwAddr: ab:cd:ef:gh:ij:kl" +// - "name: ens3" +// - "ab:cd:ef:gh:ij:kl" +// - "ens3" +// and returns a map of either +// "hwAddr: ab:cd:ef:gh:ij:kl" +// or +// "name: ens3" +func parseIfDetails(details string) (*map[string]interface{}, error) { + var ( + parts []string + data string + ) + + for _, s := range strings.Split(details, ":") { + parts = append(parts, strings.TrimSpace(s)) + } + + switch len(parts) { + case 7: + // hwAddr: ab:cd:ef:gh:ij:kl + if parts[0] != "hwAddr" { + return nil, fmt.Errorf("could not parse interface details %v", details) + } + data = fmt.Sprintf("{\"hwAddr\":\"%v\"}", strings.Join(parts[1:], ":")) + case 6: + // ab:cd:ef:gh:ij:kl + data = fmt.Sprintf("{\"hwAddr\":\"%v\"}", strings.Join(parts, ":")) + case 2: + // name: ens3 + if parts[0] != "name" { + return nil, fmt.Errorf("could not parse interface details %v", details) + } + data = fmt.Sprintf("{\"name\":\"%v\"}", parts[1]) + case 1: + // ens3 + data = fmt.Sprintf("{\"name\":\"%v\"}", parts[0]) + default: + return nil, fmt.Errorf("could not parse interface details %v", details) + } + + n := make(map[string]interface{}) + err := json.Unmarshal([]byte(data), &n) + if err != nil { + return nil, err + } + return &n, nil +} + func toSchemeVersion(data map[string]interface{}) error { schemeVersion, ok := values.GetValue(data, "scheme_version") if !ok { diff --git a/pkg/util/cmdline_test.go b/pkg/util/cmdline_test.go index 5d393edf6..d06220cad 100644 --- a/pkg/util/cmdline_test.go +++ b/pkg/util/cmdline_test.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "strings" "testing" "github.com/rancher/mapper/values" @@ -37,33 +38,59 @@ func Test_parseCmdLineWithoutPrefix(t *testing.T) { } func Test_parseCmdLineWithNetworkInterface(t *testing.T) { - - cmdline := `harvester.os.sshAuthorizedKeys=a harvester.install.management_interface.method=dhcp harvester.install.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 harvester.os.sshAuthorizedKeys=b harvester.install.mode=create harvester.install.management_interface.interfaces="hwAddr: ab:cd:ef:gh" harvester.install.management_interface.interfaces="hwAddr: de:fg:hi:jk"` - - m, err := parseCmdLine(cmdline, "harvester") - if err != nil { - t.Fatal(err) + type testcase struct { + cmdline string + expectation []interface{} + expectedError error } - want := []interface{}{ - map[string]interface{}{ - "hwAddr": "ab:cd:ef:gh", + testcases := []testcase{ + { + cmdline: `harvester.os.sshAuthorizedKeys=a harvester.install.management_interface.method=dhcp harvester.install.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 harvester.os.sshAuthorizedKeys=b harvester.install.mode=create harvester.install.management_interface.interfaces="hwAddr: ab:cd:ef:gh:ij:kl" harvester.install.management_interface.interfaces="hwAddr: de:fg:hi:jk:lm:no" harvester.install.management_interface.interfaces="ens3" harvester.install.management_interface.interfaces="name:ens5"`, + expectation: []interface{}{ + map[string]interface{}{"hwAddr": "ab:cd:ef:gh:ij:kl"}, + map[string]interface{}{"hwAddr": "de:fg:hi:jk:lm:no"}, + map[string]interface{}{"name": "ens3"}, + map[string]interface{}{"name": "ens5"}, + }, + expectedError: nil, + }, + { + cmdline: `harvester.install.management_interface.interfaces="ens3"`, + expectation: []interface{}{ + map[string]interface{}{"name": "ens3"}, + }, + expectedError: nil, }, - map[string]interface{}{ - "hwAddr": "de:fg:hi:jk", + { + cmdline: `harvester.os.sshAuthorizedKeys=a harvester.install.management_interface.method=dhcp harvester.install.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 harvester.os.sshAuthorizedKeys=b harvester.install.mode=create harvester.install.management_interface.interfaces="foo:bar:foobar"`, + expectation: []interface{}{}, + expectedError: fmt.Errorf("could not parse interface details"), }, } - have, ok := values.GetValue(m, "install", "management_interface", "interfaces") - if !ok { - t.Fatal(fmt.Errorf("no network interfaces found")) - } + for _, tc := range testcases { + m, err := parseCmdLine(tc.cmdline, "harvester") + if err != nil { + if tc.expectedError != nil { + assert.True(t, strings.Contains(err.Error(), tc.expectedError.Error()), "unexpected error") + } else { + t.Fatal(err) + } + } else { + want := tc.expectation + have, ok := values.GetValue(m, "install", "management_interface", "interfaces") + if !ok { + t.Fatal(fmt.Errorf("no network interfaces found")) + } - assert.Equal(t, want, have) + assert.Equal(t, want, have) + } + } } func Test_parseCmdLineWithSchemeVersion(t *testing.T) { - cmdline := `harvester.os.sshAuthorizedKeys=a harvester.install.management_interface.method=dhcp harvester.install.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 harvester.os.sshAuthorizedKeys=b harvester.install.mode=create harvester.install.management_interface.interfaces="hwAddr: ab:cd:ef:gh" harvester.install.management_interface.interfaces="hwAddr: de:fg:hi:jk" harvester.scheme_version=1` + cmdline := `harvester.os.sshAuthorizedKeys=a harvester.install.management_interface.method=dhcp harvester.install.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 harvester.os.sshAuthorizedKeys=b harvester.install.mode=create harvester.install.management_interface.interfaces="hwAddr: ab:cd:ef:gh:ij:kl" harvester.install.management_interface.interfaces="hwAddr: de:fg:hi:jk:lm:no" harvester.scheme_version=1` m, err := parseCmdLine(cmdline, "harvester") assert.NoError(t, err, "expected no error while parsing arguments")