Skip to content

Commit

Permalink
Separate subnet utils into a standalone package
Browse files Browse the repository at this point in the history
  • Loading branch information
errordeveloper committed Oct 25, 2018
1 parent c33ac16 commit b3ce6e6
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 173 deletions.
2 changes: 1 addition & 1 deletion pkg/apis/kops/validation/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//pkg/featureflag:go_default_library",
"//pkg/model/components:go_default_library",
"//pkg/model/iam:go_default_library",
"//pkg/util/subnet:go_default_library",
"//upup/pkg/fi:go_default_library",
"//upup/pkg/fi/cloudup/awsup:go_default_library",
"//vendor/github.com/blang/semver:go_default_library",
Expand All @@ -35,7 +36,6 @@ go_test(
name = "go_default_test",
srcs = [
"aws_test.go",
"helpers_test.go",
"instancegroup_test.go",
"validation_test.go",
],
Expand Down
21 changes: 0 additions & 21 deletions pkg/apis/kops/validation/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,11 @@ limitations under the License.
package validation

import (
"net"
"net/url"

"k8s.io/apimachinery/pkg/util/validation/field"
)

// isSubnet checks if child is a subnet of parent
func isSubnet(parent *net.IPNet, child *net.IPNet) bool {
parentOnes, parentBits := parent.Mask.Size()
childOnes, childBits := child.Mask.Size()
if childBits != parentBits {
return false
}
if parentOnes > childOnes {
return false
}
childMasked := child.IP.Mask(parent.Mask)
parentMasked := parent.IP.Mask(parent.Mask)
return childMasked.Equal(parentMasked)
}

// subnetsOverlap checks if two subnets overlap
func subnetsOverlap(l *net.IPNet, r *net.IPNet) bool {
return l.Contains(r.IP) || r.Contains(l.IP)
}

func isValidAPIServersURL(s string) bool {
u, err := url.Parse(s)
if err != nil {
Expand Down
75 changes: 0 additions & 75 deletions pkg/apis/kops/validation/helpers_test.go

This file was deleted.

11 changes: 6 additions & 5 deletions pkg/apis/kops/validation/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/kops/pkg/apis/kops/util"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/model/components"
"k8s.io/kops/pkg/util/subnet"
"k8s.io/kops/upup/pkg/fi"

"github.com/blang/semver"
Expand Down Expand Up @@ -190,7 +191,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, "Cluster had an invalid NonMasqueradeCIDR")
}

if networkCIDR != nil && subnetsOverlap(nonMasqueradeCIDR, networkCIDR) && c.Spec.Networking != nil && c.Spec.Networking.AmazonVPC == nil {
if networkCIDR != nil && subnet.Overlap(nonMasqueradeCIDR, networkCIDR) && c.Spec.Networking != nil && c.Spec.Networking.AmazonVPC == nil {
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, fmt.Sprintf("NonMasqueradeCIDR %q cannot overlap with NetworkCIDR %q", nonMasqueradeCIDRString, c.Spec.NetworkCIDR))
}

Expand Down Expand Up @@ -220,7 +221,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {
return field.Invalid(fieldSpec.Child("ServiceClusterIPRange"), serviceClusterIPRangeString, "Cluster had an invalid ServiceClusterIPRange")
}

if !isSubnet(nonMasqueradeCIDR, serviceClusterIPRange) {
if !subnet.BelongsTo(nonMasqueradeCIDR, serviceClusterIPRange) {
return field.Invalid(fieldSpec.Child("ServiceClusterIPRange"), serviceClusterIPRangeString, fmt.Sprintf("ServiceClusterIPRange %q must be a subnet of NonMasqueradeCIDR %q", serviceClusterIPRangeString, c.Spec.NonMasqueradeCIDR))
}

Expand Down Expand Up @@ -266,7 +267,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {
return field.Invalid(fieldSpec.Child("KubeControllerManager", "ClusterCIDR"), clusterCIDRString, "Cluster had an invalid KubeControllerManager.ClusterCIDR")
}

if !isSubnet(nonMasqueradeCIDR, clusterCIDR) {
if !subnet.BelongsTo(nonMasqueradeCIDR, clusterCIDR) {
return field.Invalid(fieldSpec.Child("KubeControllerManager", "ClusterCIDR"), clusterCIDRString, fmt.Sprintf("KubeControllerManager.ClusterCIDR %q must be a subnet of NonMasqueradeCIDR %q", clusterCIDRString, c.Spec.NonMasqueradeCIDR))
}
}
Expand Down Expand Up @@ -625,12 +626,12 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {

// validateSubnetCIDR is responsible for validating subnets are part of the CIRDs assigned to the cluster.
func validateSubnetCIDR(networkCIDR *net.IPNet, additionalNetworkCIDRs []*net.IPNet, subnetCIDR *net.IPNet) bool {
if isSubnet(networkCIDR, subnetCIDR) {
if subnet.BelongsTo(networkCIDR, subnetCIDR) {
return true
}

for _, additionalNetworkCIDR := range additionalNetworkCIDRs {
if isSubnet(additionalNetworkCIDR, subnetCIDR) {
if subnet.BelongsTo(additionalNetworkCIDR, subnetCIDR) {
return true
}
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/util/subnet/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = ["subnet.go"],
importpath = "k8s.io/kops/pkg/util/subnet",
visibility = ["//visibility:public"],
)

go_test(
name = "go_default_test",
srcs = ["subnet_test.go"],
embed = [":go_default_library"],
)
69 changes: 69 additions & 0 deletions pkg/util/subnet/subnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package subnet

import (
"encoding/binary"
"fmt"
"net"
)

// Overlap checks if two subnets overlap
func Overlap(l, r *net.IPNet) bool {
return l.Contains(r.IP) || r.Contains(l.IP)
}

// BelongsTo checks if child is a subnet of parent
func BelongsTo(parent *net.IPNet, child *net.IPNet) bool {
parentOnes, parentBits := parent.Mask.Size()
childOnes, childBits := child.Mask.Size()
if childBits != parentBits {
return false
}
if parentOnes > childOnes {
return false
}
childMasked := child.IP.Mask(parent.Mask)
parentMasked := parent.IP.Mask(parent.Mask)
return childMasked.Equal(parentMasked)
}

// SplitInto8 splits the parent IPNet into 8 subnets
func SplitInto8(parent *net.IPNet) ([]*net.IPNet, error) {
networkLength, _ := parent.Mask.Size()
networkLength += 3

var subnets []*net.IPNet
for i := 0; i < 8; i++ {
ip4 := parent.IP.To4()
if ip4 != nil {
n := binary.BigEndian.Uint32(ip4)
n += uint32(i) << uint(32-networkLength)
subnetIP := make(net.IP, len(ip4))
binary.BigEndian.PutUint32(subnetIP, n)

subnets = append(subnets, &net.IPNet{
IP: subnetIP,
Mask: net.CIDRMask(networkLength, 32),
})
} else {
return nil, fmt.Errorf("Unexpected IP address type: %s", parent)
}
}

return subnets, nil
}
111 changes: 111 additions & 0 deletions pkg/util/subnet/subnet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package subnet

import (
"net"
"reflect"
"testing"
)

func Test_BelongsTo(t *testing.T) {
grid := []struct {
L string
R string
Belongs bool
}{
{
L: "192.168.1.0/24",
R: "192.168.0.0/24",
Belongs: false,
},
{
L: "192.168.0.0/16",
R: "192.168.0.0/24",
Belongs: true,
},
{
L: "192.168.0.0/24",
R: "192.168.0.0/16",
Belongs: false,
},
{
L: "192.168.0.0/16",
R: "192.168.0.0/16",
Belongs: true, // Not a strict subnet
},
{
L: "192.168.0.1/16",
R: "192.168.0.0/24",
Belongs: true,
},
{
L: "0.0.0.0/0",
R: "101.0.1.0/32",
Belongs: true,
},
}
for _, g := range grid {
_, l, err := net.ParseCIDR(g.L)
if err != nil {
t.Fatalf("error parsing %q: %v", g.L, err)
}
_, r, err := net.ParseCIDR(g.R)
if err != nil {
t.Fatalf("error parsing %q: %v", g.R, err)
}
actual := BelongsTo(l, r)
if actual != g.Belongs {
t.Errorf("isSubnet(%q, %q) = %v, expected %v", g.L, g.R, actual, g.Belongs)
}
}
}

func Test_SplitInto8(t *testing.T) {
tests := []struct {
parent string
expected []string
}{
{
parent: "1.2.3.0/24",
expected: []string{"1.2.3.0/27", "1.2.3.32/27", "1.2.3.64/27", "1.2.3.96/27", "1.2.3.128/27", "1.2.3.160/27", "1.2.3.192/27", "1.2.3.224/27"},
},
{
parent: "1.2.3.0/27",
expected: []string{"1.2.3.0/30", "1.2.3.4/30", "1.2.3.8/30", "1.2.3.12/30", "1.2.3.16/30", "1.2.3.20/30", "1.2.3.24/30", "1.2.3.28/30"},
},
}
for _, test := range tests {
_, parent, err := net.ParseCIDR(test.parent)
if err != nil {
t.Fatalf("error parsing parent cidr %q: %v", test.parent, err)
}

subnets, err := SplitInto8(parent)
if err != nil {
t.Fatalf("error splitting parent cidr %q: %v", parent, err)
}

var actual []string
for _, subnet := range subnets {
actual = append(actual, subnet.String())
}
if !reflect.DeepEqual(actual, test.expected) {
t.Fatalf("unexpected result of split: actual=%v, expected=%v", actual, test.expected)
}
}
}
1 change: 1 addition & 0 deletions upup/pkg/fi/cloudup/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ go_library(
"//pkg/resources/digitalocean:go_default_library",
"//pkg/resources/spotinst:go_default_library",
"//pkg/templates:go_default_library",
"//pkg/util/subnet:go_default_library",
"//upup/models:go_default_library",
"//upup/pkg/fi:go_default_library",
"//upup/pkg/fi/assettasks:go_default_library",
Expand Down
Loading

0 comments on commit b3ce6e6

Please sign in to comment.