From db60c0554ee19197fa7892b9be5c21b3b8765dbc Mon Sep 17 00:00:00 2001 From: Sam Batschelet Date: Fri, 21 Feb 2020 13:20:51 -0500 Subject: [PATCH] pkg/cmd/render: check if bootstrap IP is part of clusterNetwork cidr Signed-off-by: Sam Batschelet --- pkg/cmd/render/render.go | 72 ++++++++++++++++++++++++----------- pkg/cmd/render/render_test.go | 11 +++++- pkg/dnshelpers/util.go | 11 ++++++ pkg/etcdcli/etcdcli.go | 13 ++++--- 4 files changed, 77 insertions(+), 30 deletions(-) diff --git a/pkg/cmd/render/render.go b/pkg/cmd/render/render.go index d148d2b0d6..6a544738c1 100644 --- a/pkg/cmd/render/render.go +++ b/pkg/cmd/render/render.go @@ -10,10 +10,11 @@ import ( "path/filepath" "strings" + "github.com/openshift/cluster-etcd-operator/pkg/cmd/render/options" + "github.com/openshift/cluster-etcd-operator/pkg/dnshelpers" "github.com/openshift/cluster-etcd-operator/pkg/operator/etcd_assets" "github.com/ghodss/yaml" - "github.com/openshift/cluster-etcd-operator/pkg/cmd/render/options" "github.com/openshift/library-go/pkg/assets" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -207,8 +208,9 @@ func newTemplateData(opts *renderOpts) (*TemplateData, error) { return nil, err } } - - templateData.setEtcdAddress() + if err := templateData.setEtcdAddress(); err != nil { + return nil, err + } return &templateData, nil } @@ -237,47 +239,70 @@ func (r *renderOpts) Run() error { return WriteFiles(&r.generic, &templateData.FileConfig, templateData) } -// setBootstrapIP gets a list of IPs from local interfaces and returns the first IPv4 or IPv6 address. func (t *TemplateData) setBootstrapIP() error { - var bootstrapIP string - ips, err := ipAddrs() + bootstrapIP, err := t.getBootstrapIP() if err != nil { return err } + t.BootstrapIP = bootstrapIP + return nil +} + +// getBootstrapIP gets a list of IPs from local interfaces and returns the first address that is contained +// in the ClusterCIDR[0] network. No extra checks are preformed if --bootstrap-ip is passed by flag. +func (t *TemplateData) getBootstrapIP() (string, error) { + if t.BootstrapIP != "" { + return t.BootstrapIP, nil + } + ips, err := ipAddrs() + if err != nil { + return "", err + } for _, addr := range ips { - ip := net.ParseIP(addr) - // IPv6 - if t.SingleStackIPv6 && ip.To4() == nil { - bootstrapIP = addr - break + isBootstrapIp, err := dnshelpers.IsNetworkContainIp(t.ClusterCIDR[0], addr) + if err != nil { + return "", err } - // IPv4 - if !t.SingleStackIPv6 && ip.To4() != nil { - bootstrapIP = addr - break + if isBootstrapIp { + return addr, nil } } - if bootstrapIP == "" { - return fmt.Errorf("no IP address found for bootstrap node") + return "", fmt.Errorf("no IP address on bootstrap node matches clusterNetwork cidr %s", t.ClusterCIDR[0]) +} + +func (t *TemplateData) getEscapedBootstrapIP() (string, error) { + bootstrapIP, err := t.getBootstrapIP() + if err != nil { + return "", err } - t.BootstrapIP = bootstrapIP - return nil + isIPV4, err := dnshelpers.IsIPv4(bootstrapIP) + if err != nil { + return "", err + } + if !isIPV4 { + return "[" + bootstrapIP + "]", nil + } + + return bootstrapIP, nil } -func (t *TemplateData) setEtcdAddress() { +func (t *TemplateData) setEtcdAddress() error { + escapedBootsrapIP, err := t.getEscapedBootstrapIP() + if err != nil { + return err + } + // IPv4 allAddresses := "0.0.0.0" localhost := "127.0.0.1" - bootstrapIP := t.BootstrapIP // IPv6 if t.SingleStackIPv6 { allAddresses = "::" localhost = "[::1]" - bootstrapIP = "[" + t.BootstrapIP + "]" } etcdAddress := options.EtcdAddress{ @@ -286,10 +311,11 @@ func (t *TemplateData) setEtcdAddress() { LocalHost: localhost, ListenMetricServer: net.JoinHostPort(allAddresses, "9978"), ListenMetricProxy: net.JoinHostPort(allAddresses, "9979"), - EscapedBootstrapIP: bootstrapIP, + EscapedBootstrapIP: escapedBootsrapIP, } t.ManifestConfig.EtcdAddress = etcdAddress + return nil } func (t *TemplateData) getClusterConfigFromFile(clusterConfigFile string) (*unstructured.Unstructured, error) { diff --git a/pkg/cmd/render/render_test.go b/pkg/cmd/render/render_test.go index b41afe64ef..1007fca0d6 100644 --- a/pkg/cmd/render/render_test.go +++ b/pkg/cmd/render/render_test.go @@ -117,12 +117,14 @@ func TestRenderIpv4(t *testing.T) { ClusterCIDR: []string{"10.128.0.0/14"}, ServiceCIDR: []string{"172.30.0.0/16"}, SingleStackIPv6: false, + BootstrapIP: "10.128.0.12", } config := &testConfig{ t: t, clusterNetworkConfig: networkConfigIpv4, want: want, + bootstrapIP: "10.128.0.12", } testRender(config) @@ -159,6 +161,7 @@ func testRender(tc *testConfig) { manifest: *options.NewManifestOptions("etcd"), errOut: errOut, clusterConfigFile: clusterConfigFile.Name(), + bootstrapIP: tc.bootstrapIP, } if err := render.Run(); err != nil { @@ -176,12 +179,14 @@ func TestTemplateDataIpv4(t *testing.T) { ClusterCIDR: []string{"10.128.0.0/14"}, ServiceCIDR: []string{"172.30.0.0/16"}, SingleStackIPv6: false, + BootstrapIP: "10.128.0.12", } config := &testConfig{ t: t, clusterNetworkConfig: networkConfigIpv4, want: want, + bootstrapIP: "10.128.0.12", } testTemplateData(config) } @@ -196,12 +201,14 @@ func TestTemplateDataMixed(t *testing.T) { ClusterCIDR: []string{"10.128.10.0/14"}, ServiceCIDR: []string{"2001:db8::/32", "172.30.0.0/16"}, SingleStackIPv6: false, + BootstrapIP: "10.128.0.12", } config := &testConfig{ t: t, clusterNetworkConfig: networkConfigMixedSwap, want: want, + bootstrapIP: "10.128.0.12", } testTemplateData(config) } @@ -216,14 +223,14 @@ func TestTemplateDataSingleStack(t *testing.T) { ClusterCIDR: []string{"10.128.0.0/14"}, ServiceCIDR: []string{"2001:db8::/32"}, SingleStackIPv6: true, - BootstrapIP: "2001:0DB8:C21A", + BootstrapIP: "fe80::d66c:724c:13d4:829c", } config := &testConfig{ t: t, clusterNetworkConfig: networkConfigIPv6SingleStack, want: want, - bootstrapIP: "2001:0DB8:C21A", + bootstrapIP: "fe80::d66c:724c:13d4:829c", } testTemplateData(config) } diff --git a/pkg/dnshelpers/util.go b/pkg/dnshelpers/util.go index dbfac9e711..4703437b03 100644 --- a/pkg/dnshelpers/util.go +++ b/pkg/dnshelpers/util.go @@ -183,3 +183,14 @@ func reverseLookupForOneIP(discoveryDomain, ipAddress string) (string, error) { } return selfTarget, nil } + +func IsNetworkContainIp(network, ipAddress string) (bool, error) { + _, parsedNet, err := net.ParseCIDR(network) + if err != nil { + return false, err + } + if parsedNet.Contains(net.ParseIP(ipAddress)) { + return true, nil + } + return false, nil +} diff --git a/pkg/etcdcli/etcdcli.go b/pkg/etcdcli/etcdcli.go index e432b04a2a..25e7c1b98e 100644 --- a/pkg/etcdcli/etcdcli.go +++ b/pkg/etcdcli/etcdcli.go @@ -3,7 +3,6 @@ package etcdcli import ( "context" "fmt" - "net" "time" configv1informers "github.com/openshift/client-go/config/informers/externalversions/config/v1" @@ -81,11 +80,15 @@ func (g *etcdClientGetter) getEtcdClient() (*clientv3.Client, error) { klog.V(2).Infof("service/host-etcd-2 is missing annotation %s", BootstrapIPAnnotationKey) } if bootstrapIP != "" { - // escape if IPv6 - if net.ParseIP(bootstrapIP).To4() == nil { - bootstrapIP = "[" + bootstrapIP + "]" + isIPV4, err := dnshelpers.IsIPv4(bootstrapIP) + if err != nil { + return nil, err + } + if isIPV4 { + etcdEndpoints = append(etcdEndpoints, "https://"+bootstrapIP+":2379") + } else { + etcdEndpoints = append(etcdEndpoints, "https://["+bootstrapIP+"]:2379") } - etcdEndpoints = append(etcdEndpoints, fmt.Sprintf("https://%s:2379", bootstrapIP)) } c, err := getEtcdClient(etcdEndpoints) if err != nil {