pkg/validate/validate_component.go (88 lines of code) (raw):
// Copyright 2018 Google LLC
//
// 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
//
// https://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 validate
import (
"fmt"
"regexp"
bundle "github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/apis/bundle/v1alpha1"
"github.com/blang/semver"
"k8s.io/apimachinery/pkg/util/validation/field"
)
var (
apiVersionPattern = regexp.MustCompile(`^bundle.gke.io/\w+$`)
)
// Components validates a list of components.
func Components(components []*bundle.Component) field.ErrorList {
errs := field.ErrorList{}
for _, component := range components {
compErrs := Component(component)
for _, err := range compErrs {
errs = append(errs, err)
}
}
return errs
}
// Component validates a single component.
func Component(c *bundle.Component) field.ErrorList {
errs := field.ErrorList{}
pi := field.NewPath("Component")
n := c.Spec.ComponentName
if n == "" {
errs = append(errs, field.Required(pi.Child("Spec", "ComponentName"), "components must have ComponentName"))
}
ver := c.Spec.Version
if ver == "" {
errs = append(errs, field.Required(pi.Child("Spec", "Version"), "components must have a Version"))
}
if n == "" || ver == "" {
// Subsequent validation relies on components having a unique name+version pair.
return errs
}
p := cPath(c.ComponentReference())
if nameErrs := validateName(p.Child("Spec", "ComponentName"), n); len(errs) > 0 {
errs = append(errs, nameErrs...)
}
api := c.APIVersion
if !apiVersionPattern.MatchString(api) {
errs = append(errs, field.Invalid(p.Child("APIVersion"), api, "must have the form \"bundle.gke.io/<version>\""))
}
expType := "Component"
if k := c.Kind; k != expType {
errs = append(errs, field.Invalid(p.Child("Kind"), k, "kind must be Component"))
}
if _, err := semver.Parse(ver); err != nil {
errs = append(errs, field.Invalid(p.Child("Spec", "Version"), ver, fmt.Sprintf("must be a SemVer version: %v", err)))
}
return errs
}
// ComponentSet validates a component.
func ComponentSet(cs *bundle.ComponentSet) field.ErrorList {
p := field.NewPath("ComponentSet")
errs := field.ErrorList{}
if cs == nil {
return errs
}
n := cs.Spec.SetName
if n == "" {
errs = append(errs, field.Required(p.Child("Spec", "SetName"), "setName is required"))
}
ver := cs.Spec.Version
if ver == "" {
errs = append(errs, field.Required(p.Child("Spec", "Version"), "version is required"))
}
if n == "" || ver == "" {
// Other validation relies on components having a unique name+version pair.
return errs
}
if nameErrs := validateName(p.Child("Spec", "SetName"), n); len(nameErrs) > 0 {
errs = append(errs, nameErrs...)
}
api := cs.APIVersion
if !apiVersionPattern.MatchString(api) {
errs = append(errs, field.Invalid(p.Child("APIVersion"), api, "must have an apiVersion of the form \"bundle.gke.io/<version>\""))
}
expType := "ComponentSet"
if k := cs.Kind; k != expType {
errs = append(errs, field.Invalid(p.Child("Kind"), k, "must be ComponentSet"))
}
if _, err := semver.Parse(ver); err != nil {
errs = append(errs, field.Invalid(p.Child("Spec", "Version"), ver, fmt.Sprintf("must be a SemVer version: %v", err)))
}
return errs
}
func cPath(ref bundle.ComponentReference) *field.Path {
return field.NewPath("Component").Key(fmt.Sprintf("%v", ref))
}