func (tg *TranslateGroup) makeNextRule(translator *Translator) error {
	ingress := tg.kubePolicy.Spec.Ingress[tg.ingressIndex]
	for _, toPort := range ingress.Ports {
		proto := strings.ToLower(string(*toPort.Protocol))
		ports := []uint{uint(toPort.Port.IntValue())}
		rule := common.Rule{Protocol: proto, Ports: ports}
		tg.romanaPolicy.Ingress[tg.ingressIndex].Rules = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Rules, rule)
	}
	return nil
}
makeNextRule analizes current ingress rule and adds a new Rule to romanaPolicy.Rules.
package kubernetes
import (
	"fmt"
	"net/http"
	"os"
	"strings"
	"sync"
	"github.com/romana/core/common"
	"github.com/romana/core/tenant"
	log "github.com/romana/rlog"
	"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
)
type PolicyTranslator interface {
	Init(*common.RestClient, string)
	Kube2Romana(v1beta1.NetworkPolicy) (common.Policy, error)
	Kube2RomanaBulk([]v1beta1.NetworkPolicy) ([]common.Policy, []v1beta1.NetworkPolicy, error)
}
type Translator struct {
	listener         *kubeListener
	restClient       *common.RestClient
	tenantsCache     []TenantCacheEntry
	cacheMu          *sync.Mutex
	segmentLabelName string
	tenantLabelName  string
}
func (t *Translator) Init(client *common.RestClient, segmentLabelName, tenantLabelName string) {
	t.cacheMu = &sync.Mutex{}
	t.restClient = client
	err := t.updateCache()
	if err == nil {
		log.Infof("Translator cache updated - have %d tenant entries", len(t.tenantsCache))
	} else {
		log.Errorf("Translator cache update failed, %s", err)
	}
	t.segmentLabelName = segmentLabelName
	t.tenantLabelName = tenantLabelName
}
func (t Translator) GetClient() *common.RestClient {
	return t.restClient
}
func (t Translator) Kube2Romana(kubePolicy v1beta1.NetworkPolicy) (common.Policy, error) {
	return common.Policy{}, nil
}
func (t Translator) Kube2RomanaBulk(kubePolicies []v1beta1.NetworkPolicy) ([]common.Policy, []v1beta1.NetworkPolicy, error) {
	log.Info("In Kube2RomanaBulk")
	var returnRomanaPolicy []common.Policy
	var returnKubePolicy []v1beta1.NetworkPolicy
	err := t.updateCache()
	if err != nil {
		return returnRomanaPolicy, returnKubePolicy, TranslatorError{ErrorCacheUpdate, err}
	}
	for kubePolicyNumber, _ := range kubePolicies {
		romanaPolicy, err := t.translateNetworkPolicy(&kubePolicies[kubePolicyNumber])
		if err != nil {
			log.Errorf("Error during policy translation %s", err)
			returnKubePolicy = append(returnKubePolicy, kubePolicies[kubePolicyNumber])
		} else {
			returnRomanaPolicy = append(returnRomanaPolicy, romanaPolicy)
		}
	}
	return returnRomanaPolicy, returnKubePolicy, nil
}
func (l *Translator) translateNetworkPolicy(kubePolicy *v1beta1.NetworkPolicy) (common.Policy, error) {
	policyName := fmt.Sprintf("kube.%s.%s", kubePolicy.ObjectMeta.Namespace, kubePolicy.ObjectMeta.Name)
	romanaPolicy := &common.Policy{Direction: common.PolicyDirectionIngress, Name: policyName, ExternalID: string(kubePolicy.ObjectMeta.UID)}
	translateGroup := &TranslateGroup{kubePolicy, romanaPolicy, TranslateGroupStartIndex}
	err := translateGroup.translateTarget(l)
	if err != nil {
		return *translateGroup.romanaPolicy, TranslatorError{ErrorTranslatingPolicyTarget, err}
	}
	for {
		err := translateGroup.translateNextIngress(l)
		if _, ok := err.(NoMoreIngressEntities); ok {
			break
		}
		if err != nil {
			return *translateGroup.romanaPolicy, TranslatorError{ErrorTranslatingPolicyIngress, err}
		}
	}
	return *translateGroup.romanaPolicy, nil
}
func (l *Translator) resolveTenantByName(tenantName string) (*tenant.Tenant, error) {
	t := &tenant.Tenant{Name: tenantName}
	err := l.restClient.Find(t, common.FindLast)
	if err != nil {
		return t, err
	}
	return t, nil
}
func (l *Translator) getOrAddSegment(namespace string, kubeSegmentName string) (*tenant.Segment, error) {
	tenantCacheEntry := l.checkTenantInCache(namespace)
	if tenantCacheEntry == nil {
		return nil, TranslatorError{ErrorTenantNotInCache, fmt.Errorf("Tenant not found in cache while resolving segment")}
	}
	segment := l.checkSegmentInCache(tenantCacheEntry, kubeSegmentName)
	if segment != nil {
		return segment, nil
	}
	defer func() {
		err := l.updateCache()
		if err != nil {
			log.Error("Failed to update cache in translator during getOrAddSegment().")
		}
	}()
	ten := tenantCacheEntry.Tenant
	seg := &tenant.Segment{}
	seg.Name = kubeSegmentName
	seg.TenantID = ten.ID
	err := l.restClient.Find(seg, common.FindExactlyOne)
	if err == nil {
		return seg, nil
	}
	switch err := err.(type) {
	case common.HttpError:
		if err.StatusCode == http.StatusNotFound {
			segreq := tenant.Segment{Name: kubeSegmentName, TenantID: ten.ID}
			segURL, err2 := l.restClient.GetServiceUrl("tenant")
			if err2 != nil {
				return nil, err2
			}
			segURL = fmt.Sprintf("%s/tenants/%d/segments", segURL, ten.ID)
			err2 = l.restClient.Post(segURL, segreq, seg)
			if err2 == nil {
				return seg, nil
			}
			switch err2 := err2.(type) {
			case common.HttpError:
				if err2.StatusCode == http.StatusConflict {
					switch details := err2.Details.(type) {
					case tenant.Segment:
						return &details, nil
					default:
						return nil, err
					}
				}
				return nil, err2
			default:
				return nil, err2
			}
		}
		return nil, err
	default:
		return nil, err
	}
}
type TenantCacheEntry struct {
	Tenant   tenant.Tenant
	Segments []tenant.Segment
}
func (t Translator) checkTenantInCache(tenantName string) *TenantCacheEntry {
	t.cacheMu.Lock()
	defer func() {
		t.cacheMu.Unlock()
	}()
	for tn, currentTenant := range t.tenantsCache {
		if currentTenant.Tenant.Name == tenantName {
			return &t.tenantsCache[tn]
		}
	}
	return nil
}
func (t Translator) checkSegmentInCache(cacheEntry *TenantCacheEntry, segmentId string) *tenant.Segment {
	t.cacheMu.Lock()
	defer func() {
		t.cacheMu.Unlock()
	}()
	for segn, currentSegment := range cacheEntry.Segments {
		if currentSegment.Name == segmentId {
			return &cacheEntry.Segments[segn]
		}
	}
	return nil
}
func (t *Translator) updateCache() error {
	log.Info("In updateCache")
	tenantURL, err := t.restClient.GetServiceUrl("tenant")
	if err != nil {
		return TranslatorError{ErrorCacheUpdate, err}
	}
	tenants := []tenant.Tenant{}
	err = t.restClient.Get(tenantURL+"/tenants", &tenants)
	if err != nil {
		return TranslatorError{ErrorCacheUpdate, err}
	}
	if t.restClient == nil {
		log.Critical("REST client is nil")
		os.Exit(255)
	}
	t.cacheMu.Lock()
	defer func() {
		log.Infof("Exiting updateCache with %d tenants", len(t.tenantsCache))
		t.cacheMu.Unlock()
	}()
	t.tenantsCache = nil
	for _, ten := range tenants {
		segments := []tenant.Segment{}
		fullUrl := fmt.Sprintf("%s/tenants/%d/segments", tenantURL, ten.ID)
		err = t.restClient.Get(fullUrl, &segments)
		if err != nil && !checkHttp404(err) {
			return TranslatorError{ErrorCacheUpdate, err}
		}
		t.tenantsCache = append(t.tenantsCache, TenantCacheEntry{ten, segments})
	}
	return nil
}
func checkHttp404(err error) (ret bool) {
	switch e := err.(type) {
	case common.HttpError:
		if e.StatusCode == 404 {
			ret = true
		}
	}
	return
}
type TranslatorError struct {
	Code    TranslatorErrorType
	Details error
}
func (t TranslatorError) Error() string {
	return fmt.Sprintf("Translator error code %d, %s", t.Code, t.Details)
}
type TranslatorErrorType int
const (
	ErrorCacheUpdate TranslatorErrorType = iota
	ErrorTenantNotInCache
	ErrorTranslatingPolicyTarget
	ErrorTranslatingPolicyIngress
)
type TranslateGroup struct {
	kubePolicy   *v1beta1.NetworkPolicy
	romanaPolicy *common.Policy
	ingressIndex int
}
const TranslateGroupStartIndex = 0
func (tg *TranslateGroup) translateTarget(translator *Translator) error {
	tenantCacheEntry := translator.checkTenantInCache(tg.kubePolicy.ObjectMeta.Namespace)
	if tenantCacheEntry == nil {
		log.Errorf("Tenant not found when translating policy %v", tg.romanaPolicy)
		return TranslatorError{ErrorTenantNotInCache, nil}
	}
	if len(tg.kubePolicy.Spec.PodSelector.MatchLabels) == 0 {
		tg.romanaPolicy.AppliedTo = []common.Endpoint{
			common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID},
		}
		log.Tracef(2, "Segment was not specified in policy %v, assuming target is a namespace", tg.kubePolicy)
		return nil
	}
	kubeSegmentID, ok := tg.kubePolicy.Spec.PodSelector.MatchLabels[translator.segmentLabelName]
	if !ok || kubeSegmentID == "" {
		log.Errorf("Expected segment to be specified in podSelector part as %s", translator.segmentLabelName)
		return common.NewError("Expected segment to be specified in podSelector part as '%s'", translator.segmentLabelName)
	}
	segment, err := translator.getOrAddSegment(tg.kubePolicy.ObjectMeta.Namespace, kubeSegmentID)
	if err != nil {
		log.Errorf("Error in translate while calling l.getOrAddSegment with %s and %s - error %s", tg.kubePolicy.ObjectMeta.Namespace, kubeSegmentID, err)
		return err
	}
	tg.romanaPolicy.AppliedTo = []common.Endpoint{
		common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID, SegmentID: segment.ID},
	}
	return nil
}
func (tg *TranslateGroup) makeNextIngressPeer(translator *Translator) error {
	ingress := tg.kubePolicy.Spec.Ingress[tg.ingressIndex]
	for _, fromEntry := range ingress.From {
		tenantCacheEntry := &TenantCacheEntry{}
		if fromEntry.PodSelector == nil && fromEntry.NamespaceSelector == nil {
			log.Errorf("Either PodSElector or NamespacesSelector must be specified")
			return common.NewError("Either PodSElector or NamespacesSelector must be specified")
		} else if fromEntry.PodSelector != nil && fromEntry.NamespaceSelector != nil {
			log.Errorf("Exactly one of PodSElector or NamespacesSelector must be specified")
			return common.NewError("Exactly on of PodSElector or NamespacesSelector must be specified")
		}
		if fromEntry.NamespaceSelector != nil {
			tenantName, ok := fromEntry.NamespaceSelector.MatchLabels[translator.tenantLabelName]
			if !ok || tenantName == "" {
				log.Errorf("Expected tenant name to be specified in NamespaceSelector field with a key %s", translator.tenantLabelName)
				return common.NewError("Expected tenant name to be specified in NamespaceSelector field with a key %s", translator.tenantLabelName)
			}
			tenantCacheEntry = translator.checkTenantInCache(tenantName)
			if tenantCacheEntry == nil {
				log.Errorf("Tenant not not found when translating policy %v", tg.romanaPolicy)
				return TranslatorError{ErrorTenantNotInCache, nil}
			}
			tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
				common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID})
		}
		if fromEntry.PodSelector != nil {
			tenantCacheEntry = translator.checkTenantInCache(tg.kubePolicy.ObjectMeta.Namespace)
			if tenantCacheEntry == nil {
				log.Errorf("Tenant not not found when translating policy %v", tg.romanaPolicy)
				return TranslatorError{ErrorTenantNotInCache, nil}
			}
			if len(fromEntry.PodSelector.MatchLabels) == 0 {
				tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
					common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID})
				log.Tracef(2, "No segment specified when translating ingress rule %v", tg.kubePolicy.Spec.Ingress[tg.ingressIndex])
				return nil
			}
			kubeSegmentID, ok := fromEntry.PodSelector.MatchLabels[translator.segmentLabelName]
			if !ok || kubeSegmentID == "" {
				log.Errorf("Expected segment to be specified in podSelector part as %s", translator.segmentLabelName)
				return common.NewError("Expected segment to be specified in podSelector part as '%s'", translator.segmentLabelName)
			}
			segment, err := translator.getOrAddSegment(tenantCacheEntry.Tenant.Name, kubeSegmentID)
			if err != nil {
				log.Errorf("Error in translate while calling l.getOrAddSegment with %s and %s - error %s", tenantCacheEntry.Tenant.Name, kubeSegmentID, err)
				return err
			}
			tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
				common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID, SegmentID: segment.ID})
		}
	}
	return nil
}