func validateCluster(sl validator.StructLevel) {
	cluster := sl.Current().Addr().Interface().(*Cluster)  
	if cluster.Namespace != runtime.SystemNS {
		sl.ReportError(cluster.Namespace, "Namespace", "", "systemNS", "")
	}
}
checks if cluster is valid
package lang
import (
	"context"
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"github.com/Aptomi/aptomi/pkg/lang/expression"
	"github.com/Aptomi/aptomi/pkg/lang/template"
	"github.com/Aptomi/aptomi/pkg/runtime"
	"github.com/Aptomi/aptomi/pkg/util"
	english "github.com/go-playground/locales/en"
	"github.com/go-playground/universal-translator"
	"gopkg.in/go-playground/validator.v9"
	"gopkg.in/go-playground/validator.v9/translations/en"
)
var (
	identifierRegex = "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$"
	clusterTypes    = []string{"kubernetes"}
	codeTypes       = []string{"helm", "raw"}
	labelOpsKeys    = []string{"set", "remove"}
	allowReject     = []string{"allow", "reject"}
)
type contextKey string
var policyKey = contextKey("policy")
var errorsKey = contextKey("errors")
func (c contextKey) String() string {
	return "lang context key " + string(c)
}
type policyValidationError struct {
	errList []string
}
func (err policyValidationError) Error() string {
	return strings.Join(err.errList, "\n")
}
func (err *policyValidationError) addError(errStr string) {
	err.errList = append(err.errList, errStr)
}
type PolicyValidator struct {
	val    *validator.Validate
	ctx    context.Context
	policy *Policy
	trans  ut.Translator
}
func NewPolicyValidator(policy *Policy) *PolicyValidator {
	result := validator.New()
	result.RegisterValidationCtx("identifier", validateIdentifier)                
	result.RegisterValidationCtx("clustertype", validateClusterType)              
	result.RegisterValidationCtx("codetype", validateCodeType)                    
	result.RegisterValidationCtx("expression", validateExpression)                
	result.RegisterValidationCtx("template", validateTemplate)                    
	result.RegisterValidationCtx("templateNestedMap", validateTemplateNestedMap)  
	result.RegisterValidationCtx("labels", validateLabels)                        
	result.RegisterValidationCtx("labelOperations", validateLabelOperations)      
	result.RegisterValidationCtx("allowReject", validateAllowRejectAction)        
	result.RegisterValidationCtx("addRoleNS", validateACLRoleActionMap)           
	result.RegisterStructValidation(validateRule, Rule{})
	result.RegisterStructValidation(validateACLRule, ACLRule{})
	result.RegisterStructValidation(validateCluster, Cluster{})
	result.RegisterStructValidationCtx(validateBundle, Bundle{})
	result.RegisterStructValidationCtx(validateClaim, Claim{})
	result.RegisterStructValidationCtx(validateService, Service{})
	ctx := context.WithValue(context.Background(), policyKey, policy)
	ctx = context.WithValue(ctx, errorsKey, &policyValidationError{})
	eng := english.New()
	uni := ut.New(eng, eng)
	trans, _ := uni.GetTranslator("en")
	err := en.RegisterDefaultTranslations(result, trans)
	if err != nil {
		panic(err)
	}
	translations := []struct {
		tag         string
		translation string
	}{
		{
			tag:         "clustertype",
			translation: fmt.Sprintf("'{0}' is not valid, must be in %s", clusterTypes),
		},
		{
			tag:         "codetype",
			translation: fmt.Sprintf("'{0}' is not valid, must be in %s", codeTypes),
		},
		{
			tag:         "allowReject",
			translation: fmt.Sprintf("'{0}' is not valid, must be in %s", allowReject),
		},
		{
			tag:         "systemNS",
			translation: fmt.Sprintf("'{0}' is not valid, must always be '%s'", runtime.SystemNS),
		},
		{
			tag:         "identifier",
			translation: fmt.Sprintf("'{0}' is not a valid identifier"),
		},
		{
			tag:         "expression",
			translation: fmt.Sprintf("'{0}' is not a valid expression"),
		},
		{
			tag:         "template",
			translation: fmt.Sprintf("'{0}' is not a valid text template"),
		},
		{
			tag:         "templateNestedMap",
			translation: fmt.Sprintf("is not a valid text template map (one or more nested text templates is invalid)"),
		},
		{
			tag:         "labels",
			translation: fmt.Sprintf("is not a valid label map (one or more nested label names is invalid)"),
		},
		{
			tag:         "labelOperations",
			translation: fmt.Sprintf("is not a valid label operations map (keys must be in %s, all label names must be valid)", labelOpsKeys),
		},
		{
			tag:         "addRoleNS",
			translation: fmt.Sprintf("is not a valid role assignment map (key must be in %s, namespace list must be comma-separated identifiers/wildcards)", util.GetSortedStringKeys(ACLRolesMap)),
		},
		{
			tag:         "exists",
			translation: fmt.Sprintf("object '{0}' does not exist"),
		},
		{
			tag:         "codeServiceSingle",
			translation: fmt.Sprintf("component '{0}' should either be code or service"),
		},
		{
			tag:         "unique",
			translation: fmt.Sprintf("'{0}' is not unique"),
		},
		{
			tag:         "topologicalSort",
			translation: fmt.Sprintf("{0}"),
		},
		{
			tag:         "ruleActions",
			translation: fmt.Sprintf("is a required field (at least one action must be specified)"),
		},
		{
			tag:         "aclRuleActions",
			translation: fmt.Sprintf("is a required field (role assignment map must be specified)"),
		},
	}
	for _, t := range translations {
		err = result.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation), translateFunc)
		if err != nil {
			panic(err)
		}
	}
	return &PolicyValidator{
		val:    result,
		ctx:    ctx,
		policy: policy,
		trans:  trans,
	}
}
func registrationFunc(tag string, translation string) validator.RegisterTranslationsFunc {
	return func(ut ut.Translator) (err error) {
		if err = ut.Add(tag, translation, true); err != nil {
			return
		}
		return
	}
}
func translateFunc(ut ut.Translator, fe validator.FieldError) string {
	t, err := ut.T(fe.Tag(), reflect.ValueOf(fe.Value()).String(), fe.Param())
	if err != nil {
		return fe.(error).Error()
	}
	return t
}
func (v *PolicyValidator) Validate() error {
	err := v.val.StructCtx(v.ctx, v.policy)
	if err == nil {
		return nil
	}
	result := policyValidationError{}
	vErrors := err.(validator.ValidationErrors)  
	for _, vErr := range vErrors {
		errStr := fmt.Sprintf("%s: %s", vErr.Namespace(), vErr.Translate(v.trans))
		result.addError(errStr)
	}
	for _, errStr := range v.ctx.Value(errorsKey).(*policyValidationError).errList {  
		result.addError(errStr)
	}
	return result
}
func attachErrorToContext(ctx context.Context, _ validator.FieldLevel, errMsg string) {
	pve := ctx.Value(errorsKey).(*policyValidationError)  
	pve.errList = append(pve.errList, errMsg)
}
func validateInStringArray(_ context.Context, expectedValues []string, fl validator.FieldLevel) bool {
	return util.ContainsString(expectedValues, fl.Field().String())
}
func validateAllowRejectAction(ctx context.Context, fl validator.FieldLevel) bool {
	return validateInStringArray(ctx, allowReject, fl)
}
func validateClusterType(ctx context.Context, fl validator.FieldLevel) bool {
	return validateInStringArray(ctx, clusterTypes, fl)
}
func validateCodeType(ctx context.Context, fl validator.FieldLevel) bool {
	return validateInStringArray(ctx, codeTypes, fl)
}
func validateIdentifier(ctx context.Context, fl validator.FieldLevel) bool {
	return isIdentifier(fl.Field().String())
}
func validateExpression(ctx context.Context, fl validator.FieldLevel) bool {
	value := fl.Field().String()
	_, err := expression.NewExpression(value)
	if err != nil {
		attachErrorToContext(ctx, fl, err.Error())
	}
	return err == nil
}
func validateTemplate(ctx context.Context, fl validator.FieldLevel) bool {
	_, err := template.NewTemplate(fl.Field().String())
	if err != nil {
		attachErrorToContext(ctx, fl, err.Error())
	}
	return err == nil
}
func validateTemplateNestedMap(ctx context.Context, fl validator.FieldLevel) bool {
	pMap := fl.Field().Interface().(util.NestedParameterMap)  
	_, err := util.ProcessParameterTree(pMap, nil, nil, util.ModeCompile)
	if err != nil {
		attachErrorToContext(ctx, fl, err.Error())
	}
	return err == nil
}
func validateLabelOperations(ctx context.Context, fl validator.FieldLevel) bool {
	ops := fl.Field().Interface().(LabelOperations)  
	for opType, operations := range ops {
		if !util.ContainsString(labelOpsKeys, opType) {
			return false
		}
		for name := range operations {
			if !isIdentifier(name) {
				return false
			}
		}
	}
	return true
}
func validateACLRoleActionMap(ctx context.Context, fl validator.FieldLevel) bool {
	addRoleMap := fl.Field().Interface().(map[string]string)  
	for roleID, namespaceList := range addRoleMap {
		role := ACLRolesMap[roleID]
		if role == nil {
			return false
		}
		namespaces := strings.Split(namespaceList, ",")
		for _, namespace := range namespaces {
			if namespace != namespaceAll && !isIdentifier(strings.TrimSpace(namespace)) {
				return false
			}
		}
	}
	return true
}
func validateLabels(ctx context.Context, fl validator.FieldLevel) bool {
	names := fl.Field().MapKeys()
	for _, name := range names {
		if !isIdentifier(name.String()) {
			return false
		}
	}
	return true
}
func validateBundle(ctx context.Context, sl validator.StructLevel) {
	bundle := sl.Current().Addr().Interface().(*Bundle)  
	policy := ctx.Value(policyKey).(*Policy)  
	for _, component := range bundle.Components {
		cnt := 0
		if component.Code != nil {
			cnt++
		}
		if len(component.Service) > 0 {
			cnt++
		}
		if cnt != 1 {
			sl.ReportError(component.Name, fmt.Sprintf("Component[%s]", component.Name), "", "codeServiceSingle", "")
			return
		}
		if len(component.Service) > 0 {
			obj, err := policy.GetObject(TypeService.Kind, component.Service, bundle.Namespace)
			if obj == nil || err != nil {
				sl.ReportError(component.Service, fmt.Sprintf("Component[%s].Service[%s/%s]", component.Name, bundle.Namespace, component.Service), "", "exists", "")
				return
			}
		}
	}
	componentNames := make(map[string]bool)
	for _, component := range bundle.Components {
		if _, exists := componentNames[component.Name]; exists {
			sl.ReportError(component.Name, fmt.Sprintf("Component[%s].Name", component.Name), "", "unique", "")
			return
		}
		componentNames[component.Name] = true
	}
	_, err := bundle.GetComponentsSortedTopologically()
	if err != nil {
		sl.ReportError(err.Error(), "Components", "", "topologicalSort", "")
	}
	for _, component := range bundle.Components {
		for _, componentName := range component.Dependencies {
			if _, exists := componentNames[componentName]; !exists {
				sl.ReportError(componentName, fmt.Sprintf("Component[%s].Dependencies[%s]", component.Name, componentName), "", "exists", "")
				return
			}
		}
	}
}
func validateClaim(ctx context.Context, sl validator.StructLevel) {
	claim := sl.Current().Addr().Interface().(*Claim)  
	policy := ctx.Value(policyKey).(*Policy)           
	obj, err := policy.GetObject(TypeService.Kind, claim.Service, claim.Namespace)
	if obj == nil || err != nil {
		sl.ReportError(claim.Service, fmt.Sprintf("Service[%s/%s]", claim.Namespace, claim.Service), "", "exists", "")
		return
	}
}
func validateService(ctx context.Context, sl validator.StructLevel) {
	service := sl.Current().Addr().Interface().(*Service)  
	policy := ctx.Value(policyKey).(*Policy)               
	for _, serviceCtx := range service.Contexts {
		bundleName := ""
		if serviceCtx.Allocation != nil {
			bundleName = serviceCtx.Allocation.Bundle
		}
		obj, err := policy.GetObject(TypeBundle.Kind, bundleName, service.Namespace)
		if obj == nil || err != nil {
			sl.ReportError(bundleName, fmt.Sprintf("Contexts[%s].Bundle[%s/%s]", serviceCtx.Name, service.Namespace, bundleName), "", "exists", "")
			return
		}
	}
}
func validateRule(sl validator.StructLevel) {
	rule := sl.Current().Addr().Interface().(*Rule)  
	hasActions := false
	hasActions = hasActions || (rule.Actions != nil && len(rule.Actions.ChangeLabels) > 0)
	hasActions = hasActions || (rule.Actions != nil && len(rule.Actions.Claim) > 0)
	hasActions = hasActions || (rule.Actions != nil && len(rule.Actions.Ingress) > 0)
	if !hasActions {
		sl.ReportError(rule.Actions, "Actions", "", "ruleActions", "")
		return
	}
}
func validateACLRule(sl validator.StructLevel) {
	rule := sl.Current().Addr().Interface().(*ACLRule)  
	hasActions := false
	hasActions = hasActions || (rule.Actions != nil && len(rule.Actions.AddRole) > 0)
	if !hasActions {
		sl.ReportError(rule.Actions, "Actions.AddRole", "", "aclRuleActions", "")
		return
	}
}