summaryrefslogtreecommitdiffstats
path: root/src/orchestrator/pkg/infra/validation/validation.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/orchestrator/pkg/infra/validation/validation.go')
-rw-r--r--src/orchestrator/pkg/infra/validation/validation.go264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/orchestrator/pkg/infra/validation/validation.go b/src/orchestrator/pkg/infra/validation/validation.go
new file mode 100644
index 00000000..d744dc3d
--- /dev/null
+++ b/src/orchestrator/pkg/infra/validation/validation.go
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * 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 validation
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "io"
+ "net"
+ "regexp"
+ "strings"
+
+ pkgerrors "github.com/pkg/errors"
+ "k8s.io/apimachinery/pkg/util/validation"
+)
+
+func IsTarGz(r io.Reader) error {
+ //Check if it is a valid gz
+ gzf, err := gzip.NewReader(r)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Invalid gzip format")
+ }
+
+ //Check if it is a valid tar file
+ //Unfortunately this can only be done by inspecting all the tar contents
+ tarR := tar.NewReader(gzf)
+ first := true
+
+ for true {
+ header, err := tarR.Next()
+
+ if err == io.EOF {
+ //Check if we have just a gzip file without a tar archive inside
+ if first {
+ return pkgerrors.New("Empty or non-existant Tar file found")
+ }
+ //End of archive
+ break
+ }
+
+ if err != nil {
+ return pkgerrors.Errorf("Error reading tar file %s", err.Error())
+ }
+
+ //Check if files are of type directory and regular file
+ if header.Typeflag != tar.TypeDir &&
+ header.Typeflag != tar.TypeReg {
+ return pkgerrors.Errorf("Unknown header in tar %s, %s",
+ header.Name, string(header.Typeflag))
+ }
+
+ first = false
+ }
+
+ return nil
+}
+
+func IsIpv4Cidr(cidr string) error {
+ _, _, err := net.ParseCIDR(cidr)
+ if err != nil {
+ return pkgerrors.Wrapf(err, "could not parse subnet %v", cidr)
+ }
+ return nil
+}
+
+func IsIpv4(ip string) error {
+ addr := net.ParseIP(ip)
+ if addr == nil {
+ return pkgerrors.Errorf("invalid ipv4 address %v", ip)
+ }
+ return nil
+}
+
+// default name check - matches valid label value with addtion that length > 0
+func IsValidName(name string) []string {
+ var errs []string
+
+ errs = validation.IsValidLabelValue(name)
+ if len(name) == 0 {
+ errs = append(errs, "name must have non-zero length")
+ }
+ return errs
+}
+
+const VALID_NAME_STR string = "NAME"
+
+var validNameRegEx = regexp.MustCompile("^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$")
+
+const VALID_ALPHA_STR string = "ALPHA"
+
+var validAlphaStrRegEx = regexp.MustCompile("^[A-Za-z]*$")
+
+const VALID_ALPHANUM_STR string = "ALPHANUM"
+
+var validAlphaNumStrRegEx = regexp.MustCompile("^[A-Za-z0-9]*$")
+
+// doesn't verify valid base64 length - just checks for proper base64 characters
+const VALID_BASE64_STR string = "BASE64"
+
+var validBase64StrRegEx = regexp.MustCompile("^[A-Za-z0-9+/]+={0,2}$")
+
+const VALID_ANY_STR string = "ANY"
+
+var validAnyStrRegEx = regexp.MustCompile("(?s)^.*$")
+
+// string check - validates for conformance to provided lengths and specified content
+// min and max - the string
+// if format string provided - check against matching predefined
+func IsValidString(str string, min, max int, format string) []string {
+ var errs []string
+
+ if min > max {
+ errs = append(errs, "Invalid string length constraints - min is greater than max")
+ return errs
+ }
+
+ if len(str) < min {
+ errs = append(errs, "string length is less than the minimum constraint")
+ return errs
+ }
+ if len(str) > max {
+ errs = append(errs, "string length is greater than the maximum constraint")
+ return errs
+ }
+
+ switch format {
+ case VALID_ALPHA_STR:
+ if !validAlphaStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the alpha only constraint")
+ }
+ case VALID_ALPHANUM_STR:
+ if !validAlphaNumStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the alphanumeric only constraint")
+ }
+ case VALID_NAME_STR:
+ if !validNameRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the valid k8s name constraint")
+ }
+ case VALID_BASE64_STR:
+ if !validBase64StrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the valid base64 characters constraint")
+ }
+ if len(str)%4 != 0 {
+ errs = append(errs, "base64 string length should be a multiple of 4")
+ }
+ case VALID_ANY_STR:
+ if !validAnyStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the any characters constraint")
+ }
+ default:
+ // invalid string format supplied
+ errs = append(errs, "an invalid string constraint was supplied")
+ }
+
+ return errs
+}
+
+// validate that label conforms to kubernetes label conventions
+// general label format expected is:
+// "<labelprefix>/<labelname>=<Labelvalue>"
+// where labelprefix matches DNS1123Subdomain format
+// labelname matches DNS1123Label format
+//
+// Input labels are allowed to match following formats:
+// "<DNS1123Subdomain>/<DNS1123Label>=<Labelvalue>"
+// "<DNS1123Label>=<LabelValue>"
+// "<LabelValue>"
+func IsValidLabel(label string) []string {
+ var labelerrs []string
+
+ expectLabelName := false
+ expectLabelPrefix := false
+
+ // split label up into prefix, name and value
+ // format: prefix/name=value
+ var labelprefix, labelname, labelvalue string
+
+ kv := strings.SplitN(label, "=", 2)
+ if len(kv) == 1 {
+ labelprefix = ""
+ labelname = ""
+ labelvalue = kv[0]
+ } else {
+ pn := strings.SplitN(kv[0], "/", 2)
+ if len(pn) == 1 {
+ labelprefix = ""
+ labelname = pn[0]
+ } else {
+ labelprefix = pn[0]
+ labelname = pn[1]
+ expectLabelPrefix = true
+ }
+ labelvalue = kv[1]
+ // if "=" was in the label input, then expect a non-zero length name
+ expectLabelName = true
+ }
+
+ // check label prefix validity - prefix is optional
+ if len(labelprefix) > 0 {
+ errs := validation.IsDNS1123Subdomain(labelprefix)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ } else if expectLabelPrefix {
+ labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"]")
+ }
+ if expectLabelName {
+ errs := validation.IsDNS1123Label(labelname)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label name - label=["+label+"%], labelname=["+labelname+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ }
+ if len(labelvalue) > 0 {
+ errs := validation.IsValidLabelValue(labelvalue)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ } else {
+ // expect a non-zero value
+ labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"]")
+ }
+
+ return labelerrs
+}
+
+func IsValidNumber(value, min, max int) []string {
+ var errs []string
+
+ if min > max {
+ errs = append(errs, "invalid constraints")
+ return errs
+ }
+
+ if value < min {
+ errs = append(errs, "value less than minimum")
+ }
+ if value > max {
+ errs = append(errs, "value greater than maximum")
+ }
+ return errs
+}