Merge pull request #3148 from justinsb/validation_cleanup

Automatic merge from submit-queue

Rework legacy validation to use field error helpers
This commit is contained in:
Kubernetes Submit Queue 2017-08-17 05:47:32 -07:00 committed by GitHub
commit d96e1870cf
4 changed files with 93 additions and 99 deletions

View File

@ -32,25 +32,22 @@ import (
// legacy contains validation functions that don't match the apimachinery style
// ValidateCluster is responsible for checking the validatity of the Cluster spec
func ValidateCluster(c *kops.Cluster, strict bool) error {
specField := field.NewPath("Spec")
// ValidateCluster is responsible for checking the validitity of the Cluster spec
func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {
fieldSpec := field.NewPath("Spec")
var err error
specPath := field.NewPath("Cluster").Child("Spec")
// kubernetesRelease is the version with only major & minor fields
var kubernetesRelease semver.Version
// KubernetesVersion
if c.Spec.KubernetesVersion == "" {
return field.Required(specField.Child("KubernetesVersion"), "")
return field.Required(fieldSpec.Child("KubernetesVersion"), "")
}
sv, err := util.ParseKubernetesVersion(c.Spec.KubernetesVersion)
if err != nil {
return field.Invalid(specField.Child("KubernetesVersion"), c.Spec.KubernetesVersion, "unable to determine kubernetes version")
return field.Invalid(fieldSpec.Child("KubernetesVersion"), c.Spec.KubernetesVersion, "unable to determine kubernetes version")
}
kubernetesRelease = semver.Version{Major: sv.Major, Minor: sv.Minor}
@ -62,45 +59,45 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
// Must be a dns name
errs := validation.IsDNS1123Subdomain(c.ObjectMeta.Name)
if len(errs) != 0 {
return fmt.Errorf("Cluster Name must be a valid DNS name (e.g. --name=mycluster.myzone.com) errors: %s", strings.Join(errs, ", "))
return field.Invalid(field.NewPath("Name"), c.ObjectMeta.Name, fmt.Sprintf("Cluster Name must be a valid DNS name (e.g. --name=mycluster.myzone.com) errors: %s", strings.Join(errs, ", ")))
}
if !strings.Contains(c.ObjectMeta.Name, ".") {
// Tolerate if this is a cluster we are importing for upgrade
if c.ObjectMeta.Annotations[kops.AnnotationNameManagement] != kops.AnnotationValueManagementImported {
return fmt.Errorf("Cluster Name must be a fully-qualified DNS name (e.g. --name=mycluster.myzone.com)")
return field.Invalid(field.NewPath("Name"), c.ObjectMeta.Name, "Cluster Name must be a fully-qualified DNS name (e.g. --name=mycluster.myzone.com)")
}
}
}
if len(c.Spec.Subnets) == 0 {
// TODO: Auto choose zones from region?
return fmt.Errorf("must configure at least one Subnet (use --zones)")
return field.Required(fieldSpec.Child("Subnets"), "must configure at least one Subnet (use --zones)")
}
if strict && c.Spec.Kubelet == nil {
return fmt.Errorf("Kubelet not configured")
return field.Required(fieldSpec.Child("Kubelet"), "Kubelet not configured")
}
if strict && c.Spec.MasterKubelet == nil {
return fmt.Errorf("MasterKubelet not configured")
return field.Required(fieldSpec.Child("MasterKubelet"), "MasterKubelet not configured")
}
if strict && c.Spec.KubeControllerManager == nil {
return fmt.Errorf("KubeControllerManager not configured")
return field.Required(fieldSpec.Child("KubeControllerManager"), "KubeControllerManager not configured")
}
if strict && c.Spec.KubeDNS == nil {
return fmt.Errorf("KubeDNS not configured")
return field.Required(fieldSpec.Child("KubeDNS"), "KubeDNS not configured")
}
if strict && c.Spec.Kubelet == nil {
return fmt.Errorf("Kubelet not configured")
if strict && c.Spec.KubeScheduler == nil {
return field.Required(fieldSpec.Child("KubeScheduler"), "KubeScheduler not configured")
}
if strict && c.Spec.KubeAPIServer == nil {
return fmt.Errorf("KubeAPIServer not configured")
return field.Required(fieldSpec.Child("KubeAPIServer"), "KubeAPIServer not configured")
}
if strict && c.Spec.KubeProxy == nil {
return fmt.Errorf("KubeProxy not configured")
return field.Required(fieldSpec.Child("KubeProxy"), "KubeProxy not configured")
}
if strict && c.Spec.Docker == nil {
return fmt.Errorf("Docker not configured")
return field.Required(fieldSpec.Child("Docker"), "Docker not configured")
}
// Check NetworkCIDR
@ -108,11 +105,11 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
{
networkCIDRString := c.Spec.NetworkCIDR
if networkCIDRString == "" {
return field.Required(specField.Child("NetworkCIDR"), "Cluster did not have NetworkCIDR set")
return field.Required(fieldSpec.Child("NetworkCIDR"), "Cluster did not have NetworkCIDR set")
}
_, networkCIDR, err = net.ParseCIDR(networkCIDRString)
if err != nil {
return field.Invalid(specField.Child("NetworkCIDR"), networkCIDRString, fmt.Sprintf("Cluster had an invalid NetworkCIDR"))
return field.Invalid(fieldSpec.Child("NetworkCIDR"), networkCIDRString, fmt.Sprintf("Cluster had an invalid NetworkCIDR"))
}
}
@ -121,25 +118,25 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
{
nonMasqueradeCIDRString := c.Spec.NonMasqueradeCIDR
if nonMasqueradeCIDRString == "" {
return fmt.Errorf("Cluster did not have NonMasqueradeCIDR set")
return field.Required(fieldSpec.Child("NonMasqueradeCIDR"), "Cluster did not have NonMasqueradeCIDR set")
}
_, nonMasqueradeCIDR, err = net.ParseCIDR(nonMasqueradeCIDRString)
if err != nil {
return fmt.Errorf("Cluster had an invalid NonMasqueradeCIDR: %q", nonMasqueradeCIDRString)
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, "Cluster had an invalid NonMasqueradeCIDR")
}
if subnetsOverlap(nonMasqueradeCIDR, networkCIDR) {
return fmt.Errorf("NonMasqueradeCIDR %q cannot overlap with NetworkCIDR %q", nonMasqueradeCIDRString, c.Spec.NetworkCIDR)
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, fmt.Sprintf("NonMasqueradeCIDR %q cannot overlap with NetworkCIDR %q", nonMasqueradeCIDRString, c.Spec.NetworkCIDR))
}
if c.Spec.Kubelet != nil && c.Spec.Kubelet.NonMasqueradeCIDR != nonMasqueradeCIDRString {
if strict || c.Spec.Kubelet.NonMasqueradeCIDR != "" {
return fmt.Errorf("Kubelet NonMasqueradeCIDR did not match cluster NonMasqueradeCIDR")
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, "Kubelet NonMasqueradeCIDR did not match cluster NonMasqueradeCIDR")
}
}
if c.Spec.MasterKubelet != nil && c.Spec.MasterKubelet.NonMasqueradeCIDR != nonMasqueradeCIDRString {
if strict || c.Spec.MasterKubelet.NonMasqueradeCIDR != "" {
return fmt.Errorf("MasterKubelet NonMasqueradeCIDR did not match cluster NonMasqueradeCIDR")
return field.Invalid(fieldSpec.Child("NonMasqueradeCIDR"), nonMasqueradeCIDRString, "MasterKubelet NonMasqueradeCIDR did not match cluster NonMasqueradeCIDR")
}
}
}
@ -150,21 +147,21 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
serviceClusterIPRangeString := c.Spec.ServiceClusterIPRange
if serviceClusterIPRangeString == "" {
if strict {
return fmt.Errorf("Cluster did not have ServiceClusterIPRange set")
return field.Required(fieldSpec.Child("ServiceClusterIPRange"), "Cluster did not have ServiceClusterIPRange set")
}
} else {
_, serviceClusterIPRange, err = net.ParseCIDR(serviceClusterIPRangeString)
if err != nil {
return fmt.Errorf("Cluster had an invalid ServiceClusterIPRange: %q", serviceClusterIPRangeString)
return field.Invalid(fieldSpec.Child("ServiceClusterIPRange"), serviceClusterIPRangeString, "Cluster had an invalid ServiceClusterIPRange")
}
if !isSubnet(nonMasqueradeCIDR, serviceClusterIPRange) {
return fmt.Errorf("ServiceClusterIPRange %q must be a subnet of NonMasqueradeCIDR %q", serviceClusterIPRangeString, c.Spec.NonMasqueradeCIDR)
return field.Invalid(fieldSpec.Child("ServiceClusterIPRange"), serviceClusterIPRangeString, fmt.Sprintf("ServiceClusterIPRange %q must be a subnet of NonMasqueradeCIDR %q", serviceClusterIPRangeString, c.Spec.NonMasqueradeCIDR))
}
if c.Spec.KubeAPIServer != nil && c.Spec.KubeAPIServer.ServiceClusterIPRange != serviceClusterIPRangeString {
if strict || c.Spec.KubeAPIServer.ServiceClusterIPRange != "" {
return fmt.Errorf("KubeAPIServer ServiceClusterIPRange did not match cluster ServiceClusterIPRange")
return field.Invalid(fieldSpec.Child("ServiceClusterIPRange"), serviceClusterIPRangeString, "KubeAPIServer ServiceClusterIPRange did not match cluster ServiceClusterIPRange")
}
}
}
@ -177,11 +174,11 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
if clusterCIDRString != "" {
_, clusterCIDR, err = net.ParseCIDR(clusterCIDRString)
if err != nil {
return fmt.Errorf("Cluster had an invalid KubeControllerManager.ClusterCIDR: %q", clusterCIDRString)
return field.Invalid(fieldSpec.Child("KubeControllerManager", "ClusterCIDR"), clusterCIDRString, "Cluster had an invalid KubeControllerManager.ClusterCIDR")
}
if !isSubnet(nonMasqueradeCIDR, clusterCIDR) {
return fmt.Errorf("KubeControllerManager.ClusterCIDR %q must be a subnet of NonMasqueradeCIDR %q", clusterCIDRString, c.Spec.NonMasqueradeCIDR)
return field.Invalid(fieldSpec.Child("KubeControllerManager", "ClusterCIDR"), clusterCIDRString, fmt.Sprintf("KubeControllerManager.ClusterCIDR %q must be a subnet of NonMasqueradeCIDR %q", clusterCIDRString, c.Spec.NonMasqueradeCIDR))
}
}
}
@ -190,23 +187,23 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
if c.Spec.KubeDNS != nil {
serverIPString := c.Spec.KubeDNS.ServerIP
if serverIPString == "" {
return fmt.Errorf("Cluster did not have KubeDNS.ServerIP set")
return field.Required(fieldSpec.Child("KubeDNS", "ServerIP"), "Cluster did not have KubeDNS.ServerIP set")
}
dnsServiceIP := net.ParseIP(serverIPString)
if dnsServiceIP == nil {
return fmt.Errorf("Cluster had an invalid KubeDNS.ServerIP: %q", serverIPString)
return field.Invalid(fieldSpec.Child("KubeDNS", "ServerIP"), serverIPString, "Cluster had an invalid KubeDNS.ServerIP")
}
if !serviceClusterIPRange.Contains(dnsServiceIP) {
return fmt.Errorf("ServiceClusterIPRange %q must contain the DNS Server IP %q", c.Spec.ServiceClusterIPRange, serverIPString)
return field.Invalid(fieldSpec.Child("KubeDNS", "ServerIP"), serverIPString, fmt.Sprintf("ServiceClusterIPRange %q must contain the DNS Server IP %q", c.Spec.ServiceClusterIPRange, serverIPString))
}
if c.Spec.Kubelet != nil && c.Spec.Kubelet.ClusterDNS != c.Spec.KubeDNS.ServerIP {
return fmt.Errorf("Kubelet ClusterDNS did not match cluster KubeDNS.ServerIP")
return field.Invalid(fieldSpec.Child("KubeDNS", "ServerIP"), serverIPString, "Kubelet ClusterDNS did not match cluster KubeDNS.ServerIP")
}
if c.Spec.MasterKubelet != nil && c.Spec.MasterKubelet.ClusterDNS != c.Spec.KubeDNS.ServerIP {
return fmt.Errorf("MasterKubelet ClusterDNS did not match cluster KubeDNS.ServerIP")
return field.Invalid(fieldSpec.Child("KubeDNS", "ServerIP"), serverIPString, "MasterKubelet ClusterDNS did not match cluster KubeDNS.ServerIP")
}
}
@ -215,45 +212,46 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
cloudProvider := c.Spec.CloudProvider
if cloudProvider == "" {
return field.Required(specPath.Child("CloudProvider"), "")
return field.Required(fieldSpec.Child("CloudProvider"), "")
}
if c.Spec.Kubelet != nil && (strict || c.Spec.Kubelet.CloudProvider != "") {
if cloudProvider != c.Spec.Kubelet.CloudProvider {
return field.Invalid(specPath.Child("Kubelet", "CloudProvider"), c.Spec.Kubelet.CloudProvider, "Did not match cluster CloudProvider")
return field.Invalid(fieldSpec.Child("Kubelet", "CloudProvider"), c.Spec.Kubelet.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.MasterKubelet != nil && (strict || c.Spec.MasterKubelet.CloudProvider != "") {
if cloudProvider != c.Spec.MasterKubelet.CloudProvider {
return field.Invalid(specPath.Child("MasterKubelet", "CloudProvider"), c.Spec.MasterKubelet.CloudProvider, "Did not match cluster CloudProvider")
return field.Invalid(fieldSpec.Child("MasterKubelet", "CloudProvider"), c.Spec.MasterKubelet.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.KubeAPIServer != nil && (strict || c.Spec.KubeAPIServer.CloudProvider != "") {
if cloudProvider != c.Spec.KubeAPIServer.CloudProvider {
return field.Invalid(specPath.Child("KubeAPIServer", "CloudProvider"), c.Spec.KubeAPIServer.CloudProvider, "Did not match cluster CloudProvider")
return field.Invalid(fieldSpec.Child("KubeAPIServer", "CloudProvider"), c.Spec.KubeAPIServer.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.KubeControllerManager != nil && (strict || c.Spec.KubeControllerManager.CloudProvider != "") {
if cloudProvider != c.Spec.KubeControllerManager.CloudProvider {
return field.Invalid(specPath.Child("KubeControllerManager", "CloudProvider"), c.Spec.KubeControllerManager.CloudProvider, "Did not match cluster CloudProvider")
return field.Invalid(fieldSpec.Child("KubeControllerManager", "CloudProvider"), c.Spec.KubeControllerManager.CloudProvider, "Did not match cluster CloudProvider")
}
}
}
// Check that the subnet CIDRs are all consistent
{
for _, s := range c.Spec.Subnets {
for i, s := range c.Spec.Subnets {
fieldSubnet := fieldSpec.Child("Subnets").Index(i)
if s.CIDR == "" {
if strict {
return fmt.Errorf("Subnet %q did not have a CIDR set", s.Name)
return field.Required(fieldSubnet.Child("CIDR"), "Subnet did not have a CIDR set")
}
} else {
_, subnetCIDR, err := net.ParseCIDR(s.CIDR)
if err != nil {
return fmt.Errorf("Subnet %q had an invalid CIDR: %q", s.Name, s.CIDR)
return field.Invalid(fieldSubnet.Child("CIDR"), s.CIDR, "Subnet had an invalid CIDR")
}
if !isSubnet(networkCIDR, subnetCIDR) {
return fmt.Errorf("Subnet %q had a CIDR %q that was not a subnet of the NetworkCIDR %q", s.Name, s.CIDR, c.Spec.NetworkCIDR)
return field.Invalid(fieldSubnet.Child("CIDR"), s.CIDR, fmt.Sprintf("Subnet %q had a CIDR %q that was not a subnet of the NetworkCIDR %q", s.Name, s.CIDR, c.Spec.NetworkCIDR))
}
}
}
@ -265,13 +263,13 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
case kops.UpdatePolicyExternal:
// Valid
default:
return fmt.Errorf("unrecognized value for UpdatePolicy: %v", *c.Spec.UpdatePolicy)
return field.Invalid(fieldSpec.Child("UpdatePolicy"), *c.Spec.UpdatePolicy, "unrecognized value for UpdatePolicy")
}
}
// KubeProxy
if c.Spec.KubeProxy != nil {
kubeProxyPath := specPath.Child("KubeProxy")
kubeProxyPath := fieldSpec.Child("KubeProxy")
master := c.Spec.KubeProxy.Master
// We no longer require the master to be set; nodeup can infer it automatically
@ -286,7 +284,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
// Kubelet
if c.Spec.Kubelet != nil {
kubeletPath := specPath.Child("Kubelet")
kubeletPath := fieldSpec.Child("Kubelet")
if kubernetesRelease.GTE(semver.MustParse("1.6.0")) {
// Flag removed in 1.6
@ -309,7 +307,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
// MasterKubelet
if c.Spec.MasterKubelet != nil {
masterKubeletPath := specPath.Child("MasterKubelet")
masterKubeletPath := fieldSpec.Child("MasterKubelet")
if kubernetesRelease.GTE(semver.MustParse("1.6.0")) {
// Flag removed in 1.6
@ -334,61 +332,64 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
if c.Spec.Topology != nil {
if c.Spec.Topology.Masters != "" && c.Spec.Topology.Nodes != "" {
if c.Spec.Topology.Masters != kops.TopologyPublic && c.Spec.Topology.Masters != kops.TopologyPrivate {
return fmt.Errorf("Invalid Masters value for Topology")
return field.Invalid(fieldSpec.Child("Topology", "Masters"), c.Spec.Topology.Masters, "Invalid Masters value for Topology")
} else if c.Spec.Topology.Nodes != kops.TopologyPublic && c.Spec.Topology.Nodes != kops.TopologyPrivate {
return fmt.Errorf("Invalid Nodes value for Topology")
return field.Invalid(fieldSpec.Child("Topology", "Nodes"), c.Spec.Topology.Nodes, "Invalid Nodes value for Topology")
}
} else {
return fmt.Errorf("Topology requires non-nil values for Masters and Nodes")
return field.Required(fieldSpec.Child("Masters"), "Topology requires non-nil values for Masters and Nodes")
}
if c.Spec.Topology.Bastion != nil {
bastion := c.Spec.Topology.Bastion
if c.Spec.Topology.Masters == kops.TopologyPublic || c.Spec.Topology.Nodes == kops.TopologyPublic {
return fmt.Errorf("Bastion supports only Private Masters and Nodes")
return field.Invalid(fieldSpec.Child("Topology", "Masters"), c.Spec.Topology.Masters, "Bastion supports only Private Masters and Nodes")
}
if bastion.IdleTimeoutSeconds != nil && *bastion.IdleTimeoutSeconds <= 0 {
return fmt.Errorf("Bastion IdleTimeoutSeconds should be greater than zero")
return field.Invalid(fieldSpec.Child("Topology", "Bastion", "IdleTimeoutSeconds"), *bastion.IdleTimeoutSeconds, "Bastion IdleTimeoutSeconds should be greater than zero")
}
if bastion.IdleTimeoutSeconds != nil && *bastion.IdleTimeoutSeconds > 3600 {
return fmt.Errorf("Bastion IdleTimeoutSeconds cannot be greater than one hour")
return field.Invalid(fieldSpec.Child("Topology", "Bastion", "IdleTimeoutSeconds"), *bastion.IdleTimeoutSeconds, "Bastion IdleTimeoutSeconds cannot be greater than one hour")
}
}
}
// Egress specification support
{
for _, s := range c.Spec.Subnets {
for i, s := range c.Spec.Subnets {
fieldSubnet := fieldSpec.Child("Subnets").Index(i)
if s.Egress != "" && !strings.HasPrefix(s.Egress, "nat-") {
return fmt.Errorf("egress must be of type NAT Gateway")
return field.Invalid(fieldSubnet.Child("Egress"), s.Egress, "egress must be of type NAT Gateway")
}
if s.Egress != "" && !(s.Type == "Private") {
return fmt.Errorf("egress can only be specified for Private subnets")
return field.Invalid(fieldSubnet.Child("Egress"), s.Egress, "egress can only be specified for Private subnets")
}
}
}
// Etcd
{
fieldEtcdClusters := fieldSpec.Child("EtcdClusters")
if len(c.Spec.EtcdClusters) == 0 {
return field.Required(specField.Child("EtcdClusters"), "")
return field.Required(fieldEtcdClusters, "")
}
for _, x := range c.Spec.EtcdClusters {
if err := validateEtcdClusterSpec(x); err != nil {
for i, x := range c.Spec.EtcdClusters {
if err := validateEtcdClusterSpec(x, fieldEtcdClusters.Index(i)); err != nil {
return err
}
}
if err := validateEtcdTLS(c.Spec.EtcdClusters); err != nil {
if err := validateEtcdTLS(c.Spec.EtcdClusters, fieldEtcdClusters); err != nil {
return err
}
if err := validateEtcdStorage(c.Spec.EtcdClusters); err != nil {
if err := validateEtcdStorage(c.Spec.EtcdClusters, fieldEtcdClusters); err != nil {
return err
}
}
if kubernetesRelease.GTE(semver.MustParse("1.4.0")) {
if c.Spec.Networking != nil && c.Spec.Networking.Classic != nil {
return field.Invalid(specField.Child("Networking"), "classic", "classic networking is not supported with kubernetes versions 1.4 and later")
return field.Invalid(fieldSpec.Child("Networking"), "classic", "classic networking is not supported with kubernetes versions 1.4 and later")
}
}
@ -400,23 +401,23 @@ func ValidateCluster(c *kops.Cluster, strict bool) error {
}
// validateEtcdClusterSpec is responsible for validating the etcd cluster spec
func validateEtcdClusterSpec(spec *kops.EtcdClusterSpec) error {
func validateEtcdClusterSpec(spec *kops.EtcdClusterSpec, fieldPath *field.Path) *field.Error {
if spec.Name == "" {
return fmt.Errorf("EtcdCluster did not have name")
return field.Required(fieldPath.Child("Name"), "EtcdCluster did not have name")
}
if len(spec.Members) == 0 {
return fmt.Errorf("No members defined in spec cluster %q", spec.Name)
return field.Required(fieldPath.Child("Members"), "No members defined in etcd cluster")
}
if (len(spec.Members) % 2) == 0 {
// Not technically a requirement, but doesn't really make sense to allow
return fmt.Errorf("Should be an odd number of master-zones for quorum. Use --zones and --master-zones to declare node zones and master zones separately")
return field.Invalid(fieldPath.Child("Members"), len(spec.Members), "Should be an odd number of master-zones for quorum. Use --zones and --master-zones to declare node zones and master zones separately")
}
if err := validateEtcdVersion(spec); err != nil {
if err := validateEtcdVersion(spec, fieldPath); err != nil {
return err
}
for _, m := range spec.Members {
if err := validateEtcdMemberSpec(m); err != nil {
return fmt.Errorf("Member in cluster: %q invalid, error: %q", spec.Name, err)
if err := validateEtcdMemberSpec(m, fieldPath); err != nil {
return err
}
}
@ -424,7 +425,7 @@ func validateEtcdClusterSpec(spec *kops.EtcdClusterSpec) error {
}
// validateEtcdTLS checks the TLS settings for etcd are valid
func validateEtcdTLS(specs []*kops.EtcdClusterSpec) error {
func validateEtcdTLS(specs []*kops.EtcdClusterSpec, fieldPath *field.Path) *field.Error {
var usingTLS int
for _, x := range specs {
if x.EnableEtcdTLS {
@ -433,18 +434,18 @@ func validateEtcdTLS(specs []*kops.EtcdClusterSpec) error {
}
// check both clusters are using tls if one us enabled
if usingTLS > 0 && usingTLS != len(specs) {
return fmt.Errorf("Both etcd clusters must have TLS enabled or none at all")
return field.Invalid(fieldPath.Index(0).Child("EnableEtcdTLS"), false, "Both etcd clusters must have TLS enabled or none at all")
}
return nil
}
// validateEtcdStorage is responsible for checks version are identical
func validateEtcdStorage(specs []*kops.EtcdClusterSpec) error {
func validateEtcdStorage(specs []*kops.EtcdClusterSpec, fieldPath *field.Path) *field.Error {
version := specs[0].Version
for _, x := range specs {
for i, x := range specs {
if x.Version != "" && x.Version != version {
return fmt.Errorf("cluster: %q, has a different storage versions: %q, both must be the same", x.Name, x.Version)
return field.Invalid(fieldPath.Index(i).Child("Version"), x.Version, fmt.Sprintf("cluster: %q, has a different storage versions: %q, both must be the same", x.Name, x.Version))
}
}
@ -453,7 +454,7 @@ func validateEtcdStorage(specs []*kops.EtcdClusterSpec) error {
// validateEtcdVersion is responsible for validating the storage version of etcd
// @TODO semvar package doesn't appear to ignore a 'v' in v1.1.1 should could be a problem later down the line
func validateEtcdVersion(spec *kops.EtcdClusterSpec) error {
func validateEtcdVersion(spec *kops.EtcdClusterSpec, fieldPath *field.Path) *field.Error {
// @check if the storage is specified, thats is valid
if spec.Version == "" {
return nil // as it will be filled in by default for us
@ -461,7 +462,7 @@ func validateEtcdVersion(spec *kops.EtcdClusterSpec) error {
sem, err := semver.Parse(strings.TrimPrefix(spec.Version, "v"))
if err != nil {
return fmt.Errorf("the storage version: %q for cluster: %q is invalid", spec.Version, spec.Name)
return field.Invalid(fieldPath.Child("Version"), spec.Version, "the storage version is invalid")
}
// we only support v3 and v2 for now
@ -469,17 +470,17 @@ func validateEtcdVersion(spec *kops.EtcdClusterSpec) error {
return nil
}
return fmt.Errorf("unsupported storage version: %q, we only support major versions 2 and 3", spec.Version)
return field.Invalid(fieldPath.Child("Version"), spec.Version, "unsupported storage version, we only support major versions 2 and 3")
}
// validateEtcdMemberSpec is responsible for validate the cluster member
func validateEtcdMemberSpec(spec *kops.EtcdMemberSpec) error {
func validateEtcdMemberSpec(spec *kops.EtcdMemberSpec, fieldPath *field.Path) *field.Error {
if spec.Name == "" {
return fmt.Errorf("does not have a name")
return field.Required(fieldPath.Child("Name"), "EtcdMember did not have Name")
}
if fi.StringValue(spec.InstanceGroup) == "" {
return fmt.Errorf("does not have a instance group")
return field.Required(fieldPath.Child("InstanceGroup"), "EtcdMember did not have InstanceGroup")
}
return nil

View File

@ -90,8 +90,7 @@ func (c *ClusterVFS) List(options metav1.ListOptions) (*api.ClusterList, error)
}
func (r *ClusterVFS) Create(c *api.Cluster) (*api.Cluster, error) {
err := validation.ValidateCluster(c, false)
if err != nil {
if err := validation.ValidateCluster(c, false); err != nil {
return nil, err
}
@ -104,8 +103,7 @@ func (r *ClusterVFS) Create(c *api.Cluster) (*api.Cluster, error) {
return nil, fmt.Errorf("clusterName is required")
}
err = r.writeConfig(r.basePath.Join(clusterName, registry.PathCluster), c, vfs.WriteOptionCreate)
if err != nil {
if err := r.writeConfig(r.basePath.Join(clusterName, registry.PathCluster), c, vfs.WriteOptionCreate); err != nil {
if os.IsExist(err) {
return nil, err
}
@ -126,8 +124,7 @@ func (r *ClusterVFS) Update(c *api.Cluster) (*api.Cluster, error) {
return nil, fmt.Errorf("clusterName is required")
}
err = r.writeConfig(r.basePath.Join(clusterName, registry.PathCluster), c, vfs.WriteOptionOnlyIfExists)
if err != nil {
if err := r.writeConfig(r.basePath.Join(clusterName, registry.PathCluster), c, vfs.WriteOptionOnlyIfExists); err != nil {
if os.IsNotExist(err) {
return nil, err
}

View File

@ -96,8 +96,7 @@ func PopulateClusterSpec(cluster *api.Cluster, assetBuilder *assets.AssetBuilder
// @kris-nova
//
func (c *populateClusterSpec) run() error {
err := validation.ValidateCluster(c.InputCluster, false)
if err != nil {
if err := validation.ValidateCluster(c.InputCluster, false); err != nil {
return err
}
@ -106,7 +105,7 @@ func (c *populateClusterSpec) run() error {
utils.JsonMergeStruct(cluster, c.InputCluster)
err = c.assignSubnets(cluster)
err := c.assignSubnets(cluster)
if err != nil {
return err
}
@ -326,8 +325,7 @@ func (c *populateClusterSpec) run() error {
fullCluster.Spec = *completed
tf.cluster = fullCluster
err = validation.ValidateCluster(fullCluster, true)
if err != nil {
if err := validation.ValidateCluster(fullCluster, true); err != nil {
return fmt.Errorf("Completed cluster failed validation: %v", err)
}

View File

@ -108,13 +108,11 @@ func buildDefaultCluster(t *testing.T) *api.Cluster {
func TestValidateFull_Default_Validates(t *testing.T) {
c := buildDefaultCluster(t)
err := validation.ValidateCluster(c, false)
if err != nil {
if err := validation.ValidateCluster(c, false); err != nil {
glog.Infof("Cluster: %v", c)
t.Fatalf("Validate gave unexpected error (strict=false): %v", err)
}
err = validation.ValidateCluster(c, true)
if err != nil {
if err := validation.ValidateCluster(c, true); err != nil {
t.Fatalf("Validate gave unexpected error (strict=true): %v", err)
}
}