Skip to content

Commit

Permalink
validate: simplify CIDR validation
Browse files Browse the repository at this point in the history
Much of the code that made of the CIDR validation was there to give a custom
description of what made the CIDR provided invalid. This has been removed in
favor of using the error returned by the golang library's ParseCIDR function.

Additionally, the code to determine whether two CIDRs overlap was unnecessary
complex because it did not take advantage of the fact that CIDRs only overlap
if one is a subset of the other.

https://jira.coreos.com/browse/CORS-850
  • Loading branch information
staebler committed Dec 15, 2018
1 parent d813360 commit b2d6fa4
Show file tree
Hide file tree
Showing 26 changed files with 538 additions and 193 deletions.
1 change: 1 addition & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions pkg/asset/ignition/machine/master_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package machine

import (
"net"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -24,12 +23,7 @@ func TestMasterGenerate(t *testing.T) {
},
BaseDomain: "test-domain",
Networking: types.Networking{
ServiceCIDR: ipnet.IPNet{
IPNet: func(s string) net.IPNet {
_, cidr, _ := net.ParseCIDR(s)
return *cidr
}("10.0.1.0/24"),
},
ServiceCIDR: *ipnet.MustParseCIDR("10.0.1.0/24"),
},
Platform: types.Platform{
AWS: &aws.Platform{
Expand Down
8 changes: 1 addition & 7 deletions pkg/asset/ignition/machine/worker_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package machine

import (
"net"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -19,12 +18,7 @@ func TestWorkerGenerate(t *testing.T) {
installConfig := &installconfig.InstallConfig{
Config: &types.InstallConfig{
Networking: types.Networking{
ServiceCIDR: ipnet.IPNet{
IPNet: func(s string) net.IPNet {
_, cidr, _ := net.ParseCIDR(s)
return *cidr
}("10.0.1.0/24"),
},
ServiceCIDR: *ipnet.MustParseCIDR("10.0.1.0/24"),
},
Platform: types.Platform{
AWS: &aws.Platform{
Expand Down
38 changes: 8 additions & 30 deletions pkg/asset/installconfig/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,19 @@ import (
"github.com/sirupsen/logrus"
survey "gopkg.in/AlecAivazis/survey.v1"

"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types/aws"
)

const (
defaultVPCCIDR = "10.0.0.0/16"
)

var (
validAWSRegions = map[string]string{
"ap-northeast-1": "Tokyo",
"ap-northeast-2": "Seoul",
"ap-northeast-3": "Osaka-Local",
"ap-south-1": "Mumbai",
"ap-southeast-1": "Singapore",
"ap-southeast-2": "Sydney",
"ca-central-1": "Central",
"cn-north-1": "Beijing",
"cn-northwest-1": "Ningxia",
"eu-central-1": "Frankfurt",
"eu-west-1": "Ireland",
"eu-west-2": "London",
"eu-west-3": "Paris",
"sa-east-1": "São Paulo",
"us-east-1": "N. Virginia",
"us-east-2": "Ohio",
"us-west-1": "N. California",
"us-west-2": "Oregon",
}
defaultVPCCIDR = ipnet.MustParseCIDR("10.0.0.0/16")
)

// Platform collects AWS-specific configuration.
func Platform() (*aws.Platform, error) {
longRegions := make([]string, 0, len(validAWSRegions))
shortRegions := make([]string, 0, len(validAWSRegions))
for id, location := range validAWSRegions {
longRegions := make([]string, 0, len(aws.ValidRegions))
shortRegions := make([]string, 0, len(aws.ValidRegions))
for id, location := range aws.ValidRegions {
longRegions = append(longRegions, fmt.Sprintf("%s (%s)", id, location))
shortRegions = append(shortRegions, id)
}
Expand All @@ -59,7 +37,7 @@ func Platform() (*aws.Platform, error) {
})

defaultRegion := "us-east-1"
_, ok := validAWSRegions[defaultRegion]
_, ok := aws.ValidRegions[defaultRegion]
if !ok {
panic(fmt.Sprintf("installer bug: invalid default AWS region %q", defaultRegion))
}
Expand All @@ -81,7 +59,7 @@ func Platform() (*aws.Platform, error) {

defaultRegionPointer := ssn.Config.Region
if defaultRegionPointer != nil && *defaultRegionPointer != "" {
_, ok := validAWSRegions[*defaultRegionPointer]
_, ok := aws.ValidRegions[*defaultRegionPointer]
if ok {
defaultRegion = *defaultRegionPointer
} else {
Expand All @@ -98,7 +76,7 @@ func Platform() (*aws.Platform, error) {
Prompt: &survey.Select{
Message: "Region",
Help: "The AWS region to be used for installation.",
Default: fmt.Sprintf("%s (%s)", defaultRegion, validAWSRegions[defaultRegion]),
Default: fmt.Sprintf("%s (%s)", defaultRegion, aws.ValidRegions[defaultRegion]),
Options: longRegions,
},
Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
Expand Down
5 changes: 5 additions & 0 deletions pkg/asset/installconfig/installconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/validation"
)

const (
Expand Down Expand Up @@ -156,6 +157,10 @@ func (a *InstallConfig) Load(f asset.FileFetcher) (found bool, err error) {
return false, errors.Wrapf(err, "failed to unmarshal")
}

if err := validation.ValidateInstallConfig(config).ToAggregate(); err != nil {
return false, errors.Wrapf(err, "invalid %q file", installConfigFilename)
}

a.File, a.Config = file, config
return true, nil
}
10 changes: 7 additions & 3 deletions pkg/asset/installconfig/libvirt/libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import (
"github.com/pkg/errors"
survey "gopkg.in/AlecAivazis/survey.v1"

"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/rhcos"
"github.com/openshift/installer/pkg/types/libvirt"
"github.com/openshift/installer/pkg/validate"
)

const (
defaultNetworkIfName = "tt0"
defaultNetworkIPRange = "192.168.126.0/24"
defaultNetworkIfName = "tt0"
)

var (
defaultNetworkIPRange = ipnet.MustParseCIDR("192.168.126.0/24")
)

// Platform collects libvirt-specific configuration.
Expand Down Expand Up @@ -42,7 +46,7 @@ func Platform() (*libvirt.Platform, error) {
return &libvirt.Platform{
Network: libvirt.Network{
IfName: defaultNetworkIfName,
IPRange: defaultNetworkIPRange,
IPRange: *defaultNetworkIPRange,
},
DefaultMachinePlatform: &libvirt.MachinePool{
Image: qcowImage,
Expand Down
7 changes: 4 additions & 3 deletions pkg/asset/installconfig/openstack/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (
"github.com/pkg/errors"
survey "gopkg.in/AlecAivazis/survey.v1"

"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types/openstack"
)

const (
defaultVPCCIDR = "10.0.0.0/16"
var (
defaultNetworkCIDR = ipnet.MustParseCIDR("10.0.0.0/16")
)

// Read the valid cloud names from the clouds.yaml
Expand Down Expand Up @@ -235,7 +236,7 @@ func Platform() (*openstack.Platform, error) {
}

return &openstack.Platform{
NetworkCIDRBlock: defaultVPCCIDR,
NetworkCIDRBlock: *defaultNetworkCIDR,
Region: region,
BaseImage: image,
Cloud: cloud,
Expand Down
2 changes: 1 addition & 1 deletion pkg/asset/machines/libvirt/machines.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func provider(clusterName string, platform *libvirt.Platform, userDataSecret str
BaseVolumeID: fmt.Sprintf("/var/lib/libvirt/images/%s-base", clusterName),
},
NetworkInterfaceName: clusterName,
NetworkInterfaceAddress: platform.Network.IPRange,
NetworkInterfaceAddress: platform.Network.IPRange.String(),
Autostart: false,
URI: platform.URI,
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/ipnet/ipnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,22 @@ func (ipnet *IPNet) UnmarshalJSON(b []byte) (err error) {

return nil
}

// ParseCIDR parses a CIDR from its string representation.
func ParseCIDR(s string) (*IPNet, error) {
_, cidr, err := net.ParseCIDR(s)
if err != nil {
return nil, err
}
return &IPNet{IPNet: *cidr}, nil
}

// MustParseCIDR parses a CIDR from its string representation. If the parse fails,
// the function will panic.
func MustParseCIDR(s string) *IPNet {
cidr, err := ParseCIDR(s)
if err != nil {
panic(err)
}
return cidr
}
4 changes: 2 additions & 2 deletions pkg/tfvars/libvirt/libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ type Libvirt struct {

// Network describes a libvirt network configuration.
type Network struct {
IfName string `json:"libvirt_network_if,omitempty"`
IPRange string `json:"libvirt_ip_range,omitempty"`
IfName string `json:"libvirt_network_if"`
IPRange string `json:"libvirt_ip_range"`
}

// TFVars fills in computed Terraform variables.
Expand Down
15 changes: 10 additions & 5 deletions pkg/tfvars/tfvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,14 @@ func TFVars(cfg *types.InstallConfig, bootstrapIgn, masterIgn string) ([]byte, e
}

config.AWS = aws.AWS{
Region: cfg.Platform.AWS.Region,
ExtraTags: cfg.Platform.AWS.UserTags,
VPCCIDRBlock: cfg.Platform.AWS.VPCCIDRBlock,
Region: cfg.Platform.AWS.Region,
ExtraTags: cfg.Platform.AWS.UserTags,
VPCCIDRBlock: func() string {
if cfg.Platform.AWS.VPCCIDRBlock == nil {
return ""
}
return cfg.Platform.AWS.VPCCIDRBlock.String()
}(),
EC2AMIOverride: ami,
}
} else if cfg.Platform.Libvirt != nil {
Expand All @@ -96,7 +101,7 @@ func TFVars(cfg *types.InstallConfig, bootstrapIgn, masterIgn string) ([]byte, e
URI: cfg.Platform.Libvirt.URI,
Network: libvirt.Network{
IfName: cfg.Platform.Libvirt.Network.IfName,
IPRange: cfg.Platform.Libvirt.Network.IPRange,
IPRange: cfg.Platform.Libvirt.Network.IPRange.String(),
},
Image: cfg.Platform.Libvirt.DefaultMachinePlatform.Image,
MasterIPs: masterIPs,
Expand All @@ -110,7 +115,7 @@ func TFVars(cfg *types.InstallConfig, bootstrapIgn, masterIgn string) ([]byte, e
} else if cfg.Platform.OpenStack != nil {
config.OpenStack = openstack.OpenStack{
Region: cfg.Platform.OpenStack.Region,
NetworkCIDRBlock: cfg.Platform.OpenStack.NetworkCIDRBlock,
NetworkCIDRBlock: cfg.Platform.OpenStack.NetworkCIDRBlock.String(),
BaseImage: cfg.Platform.OpenStack.BaseImage,
}
config.OpenStack.Credentials.Cloud = cfg.Platform.OpenStack.Cloud
Expand Down
6 changes: 3 additions & 3 deletions pkg/types/aws/machinepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ func (a *MachinePool) Set(required *MachinePool) {

// EC2RootVolume defines the storage for an ec2 instance.
type EC2RootVolume struct {
// IOPS defines the iops for the instance.
// IOPS defines the iops for the storage.
IOPS int `json:"iops"`
// Size defines the size of the instance.
// Size defines the size of the storage.
Size int `json:"size"`
// Type defines the type of the instance.
// Type defines the type of the storage.
Type string `json:"type"`
}
33 changes: 32 additions & 1 deletion pkg/types/aws/platform.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
package aws

import (
"github.com/openshift/installer/pkg/ipnet"
)

var (
// ValidRegions is a map of the known AWS regions. The key of the map is
// the short name of the region. The value of the map is the long name of
// the region.
ValidRegions = map[string]string{
"ap-northeast-1": "Tokyo",
"ap-northeast-2": "Seoul",
"ap-northeast-3": "Osaka-Local",
"ap-south-1": "Mumbai",
"ap-southeast-1": "Singapore",
"ap-southeast-2": "Sydney",
"ca-central-1": "Central",
"cn-north-1": "Beijing",
"cn-northwest-1": "Ningxia",
"eu-central-1": "Frankfurt",
"eu-west-1": "Ireland",
"eu-west-2": "London",
"eu-west-3": "Paris",
"sa-east-1": "São Paulo",
"us-east-1": "N. Virginia",
"us-east-2": "Ohio",
"us-west-1": "N. California",
"us-west-2": "Oregon",
}
)

// Platform stores all the global configuration that all machinesets
// use.
type Platform struct {
Expand All @@ -15,5 +45,6 @@ type Platform struct {
DefaultMachinePlatform *MachinePool `json:"defaultMachinePlatform,omitempty"`

// VPCCIDRBlock
VPCCIDRBlock string `json:"vpcCIDRBlock"`
// +optional
VPCCIDRBlock *ipnet.IPNet `json:"vpcCIDRBlock,omitempty"`
}
19 changes: 19 additions & 0 deletions pkg/types/aws/validation/machinepool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package validation

import (
"k8s.io/apimachinery/pkg/util/validation/field"

"github.com/openshift/installer/pkg/types/aws"
)

// ValidateMachinePool checks that the specified machine pool is valid.
func ValidateMachinePool(p *aws.MachinePool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if p.IOPS < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("iops"), p.IOPS, "Storage IOPS must be positive"))
}
if p.Size < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("size"), p.IOPS, "Storage size must be positive"))
}
return allErrs
}
37 changes: 37 additions & 0 deletions pkg/types/aws/validation/platform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package validation

import (
"k8s.io/apimachinery/pkg/util/validation/field"

"github.com/openshift/installer/pkg/types/aws"
"github.com/openshift/installer/pkg/validate"
)

var (
validRegionValues = func() []string {
validValues := make([]string, len(aws.ValidRegions))
i := 0
for r := range aws.ValidRegions {
validValues[i] = r
i++
}
return validValues
}()
)

// ValidatePlatform checks that the specified platform is valid.
func ValidatePlatform(p *aws.Platform, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if _, ok := aws.ValidRegions[p.Region]; !ok {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("region"), p.Region, validRegionValues))
}
if p.DefaultMachinePlatform != nil {
allErrs = append(allErrs, ValidateMachinePool(p.DefaultMachinePlatform, fldPath.Child("defaultMachinePlatform"))...)
}
if p.VPCCIDRBlock != nil {
if err := validate.SubnetCIDR(&p.VPCCIDRBlock.IPNet); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("vpcCIDRBlock"), p.VPCCIDRBlock, err.Error()))
}
}
return allErrs
}
Loading

0 comments on commit b2d6fa4

Please sign in to comment.