func NewValidator()

in internal/api/validate.go [60:196]


func NewValidator() *validator.Validate {
	var err error

	validate := validator.New(validator.WithRequiredStructEnabled())

	// Use "json" struct tags for alternate field names.
	// Alternate field names will be used in validation errors.
	validate.RegisterTagNameFunc(func(field reflect.StructField) string {
		return GetJSONTagName(field.Tag)
	})

	// Register ARM-mandated enumeration types.
	validate.RegisterAlias("enum_managedserviceidentitytype", EnumValidateTag(
		arm.ManagedServiceIdentityTypeNone,
		arm.ManagedServiceIdentityTypeSystemAssigned,
		arm.ManagedServiceIdentityTypeSystemAssignedUserAssigned,
		arm.ManagedServiceIdentityTypeUserAssigned))
	validate.RegisterAlias("enum_subscriptionstate", EnumValidateTag(
		arm.SubscriptionStateRegistered,
		arm.SubscriptionStateUnregistered,
		arm.SubscriptionStateWarned,
		arm.SubscriptionStateDeleted,
		arm.SubscriptionStateSuspended))

	// Use this for string fields specifying an ARO-HCP API version.
	err = validate.RegisterValidation("api_version", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		if field.Kind() != reflect.String {
			panic("String type required for api_version")
		}
		_, ok := Lookup(field.String())
		return ok
	})
	if err != nil {
		panic(err)
	}

	// Use this for string fields that must be a valid Kubernetes qualified name.
	err = validate.RegisterValidation("k8s_qualified_name", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		if field.Kind() != reflect.String {
			panic("String type required for k8s_qualified_name")
		}
		return len(k8svalidation.IsQualifiedName(field.String())) == 0
	})
	if err != nil {
		panic(err)
	}

	// Use this for string fields that must be a valid Kubernetes label value.
	err = validate.RegisterValidation("k8s_label_value", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		if field.Kind() != reflect.String {
			panic("String type required for k8s_label_value")
		}
		return len(k8svalidation.IsValidLabelValue(field.String())) == 0
	})
	if err != nil {
		panic(err)
	}

	// Use this for version ID fields that might begin with "openshift-v".
	err = validate.RegisterValidation("openshift_version", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		if field.Kind() != reflect.String {
			panic("String type required for openshift_version")
		}
		_, err := NewOpenShiftVersion(field.String())
		return err == nil
	})
	if err != nil {
		panic(err)
	}

	// Use this for string fields providing PEM encoded certificates.
	err = validate.RegisterValidation("pem_certificates", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		if field.Kind() != reflect.String {
			panic("String type required for pem_certificates")
		}
		return x509.NewCertPool().AppendCertsFromPEM([]byte(field.String()))
	})
	if err != nil {
		panic(err)
	}

	// Use this for fields required in PUT requests. Do not apply to read-only fields.
	err = validate.RegisterValidation("required_for_put", func(fl validator.FieldLevel) bool {
		val := fl.Top().FieldByName("Method")
		if val.IsZero() {
			panic("Method field not found for required_for_put")
		}
		if val.String() != http.MethodPut {
			return true
		}

		// This is replicating the implementation of "required".
		// See https://github.com/go-playground/validator/issues/492
		// Sounds like "hasValue" is unlikely to be exported and
		// "validate.Var" does not seem like a safe alternative.
		field := fl.Field()
		_, kind, nullable := fl.ExtractType(field)
		switch kind {
		case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
			return !field.IsNil()
		default:
			if nullable && field.Interface() != nil {
				return true
			}
			return field.IsValid() && !field.IsZero()
		}
	})
	if err != nil {
		panic(err)
	}

	// Use this for string fields specifying an Azure resource ID.
	// The optional argument further enforces a specific resource type.
	err = validate.RegisterValidation("resource_id", func(fl validator.FieldLevel) bool {
		field := fl.Field()
		param := fl.Param()
		if field.Kind() != reflect.String {
			panic("String type required for resource_id")
		}
		resourceID, err := azcorearm.ParseResourceID(field.String())
		if err != nil {
			return false
		}
		resourceType := resourceID.ResourceType.String()
		return param == "" || strings.EqualFold(resourceType, param)
	})
	if err != nil {
		panic(err)
	}

	return validate
}