sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/internal/validation/dns.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validation
    18  
    19  import (
    20  	"fmt"
    21  	"regexp"
    22  )
    23  
    24  // This file's code was modified from "k8s.io/apimachinery/pkg/util/validation"
    25  // to avoid package dependencies. In case of additional functionality from
    26  // "k8s.io/apimachinery" is needed, re-consider whether to add the dependency.
    27  
    28  const (
    29  	dns1123LabelFmt     string = "[a-z0-9](?:[-a-z0-9]*[a-z0-9])?"
    30  	dns1123SubdomainFmt string = dns1123LabelFmt + "(?:\\." + dns1123LabelFmt + ")*"
    31  	dns1035LabelFmt     string = "[a-z](?:[-a-z0-9]*[a-z0-9])?"
    32  )
    33  
    34  type dnsValidationConfig struct {
    35  	format   string
    36  	maxLen   int
    37  	re       *regexp.Regexp
    38  	errMsg   string
    39  	examples []string
    40  }
    41  
    42  var dns1123LabelConfig = dnsValidationConfig{
    43  	format: dns1123LabelFmt,
    44  	maxLen: 56, // = 63 - len("-system")
    45  	re:     regexp.MustCompile("^" + dns1123LabelFmt + "$"),
    46  	errMsg: "a DNS-1123 label must consist of lower case alphanumeric characters or '-', " +
    47  		"and must start and end with an alphanumeric character",
    48  	examples: []string{"example.com"},
    49  }
    50  
    51  var dns1123SubdomainConfig = dnsValidationConfig{
    52  	format: dns1123SubdomainFmt,
    53  	maxLen: 253, // a subdomain's max length in DNS (RFC 1123).
    54  	re:     regexp.MustCompile("^" + dns1123SubdomainFmt + "$"),
    55  	errMsg: "a DNS-1123 subdomain must consist of lower case alphanumeric characters, " +
    56  		"'-' or '.', and must start and end with an alphanumeric character",
    57  	examples: []string{"my-name", "abc-123"},
    58  }
    59  
    60  var dns1035LabelConfig = dnsValidationConfig{
    61  	format: dns1035LabelFmt,
    62  	maxLen: 63, // a label's max length in DNS (RFC 1035).
    63  	re:     regexp.MustCompile("^" + dns1035LabelFmt + "$"),
    64  	errMsg: "a DNS-1035 label must consist of lower case alphanumeric characters or '-', " +
    65  		"start with an alphabetic character, and end with an alphanumeric character",
    66  	examples: []string{"my-name", "123-abc"},
    67  }
    68  
    69  func (c dnsValidationConfig) check(value string) (errs []string) {
    70  	if len(value) > c.maxLen {
    71  		errs = append(errs, maxLenError(c.maxLen))
    72  	}
    73  	if !c.re.MatchString(value) {
    74  		errs = append(errs, regexError(c.errMsg, c.format, c.examples...))
    75  	}
    76  	return errs
    77  }
    78  
    79  // IsDNS1123Label tests for a string that conforms to the definition of a label in DNS (RFC 1123).
    80  func IsDNS1123Label(value string) []string {
    81  	return dns1123LabelConfig.check(value)
    82  }
    83  
    84  // IsDNS1123Subdomain tests for a string that conforms to the definition of a
    85  // subdomain in DNS (RFC 1123).
    86  func IsDNS1123Subdomain(value string) []string {
    87  	return dns1123SubdomainConfig.check(value)
    88  }
    89  
    90  // IsDNS1035Label tests for a string that conforms to the definition of a label in DNS (RFC 1035).
    91  func IsDNS1035Label(value string) []string {
    92  	return dns1035LabelConfig.check(value)
    93  }
    94  
    95  // maxLenError returns a string explanation of a "string too long" validation
    96  // failure.
    97  func maxLenError(length int) string {
    98  	return fmt.Sprintf("must be no more than %d characters", length)
    99  }
   100  
   101  // regexError returns a string explanation of a regex validation failure.
   102  func regexError(msg string, fmt string, examples ...string) string {
   103  	if len(examples) == 0 {
   104  		return msg + " (regex used for validation is '" + fmt + "')"
   105  	}
   106  	msg += " (e.g. "
   107  	for i := range examples {
   108  		if i > 0 {
   109  			msg += " or "
   110  		}
   111  		msg += "'" + examples[i] + "', "
   112  	}
   113  	msg += "regex used for validation is '" + fmt + "')"
   114  	return msg
   115  }