func (p *Pod) GetServiceHealth(n string, defaultVal string) string {
	healthStr := p.Pod.ObjectMeta.Annotations[ConsulServiceHealthOverride+n]
	if healthStr == "" {
		healthStr = p.Pod.ObjectMeta.Annotations[ConsulServiceHealth]
	}
	switch healthStr {
	case consulApi.HealthCritical, consulApi.HealthPassing, consulApi.HealthWarning:
		return healthStr
	case "":  
	default:
		logrus.Errorf("Unknown service health status '%v' ignored", healthStr)
	}
	return defaultVal
}
GetServiceHealth returns the service health specified in annotation, or defaultVal if not specified.
package daemon
import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"
	consulApi "github.com/hashicorp/consul/api"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)
const ReadinessGateType = "katalog-sync.wish.com/synced"  
var (
	ConsulServiceNames          = "katalog-sync.wish.com/service-names"      
	ConsulServicePort           = "katalog-sync.wish.com/service-port"       
	ConsulServicePortOverride   = "katalog-sync.wish.com/service-port-"      
	ConsulServiceTags           = "katalog-sync.wish.com/service-tags"       
	ConsulServiceTagsOverride   = "katalog-sync.wish.com/service-tags-"      
	ConsulServiceMeta           = "katalog-sync.wish.com/service-meta"       
	ConsulServiceMetaOverride   = "katalog-sync.wish.com/service-meta-"      
	ConsulServiceHealth         = "katalog-sync.wish.com/service-health"     
	ConsulServiceHealthOverride = "katalog-sync.wish.com/service-health-"    
	SidecarName                 = "katalog-sync.wish.com/sidecar"            
	SyncInterval                = "katalog-sync.wish.com/sync-interval"      
	ConsulServiceCheckTTL       = "katalog-sync.wish.com/service-check-ttl"  
	ContainerExclusion          = "katalog-sync.wish.com/container-exclude"  
)
func NewPod(pod corev1.Pod, dc *DaemonConfig) (*Pod, error) {
	var sidecarState *SidecarState
	if sidecarContainerName, ok := pod.ObjectMeta.Annotations[SidecarName]; ok {
		sidecarReady := false
		found := false
		for _, containerStatus := range pod.Status.ContainerStatuses {
			if containerStatus.Name == sidecarContainerName {
				sidecarReady = containerStatus.Ready
				found = true
				break
			}
		}
		if !found {
			return nil, fmt.Errorf("Unable to find sidecar container %s", sidecarContainerName)
		}
		sidecarState = &SidecarState{
			SidecarName: sidecarContainerName,
			Ready:       sidecarReady,
		}
	}
	var ourReadinessGate corev1.PodReadinessGate
	for _, gate := range pod.Spec.ReadinessGates {
		if gate.ConditionType == ReadinessGateType {
			ourReadinessGate = gate
		}
	}
	syncInterval := dc.DefaultSyncInterval
	if interval, ok := pod.ObjectMeta.Annotations[SyncInterval]; ok {
		duration, err := time.ParseDuration(interval)
		if err != nil {
			return nil, err
		}
		syncInterval = duration
	}
	checkTTL := dc.DefaultCheckTTL
	if interval, ok := pod.ObjectMeta.Annotations[ConsulServiceCheckTTL]; ok {
		duration, err := time.ParseDuration(interval)
		if err != nil {
			return nil, err
		}
		checkTTL = duration
	}
	if minCheckTTL := syncInterval + dc.SyncTTLBuffer; checkTTL < minCheckTTL {
		checkTTL = minCheckTTL
	}
	ctx, cancel := context.WithCancel(context.Background())
	return &Pod{
		Pod:                      pod,
		SidecarState:             sidecarState,
		SyncStatuses:             make(map[string]*SyncStatus),
		OutstandingReadinessGate: ourReadinessGate.ConditionType == ReadinessGateType,
		CheckTTL:     checkTTL,
		SyncInterval: syncInterval,
		Ctx:          ctx,
		Cancel:       cancel,
	}, nil
}
type Pod struct {
	corev1.Pod
	*SidecarState
	SyncStatuses
	OutstandingReadinessGate bool  
	InitialSyncDone          bool  
	CheckTTL     time.Duration
	SyncInterval time.Duration
	Ctx          context.Context
	Cancel       context.CancelFunc
	l sync.Mutex
	waitCh []chan struct{}
}
func (p *Pod) WaitChanges() chan struct{} {
	ch := make(chan struct{}, 5)
	p.l.Lock()
	p.waitCh = append(p.waitCh, ch)
	p.l.Unlock()
	return ch
}
func (p *Pod) HasChange(service *consulApi.AgentService) bool {
	if service.Port != p.GetPort(service.Service) {
		return true
	}
	if service.Address != p.Status.PodIP {
		return true
	}
	return false
}
func (p *Pod) GetServiceID(serviceName string) string {
	return strings.Join([]string{
		"katalog-sync",
		serviceName,
		p.Pod.ObjectMeta.Namespace,
		p.Pod.ObjectMeta.Name,
	}, "_")
}
func (p *Pod) UpdatePod(k8sPod corev1.Pod) {
	p.l.Lock()
	defer p.l.Unlock()
	p.Pod = k8sPod
	for i, ch := range p.waitCh {
		select {
		case ch <- struct{}{}:
			continue
		default:
			close(ch)
			copy(p.waitCh[i:], p.waitCh[i+1:])
			p.waitCh = p.waitCh[:len(p.waitCh)-1]
		}
	}
}
func (p *Pod) GetServiceNames() []string {
	return strings.Split(p.Pod.ObjectMeta.Annotations[ConsulServiceNames], ",")
}
func (p *Pod) HasServiceName(n string) bool {
	for _, name := range p.GetServiceNames() {
		if name == n {
			return true
		}
	}
	return false
}
func (p *Pod) GetTags(n string) []string {
	if tagStr, ok := p.Pod.ObjectMeta.Annotations[ConsulServiceTagsOverride+n]; ok {
		return strings.Split(tagStr, ",")
	}
	if tagStr, ok := p.Pod.ObjectMeta.Annotations[ConsulServiceTags]; ok {
		return strings.Split(tagStr, ",")
	}
	return nil
}
func (p *Pod) GetServiceMeta(n string) map[string]string {
	if metaStr, ok := p.Pod.ObjectMeta.Annotations[ConsulServiceMetaOverride+n]; ok {
		return ParseMap(metaStr)
	}
	if metaStr, ok := p.Pod.ObjectMeta.Annotations[ConsulServiceMeta]; ok {
		return ParseMap(metaStr)
	}
	return nil
}