diff --git a/installer/pkg/config-generator/BUILD.bazel b/installer/pkg/config-generator/BUILD.bazel index 23270c31cf8..8045408332a 100644 --- a/installer/pkg/config-generator/BUILD.bazel +++ b/installer/pkg/config-generator/BUILD.bazel @@ -13,6 +13,7 @@ go_library( "//installer/pkg/config:go_default_library", "//installer/pkg/copy:go_default_library", "//pkg/asset/tls:go_default_library", + "//pkg/ipnet:go_default_library", "//pkg/types:go_default_library", "//vendor/github.com/apparentlymart/go-cidr/cidr:go_default_library", "//vendor/github.com/coreos/ignition/config/v2_2:go_default_library", @@ -37,5 +38,6 @@ go_test( deps = [ "//installer/pkg/config:go_default_library", "//pkg/asset/tls:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", ], ) diff --git a/installer/pkg/config-generator/fixtures/kube-system.yaml b/installer/pkg/config-generator/fixtures/kube-system.yaml index ac78d66804f..f440bac5a6b 100644 --- a/installer/pkg/config-generator/fixtures/kube-system.yaml +++ b/installer/pkg/config-generator/fixtures/kube-system.yaml @@ -31,12 +31,8 @@ data: creationTimestamp: null name: test networking: - podCIDR: - IP: 10.2.0.0 - Mask: //8AAA== - serviceCIDR: - IP: 10.3.0.0 - Mask: //8AAA== + podCIDR: 10.2.0.0/16 + serviceCIDR: 10.3.0.0/16 type: canal platform: aws: diff --git a/installer/pkg/config-generator/generator.go b/installer/pkg/config-generator/generator.go index 07915195d38..c0cb50bbc84 100644 --- a/installer/pkg/config-generator/generator.go +++ b/installer/pkg/config-generator/generator.go @@ -19,6 +19,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/openshift/installer/installer/pkg/config" + "github.com/openshift/installer/pkg/ipnet" "github.com/openshift/installer/pkg/types" ) @@ -185,8 +186,8 @@ func (c *ConfigGenerator) installConfig() (*types.InstallConfig, error) { PullSecret: c.PullSecret, Networking: types.Networking{ Type: types.NetworkType(string(c.Networking.Type)), - ServiceCIDR: *serviceCIDR, - PodCIDR: *podCIDR, + ServiceCIDR: ipnet.IPNet{IPNet: *serviceCIDR}, + PodCIDR: ipnet.IPNet{IPNet: *podCIDR}, }, Platform: platform, Machines: []types.MachinePool{{ diff --git a/installer/pkg/config-generator/generator_test.go b/installer/pkg/config-generator/generator_test.go index 7cd10327bc6..bfaae5fca8b 100644 --- a/installer/pkg/config-generator/generator_test.go +++ b/installer/pkg/config-generator/generator_test.go @@ -9,6 +9,7 @@ import ( "github.com/openshift/installer/installer/pkg/config" "github.com/openshift/installer/pkg/asset/tls" + "github.com/stretchr/testify/assert" ) func initConfig(t *testing.T, file string) ConfigGenerator { @@ -46,9 +47,7 @@ func TestUrlFunctions(t *testing.T) { }, } for _, tc := range testCases { - if tc.got != tc.expected { - t.Errorf("Test case %s: expected: %s, got: %s", tc.test, tc.expected, tc.got) - } + assert.Equal(t, tc.expected, tc.got) } } @@ -68,9 +67,7 @@ func TestGetEtcdServersURLs(t *testing.T) { config := initConfig(t, tc.configFile) got := config.getEtcdServersURLs() - if got != tc.expected { - t.Errorf("Test case %s: expected: %s, got: %s", tc.test, tc.expected, got) - } + assert.Equal(t, tc.expected, got) } } @@ -85,9 +82,7 @@ func TestKubeSystem(t *testing.T) { t.Errorf("Test case TestKubeSystem: failed to ReadFile(): %s", err) } - if got != string(expected) { - t.Errorf("Test case TestKubeSystem: expected: %s, got: %s", expected, got) - } + assert.Equal(t, string(expected), got) } func TestCIDRHost(t *testing.T) { @@ -115,9 +110,7 @@ func TestCIDRHost(t *testing.T) { if err != nil { t.Errorf("Test case %s: failed to run cidrhost(): %s", tc.test, err) } - if got != tc.expected { - t.Errorf("Test case %s: expected: %s, got: %s", tc.test, tc.expected, got) - } + assert.Equal(t, tc.expected, got) } } diff --git a/pkg/asset/installconfig/installconfig_test.go b/pkg/asset/installconfig/installconfig_test.go index 12ce4aad5fc..7e71cc9c730 100644 --- a/pkg/asset/installconfig/installconfig_test.go +++ b/pkg/asset/installconfig/installconfig_test.go @@ -163,12 +163,8 @@ metadata: creationTimestamp: null name: test-cluster-name networking: - podCIDR: - IP: "" - Mask: null - serviceCIDR: - IP: "" - Mask: null + podCIDR: null + serviceCIDR: null type: "" platform: %s diff --git a/pkg/asset/tls/helper.go b/pkg/asset/tls/helper.go index 33371d77d71..b4647d16d54 100644 --- a/pkg/asset/tls/helper.go +++ b/pkg/asset/tls/helper.go @@ -53,7 +53,7 @@ func genDNSNamesForAPIServerCertKey(cfg *types.InstallConfig) ([]string, error) } func genIPAddressesForAPIServerCertKey(cfg *types.InstallConfig) ([]net.IP, error) { - apiServerAddress, err := cidrhost(cfg.Networking.ServiceCIDR, 1) + apiServerAddress, err := cidrhost(cfg.Networking.ServiceCIDR.IPNet, 1) if err != nil { return nil, err } @@ -72,7 +72,7 @@ func genDNSNamesForOpenshiftAPIServerCertKey(cfg *types.InstallConfig) ([]string } func genIPAddressesForOpenshiftAPIServerCertKey(cfg *types.InstallConfig) ([]net.IP, error) { - apiServerAddress, err := cidrhost(cfg.Networking.ServiceCIDR, 1) + apiServerAddress, err := cidrhost(cfg.Networking.ServiceCIDR.IPNet, 1) if err != nil { return nil, err } diff --git a/pkg/ipnet/BUILD.bazel b/pkg/ipnet/BUILD.bazel new file mode 100644 index 00000000000..8b0557e8054 --- /dev/null +++ b/pkg/ipnet/BUILD.bazel @@ -0,0 +1,14 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["ipnet.go"], + importpath = "github.com/openshift/installer/pkg/ipnet", + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["ipnet_test.go"], + embed = [":go_default_library"], +) diff --git a/pkg/ipnet/ipnet.go b/pkg/ipnet/ipnet.go new file mode 100644 index 00000000000..48ca01e6706 --- /dev/null +++ b/pkg/ipnet/ipnet.go @@ -0,0 +1,49 @@ +// Package ipnet wraps net.IPNet to get CIDR serialization. +package ipnet + +import ( + "encoding/json" + "net" + "reflect" +) + +var nullString = "null" +var nullBytes = []byte(nullString) +var emptyIPNet = net.IPNet{} + +// IPNet wraps net.IPNet to get CIDR serialization. +type IPNet struct { + net.IPNet +} + +// MarshalJSON interface for an IPNet +func (ipnet IPNet) MarshalJSON() (data []byte, err error) { + if reflect.DeepEqual(ipnet.IPNet, emptyIPNet) { + return nullBytes, nil + } + + return json.Marshal(ipnet.String()) +} + +// UnmarshalJSON interface for an IPNet +func (ipnet *IPNet) UnmarshalJSON(b []byte) (err error) { + if string(b) == nullString { + ipnet.IP = net.IP{} + ipnet.Mask = net.IPMask{} + return nil + } + + var cidr string + err = json.Unmarshal(b, &cidr) + if err != nil { + return err + } + + ip, net, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + ipnet.IP = ip + ipnet.Mask = net.Mask + return nil +} diff --git a/pkg/ipnet/ipnet_test.go b/pkg/ipnet/ipnet_test.go new file mode 100644 index 00000000000..94b927d6f47 --- /dev/null +++ b/pkg/ipnet/ipnet_test.go @@ -0,0 +1,62 @@ +package ipnet + +import ( + "encoding/json" + "net" + "testing" +) + +func assertJSON(t *testing.T, data interface{}, expected string) { + actualBytes, err := json.Marshal(data) + if err != nil { + t.Fatal(err) + } + actual := string(actualBytes) + + if actual != expected { + t.Fatalf("%s != %s", actual, expected) + } +} + +func TestMarshal(t *testing.T) { + stdlibIPNet := &net.IPNet{ + IP: net.IP{192, 168, 0, 10}, + Mask: net.IPv4Mask(255, 255, 255, 0), + } + assertJSON(t, stdlibIPNet, "{\"IP\":\"192.168.0.10\",\"Mask\":\"////AA==\"}") + wrappedIPNet := &IPNet{IPNet: *stdlibIPNet} + assertJSON(t, wrappedIPNet, "\"192.168.0.10/24\"") + assertJSON(t, &IPNet{}, "null") + assertJSON(t, nil, "null") +} + +func TestUnmarshal(t *testing.T) { + for _, ipNetIn := range []*IPNet{ + nil, + {IPNet: net.IPNet{ + IP: net.IP{192, 168, 0, 10}, + Mask: net.IPv4Mask(255, 255, 255, 0), + }}, + } { + data, err := json.Marshal(ipNetIn) + if err != nil { + t.Fatal(err) + } + + t.Run(string(data), func(t *testing.T) { + var ipNetOut *IPNet + err := json.Unmarshal(data, &ipNetOut) + if err != nil { + t.Fatal(err) + } + + if ipNetIn == nil { + if ipNetOut != nil { + t.Fatalf("%v != %v", ipNetOut, ipNetIn) + } + } else if ipNetOut.String() != ipNetIn.String() { + t.Fatalf("%v != %v", ipNetOut, ipNetIn) + } + }) + } +} diff --git a/pkg/types/BUILD.bazel b/pkg/types/BUILD.bazel index 4dc44ca922e..05748e49200 100644 --- a/pkg/types/BUILD.bazel +++ b/pkg/types/BUILD.bazel @@ -9,5 +9,8 @@ go_library( ], importpath = "github.com/openshift/installer/pkg/types", visibility = ["//visibility:public"], - deps = ["//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"], + deps = [ + "//pkg/ipnet:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], ) diff --git a/pkg/types/installconfig.go b/pkg/types/installconfig.go index 7117e518df0..9322a8fb050 100644 --- a/pkg/types/installconfig.go +++ b/pkg/types/installconfig.go @@ -3,6 +3,7 @@ package types import ( "net" + "github.com/openshift/installer/pkg/ipnet" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -58,8 +59,8 @@ type Platform struct { // Networking defines the pod network provider in the cluster. type Networking struct { Type NetworkType `json:"type"` - ServiceCIDR net.IPNet `json:"serviceCIDR"` - PodCIDR net.IPNet `json:"podCIDR"` + ServiceCIDR ipnet.IPNet `json:"serviceCIDR"` + PodCIDR ipnet.IPNet `json:"podCIDR"` } // NetworkType defines the pod network provider in the cluster.