func (resolver *PolicyResolver) resolveNode(node *resolutionNode) (resolveErr error) {  
	recursiveError := false
	defer func() {
		if resolveErr != nil {
			if !recursiveError {
				node.eventLog.NewEntry().Error(printCauseDetailsOnDebug(resolveErr, node.eventLog))
			}
			node.logCannotResolveInstance()
		}
	}()
	var err error
	node.objectResolved(node.claim)
	node.logStartResolvingClaim()
	err = node.checkUserExists()
	if err != nil {
		return err
	}
	node.service, err = node.getService(resolver.policy)
	if err != nil {
		return err
	}
	node.namespace = node.service.Namespace
	node.objectResolved(node.service)
	node.transformLabels(node.labels, node.service.ChangeLabels)
	node.context, err = node.getMatchedContext()
	if err != nil {
		return err
	}
	node.bundle, err = node.getMatchedBundle(resolver.policy)
	if err != nil {
		return err
	}
	node.objectResolved(node.bundle)
	node.transformLabels(node.labels, node.context.ChangeLabels)
	node.allocationKeysResolved, err = node.resolveAllocationKeys()
	if err != nil {
		return err
	}
	ruleResult, err := node.processRules()
	if err != nil {
		return err
	}
	node.bundleKey, err = node.createComponentKey(nil)
	if err != nil {
		return err
	}
	cycle := util.ContainsString(node.path, node.bundleKey.GetKey())
	node.path = append(node.path, node.bundleKey.GetKey())
	if cycle {
		return node.errorBundleCycleDetected()
	}
	node.resolution.RecordLabels(node.bundleKey, node.labels)
	node.resolution.StoreEdge(node.arrivalKey, node.bundleKey)
	componentsOrdered, err := node.bundle.GetComponentsSortedTopologically()
	if err != nil {
		return err
	}
	for _, node.component = range componentsOrdered {
		componentMatch, componentMatchErr := node.componentMatches(node.component)
		if componentMatchErr != nil {
			return err
		}
		if !componentMatch {
			continue
		}
		node.componentKey, err = node.createComponentKey(node.component)
		if err != nil {
			return err
		}
		node.resolution.StoreEdge(node.bundleKey, node.componentKey)
		node.resolution.RecordLabels(node.componentKey, node.labels)
		node.discoveryTreeNode[node.component.Name] = util.NestedParameterMap{}
		err := node.calculateAndStoreDiscoveryParams()
		if err != nil {
			return err
		}
		node.logResolvingClaimOnComponent()
		if node.component.Code != nil {
			err := node.calculateAndStoreCodeParams()
			if err != nil {
				return err
			}
		} else if node.component.Service != "" {
			nodeNext := node.createChildNode()
			err := resolver.resolveNode(nodeNext)
			node.eventLogsCombined = append(node.eventLogsCombined, nodeNext.eventLogsCombined...)
			if err != nil {
				recursiveError = true
				return err
			}
		}
		node.logInstanceSuccessfullyResolved(node.componentKey)
		node.resolution.RecordResolved(node.componentKey, node.claim, node.depth, ruleResult)
	}
	node.logInstanceSuccessfullyResolved(node.bundleKey)
	node.resolution.RecordResolved(node.bundleKey, node.claim, node.depth, ruleResult)
	return nil
}
Evaluate evaluates and resolves a single claim, as well as calculates component allocations.
Returns error only if there is an issue with the given claim and it cannot be resolved
package resolve
import (
	"fmt"
	sysruntime "runtime"
	"runtime/debug"
	"sync"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/external"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/lang/expression"
	"github.com/Aptomi/aptomi/pkg/lang/template"
	"github.com/Aptomi/aptomi/pkg/util"
)
var MaxConcurrentGoRoutines = sysruntime.NumCPU()
type PolicyResolver struct {
	policy *lang.Policy
	externalData *external.Data
	expressionCache *expression.Cache
	templateCache *template.Cache
	combineMutex sync.Mutex
	resolution *PolicyResolution
	eventLog *event.Log
}
func NewPolicyResolver(policy *lang.Policy, externalData *external.Data, eventLog *event.Log) *PolicyResolver {
	policyValidationErr := policy.Validate()
	if policyValidationErr != nil {
		panic(fmt.Sprintf("can't create resolver because policy is invalid: %s", policyValidationErr))
	}
	return &PolicyResolver{
		policy:          policy,
		externalData:    externalData,
		expressionCache: expression.NewCache(),
		templateCache:   template.NewCache(),
		resolution:      NewPolicyResolution(),
		eventLog:        eventLog,
	}
}
func (resolver *PolicyResolver) ResolveAllClaims() *PolicyResolution {
	var semaphore = make(chan int, MaxConcurrentGoRoutines)
	var wg sync.WaitGroup
	claims := resolver.policy.GetObjectsByKind(lang.TypeClaim.Kind)
	for _, claim := range claims {
		wg.Add(1)
		semaphore <- 1
		go func(c *lang.Claim) {
			defer wg.Done()
			node, resolveErr := resolver.resolveClaim(c)
			resolver.combineData(node, resolveErr)
			<-semaphore
		}(claim.(*lang.Claim))
	}
	wg.Wait()
	for _, instance := range resolver.resolution.ComponentInstanceMap {
		if instance.Metadata.Key.IsComponent() {
			resolver.logComponentParams(instance)
		}
	}
	return resolver.resolution
}
func (resolver *PolicyResolver) resolveClaim(claim *lang.Claim) (node *resolutionNode, resolveErr error) {
	defer func() {
		if err := recover(); err != nil {
			resolveErr = fmt.Errorf("panic: %s\n%s", err, string(debug.Stack()))
			node.eventLog.NewEntry().Error(resolveErr)
		}
	}()
	node = resolver.newResolutionNode()
	resolver.initResolutionNode(node, claim)
	resolveErr = resolver.resolveNode(node)
	return node, resolveErr
}
func (resolver *PolicyResolver) combineData(node *resolutionNode, resolutionErr error) {
	resolver.combineMutex.Lock()
	defer func() {
		if node != nil {
			for _, eventLog := range node.eventLogsCombined {
				resolver.eventLog.Append(eventLog)
			}
		}
		resolver.combineMutex.Unlock()
	}()
	if resolutionErr == nil {
		resolver.resolution.AppendData(node.resolution)
	}
}