diff --git a/common/libnetwork/internal/util/parse.go b/common/libnetwork/internal/util/parse.go index 2bda3b1228..74064eca79 100644 --- a/common/libnetwork/internal/util/parse.go +++ b/common/libnetwork/internal/util/parse.go @@ -34,3 +34,21 @@ func ParseVlan(vlan string) (int, error) { } return v, nil } + +// ParseIsolate parses the isolate option +func ParseIsolate(isolate string) (string, error) { + switch isolate { + case "": + return "false", nil + case "strict": + return isolate, nil + default: + // isolate option accepts "strict" and Rust boolean values "true" or "false" + optIsolateBool, err := strconv.ParseBool(isolate) + if err != nil { + return "", fmt.Errorf("failed to parse isolate option: %w", err) + } + // Rust boolean only support "true" or "false" while go can parse 1 and 0 as well so we need to change it + return strconv.FormatBool(optIsolateBool), nil + } +} diff --git a/common/libnetwork/internal/util/parse_test.go b/common/libnetwork/internal/util/parse_test.go new file mode 100644 index 0000000000..595b4bdd63 --- /dev/null +++ b/common/libnetwork/internal/util/parse_test.go @@ -0,0 +1,217 @@ +package util + +import ( + "reflect" + "testing" +) + +func TestParseMTU(t *testing.T) { + type args struct { + mtuOption string + } + tests := []struct { + name string + args args + want int + wantErr bool + }{ + { + name: "mtu default", + args: args{ + mtuOption: "", + }, + want: 0, + }, + { + name: "mtu 1500", + args: args{ + mtuOption: "1500", + }, + want: 1500, + }, + { + name: "mtu string", + args: args{ + mtuOption: "thousand-fifty-hundred", + }, + wantErr: true, + }, + { + name: "mtu less than 0", + args: args{ + mtuOption: "-1", + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got, err := ParseMTU(tt.args.mtuOption) + if (err != nil) != tt.wantErr { + t.Errorf("ParseMTU() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParseMTU() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestParseVlan(t *testing.T) { + type args struct { + vlanOption string + } + tests := []struct { + name string + args args + want int + wantErr bool + }{ + { + name: "vlan default", + args: args{ + vlanOption: "", + }, + want: 0, + }, + { + name: "vlan 0", + args: args{ + vlanOption: "0", + }, + want: 0, + }, + { + name: "vlan less than 0", + args: args{ + vlanOption: "-1", + }, + wantErr: true, + }, + { + name: "vlan 4094", + args: args{ + vlanOption: "4094", + }, + want: 4094, + }, + { + name: "vlan greater than 4094", + args: args{ + vlanOption: "4095", + }, + wantErr: true, + }, + { + name: "vlan string", + args: args{ + vlanOption: "thousand-fifty-hundred", + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got, err := ParseVlan(tt.args.vlanOption) + if (err != nil) != tt.wantErr { + t.Errorf("ParseVlan() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParseVlan() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestParseIsolate(t *testing.T) { + type args struct { + isolateOption string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "isolate default", + args: args{ + isolateOption: "", + }, + want: "false", + }, + { + name: "isolate true", + args: args{ + isolateOption: "true", + }, + want: "true", + }, + { + name: "isolate 1", + args: args{ + isolateOption: "1", + }, + want: "true", + }, + { + name: "isolate greater than 1", + args: args{ + isolateOption: "2", + }, + wantErr: true, + }, + { + name: "isolate false", + args: args{ + isolateOption: "false", + }, + want: "false", + }, + { + name: "isolate 0", + args: args{ + isolateOption: "0", + }, + want: "false", + }, + { + name: "isolate less than 0", + args: args{ + isolateOption: "-1", + }, + wantErr: true, + }, + { + name: "isolate strict", + args: args{ + isolateOption: "strict", + }, + want: "strict", + }, + { + name: "isolate unknown value", + args: args{ + isolateOption: "foobar", + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + got, err := ParseIsolate(tt.args.isolateOption) + if (err != nil) != tt.wantErr { + t.Errorf("ParseIsolate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParseIsolate() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/common/libnetwork/netavark/config.go b/common/libnetwork/netavark/config.go index aaf7843bee..de862d503c 100644 --- a/common/libnetwork/netavark/config.go +++ b/common/libnetwork/netavark/config.go @@ -187,12 +187,11 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo } case types.IsolateOption: - val, err := strconv.ParseBool(value) + val, err := internalutil.ParseIsolate(value) if err != nil { return nil, err } - // rust only support "true" or "false" while go can parse 1 and 0 as well so we need to change it - newNetwork.Options[types.IsolateOption] = strconv.FormatBool(val) + newNetwork.Options[types.IsolateOption] = val case types.MetricOption: _, err := strconv.ParseUint(value, 10, 32) if err != nil { diff --git a/common/libnetwork/netavark/config_test.go b/common/libnetwork/netavark/config_test.go index 21c961fa36..3546c9684d 100644 --- a/common/libnetwork/netavark/config_test.go +++ b/common/libnetwork/netavark/config_test.go @@ -1389,7 +1389,7 @@ var _ = Describe("Config", func() { Expect(err.Error()).To(Equal("unknown ipvlan mode \"abc\"")) }) - It("create network with isolate option", func() { + It("create network with isolate option 'true'", func() { for _, val := range []string{"true", "1"} { network := types.Network{ Options: map[string]string{ @@ -1407,6 +1407,22 @@ var _ = Describe("Config", func() { } }) + It("create network with isolate option 'strict'", func() { + network := types.Network{ + Options: map[string]string{ + types.IsolateOption: "strict", + }, + } + network1, err := libpodNet.NetworkCreate(network, nil) + Expect(err).To(BeNil()) + Expect(network1.Driver).To(Equal("bridge")) + Expect(network1.Options).ToNot(BeNil()) + path := filepath.Join(networkConfDir, network1.Name+".json") + Expect(path).To(BeARegularFile()) + grepInFile(path, `"isolate": "strict"`) + Expect(network1.Options).To(HaveKeyWithValue("isolate", "strict")) + }) + It("create network with invalid isolate option", func() { network := types.Network{ Options: map[string]string{