From 2b235d9f63e0410a10a747717a05af343bb22f62 Mon Sep 17 00:00:00 2001 From: Maksym Melnychok Date: Tue, 27 Apr 2021 06:59:41 -0700 Subject: [PATCH] wip meshregistrator --- cmd/meshregistrator/aws.go | 69 +++++++++++ cmd/meshregistrator/local.go | 70 +++++++++++ cmd/meshregistrator/main.go | 95 +++++++++++++++ cmd/meshregistrator/pods.go | 125 ++++++++++++++++++++ cmd/meshregistrator/service_registration.go | 59 +++++++++ cmd/meshregistrator/signal.go | 25 ++++ go.mod | 3 +- go.sum | 15 +++ 8 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 cmd/meshregistrator/aws.go create mode 100644 cmd/meshregistrator/local.go create mode 100644 cmd/meshregistrator/main.go create mode 100644 cmd/meshregistrator/pods.go create mode 100644 cmd/meshregistrator/service_registration.go create mode 100644 cmd/meshregistrator/signal.go diff --git a/cmd/meshregistrator/aws.go b/cmd/meshregistrator/aws.go new file mode 100644 index 0000000..870c29e --- /dev/null +++ b/cmd/meshregistrator/aws.go @@ -0,0 +1,69 @@ +package main + +import ( + "context" + "time" + + "k8s.io/klog/v2" +) + +// merge pods, local and aws, calculate diff from previous frame +// and write differences +func writeAWS(ctx context.Context, podsch, localch, awsch chan []ServiceRegistration) { + var pods, local, aws []ServiceRegistration + var podsDirty, localDirty, awsDirty bool + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + klog.Info("selecting") + select { + case <-ctx.Done(): + klog.Info("writeAWS stopped") + return + case pods = <-podsch: + klog.Info("pods updated") + podsDirty = true + case local = <-localch: + klog.Info("local updated") + localDirty = true + case aws = <-awsch: + klog.Info("aws updated") + awsDirty = true + case <-ticker.C: + if podsDirty { + klog.Infof("new pods=%+v\n", pods) + } + if localDirty { + klog.Infof("new local=%+v\n", local) + } + if awsDirty { + klog.Infof("new aws=%+v\n", aws) + } + if !podsDirty && !localDirty && !awsDirty { + klog.Info("nothing updated") + continue + } + + podsDirty = false + localDirty = false + awsDirty = false + } + } +} + +// find registrations in CloudMap that match current node name +func fetchAWS(ctx context.Context, aws chan []ServiceRegistration) { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + klog.Info("fetchAWS stopped") + return + case <-ticker.C: + continue + } + } +} diff --git a/cmd/meshregistrator/local.go b/cmd/meshregistrator/local.go new file mode 100644 index 0000000..01f0002 --- /dev/null +++ b/cmd/meshregistrator/local.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "k8s.io/klog/v2" +) + +// check host for services configured via other means and update registration list +func fetchLocal(ctx context.Context, out chan []ServiceRegistration, servicesDir string) { + var oldRegistrations, newRegistrations []ServiceRegistration + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + klog.Info("fetchLocal stopped") + return + case <-ticker.C: + newRegistrations = []ServiceRegistration{} + err := filepath.Walk(servicesDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error accessing %v: %v", path, err) + } + if info.IsDir() { + return nil + } + + fh, err := os.Open(path) + if err != nil { + // ignore broken symlinks + return nil + } + + serviceInfo := struct { + Namespaces []string `json:"namespaces"` + }{} + bytes, err := ioutil.ReadAll(fh) + if err != nil { + return fmt.Errorf("error reading %v: %v", path, err) + } + err = json.Unmarshal(bytes, &serviceInfo) + if err != nil { + return fmt.Errorf("error parsing %v: %v", path, err) + } + if serviceInfo.Namespaces == nil { + klog.Infof("service has no namespaces: %v", path) + return nil + } + klog.Infof("local service: %v %+v\n", info.Name(), serviceInfo.Namespaces) + return nil + }) + if err != nil { + klog.Error(err) + continue + } + if registrationsEqual(oldRegistrations, newRegistrations) { + continue + } + out <- newRegistrations + } + } +} diff --git a/cmd/meshregistrator/main.go b/cmd/meshregistrator/main.go new file mode 100644 index 0000000..c3055d6 --- /dev/null +++ b/cmd/meshregistrator/main.go @@ -0,0 +1,95 @@ +// meshregistrator has multiple goroutines: +// - fetchPods will take a snapshot of pods running in local kubelet and +// turn them into a map of registrations +// - fetchLocal will gather locally running backends according to +// configuration in ... +// - fetchAWS will download existing registrations in AWS cloudmap +// to find potential zombies for cleanup +// - writeAWS will merge those and execute relevant cloudmap +// register/deregister calls +package main + +import ( + "context" + "os" + "sync" + + origflag "flag" + + flag "github.com/spf13/pflag" + + "k8s.io/klog/v2" +) + +type MeshregistratorOptions struct { + SystemPaastaDir string + YelpSoaDir string + LocalServicesDir string + TrackLocal bool + TrackKubelet bool +} + +// Setup ... +func (o *MeshregistratorOptions) Setup() { + flag.StringVarP(&o.SystemPaastaDir, "systempaastadir", "", "/etc/paasta", "") + flag.StringVarP(&o.YelpSoaDir, "yelpsoadir", "", "/nail/etc/services", "") + flag.StringVarP(&o.LocalServicesDir, "localservicesdir", "", "/etc/nerve/puppet_services.d", "") + flag.BoolVarP(&o.TrackLocal, "tracklocal", "", true, "") + flag.BoolVarP(&o.TrackKubelet, "trackkubelet", "", true, "") +} + +func parseFlags(opts *MeshregistratorOptions) error { + opts.Setup() + flag.Parse() + return nil +} + +// A subprocess keeps track of ysoa-configs and some local configuration coming from puppet and other sources to understand Yelp’s service topology +func main() { + klogFlags := origflag.NewFlagSet("klog", origflag.ExitOnError) + klog.InitFlags(klogFlags) + debug, _ := os.LookupEnv("MESHREGISTRATOR_DEBUG") + v := klogFlags.Lookup("v") + if v != nil { + if debug != "" { + v.Value.Set("10") + } else { + v.Value.Set("0") + } + } + + var options MeshregistratorOptions + parseFlags(&options) + + klog.Infof("starting meshregistrator: %+v", options) + + // sysStore := configstore.NewStore(options.SystemPaastaDir, nil) + + var wg sync.WaitGroup + pods := make(chan []ServiceRegistration, 1) + local := make(chan []ServiceRegistration, 1) + aws := make(chan []ServiceRegistration, 1) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + if options.TrackKubelet { + wg.Add(1) + go func() { defer wg.Done(); fetchPods(ctx, pods); cancel() }() + } + + if options.TrackLocal { + wg.Add(1) + go func() { defer wg.Done(); fetchLocal(ctx, local, options.LocalServicesDir); cancel() }() + } + + wg.Add(1) + go func() { defer wg.Done(); fetchAWS(ctx, aws); cancel() }() + + wg.Add(1) + go func() { defer wg.Done(); writeAWS(ctx, pods, local, aws); cancel() }() + + go signalLoop(ctx, cancel) + wg.Wait() + + klog.Info("meshregistrator out") +} diff --git a/cmd/meshregistrator/pods.go b/cmd/meshregistrator/pods.go new file mode 100644 index 0000000..9ac4519 --- /dev/null +++ b/cmd/meshregistrator/pods.go @@ -0,0 +1,125 @@ +package main + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" + "time" + + corev1 "k8s.io/api/core/v1" + klog "k8s.io/klog/v2" +) + +const HacheckPodName = "hacheck" + +// fetch running pods from kubelet and update pods registration list +func fetchPods(ctx context.Context, out chan []ServiceRegistration) { + var oldRegistrations, newRegistrations []ServiceRegistration + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + klog.Info("fetchPods stopped") + return + case <-ticker.C: + startTime := time.Now().UnixNano() + resp, err := http.Get("http://127.0.0.1:10255/pods") + if err != nil { + klog.Errorf("fetching pods failed: %v", err) + continue + } + + if resp.StatusCode != http.StatusOK { + klog.Errorf("fetching pods bad response: %v", resp.StatusCode) + continue + } + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + klog.Errorf("reading body failed: %v", err) + continue + } + loadedTime := time.Now().UnixNano() + klog.Infof( + "read %v bytes in %vs", + len(bodyBytes), + float64(loadedTime-startTime)/float64(time.Second), + ) + + var podList corev1.PodList + err = json.Unmarshal(bodyBytes, &podList) + if err != nil { + klog.Errorf("unmarshaling body failed: %v", err) + continue + } + parsedTime := time.Now().UnixNano() + + klog.Infof( + "loaded %v pods in %vs", + len(podList.Items), + float64(parsedTime-loadedTime)/float64(time.Second), + ) + + newRegistrations = []ServiceRegistration{} + for _, pod := range podList.Items { + if pod.Status.Phase != corev1.PodRunning { + continue + } + podRegsJson, ok := pod.Annotations["smartstack_registrations"] + if !ok { + continue + } + + var podRegs []string + err := json.Unmarshal([]byte(podRegsJson), &podRegs) + if err != nil { + klog.Errorf( + "pod %v/%v smartstack_registrations failed to load: %v, raw json: %+v", + pod.Namespace, + pod.Name, + err, + podRegsJson, + ) + continue + } + + var port int32 + for _, cont := range pod.Spec.Containers { + // TODO: use instance name? + if cont.Name != HacheckPodName { + port = cont.Ports[0].ContainerPort + break + } + } + service := pod.Labels["paasta.yelp.com/service"] + instance := pod.Labels["paasta.yelp.com/instance"] + podIP := pod.Status.PodIP + + for _, reg := range podRegs { + newRegistrations = append(newRegistrations, ServiceRegistration{ + Service: service, + Instance: instance, + PodNode: pod.Spec.NodeName, + PodNs: pod.Namespace, + PodName: pod.Name, + PodIP: podIP, + Port: port, + Registration: reg, + }) + } + } + + if registrationsEqual(oldRegistrations, newRegistrations) { + klog.V(10).Info("pods registrations did not change") + continue + } + + klog.Infof("pods registrations updated: %+v", newRegistrations) + oldRegistrations = newRegistrations + out <- newRegistrations + } + } +} diff --git a/cmd/meshregistrator/service_registration.go b/cmd/meshregistrator/service_registration.go new file mode 100644 index 0000000..7889251 --- /dev/null +++ b/cmd/meshregistrator/service_registration.go @@ -0,0 +1,59 @@ +package main + +import ( + "hash/fnv" + "strconv" + "sync" +) + +type ServiceRegistrationsList struct { + sync.Mutex + IsDirty bool + Items []ServiceRegistration +} + +type ServiceRegistration struct { + Service string + Instance string + PodNs string + PodName string + PodNode string + PodIP string + Port int32 + Registration string +} + +func (s *ServiceRegistration) Hash() uint64 { + h := fnv.New64a() + h.Write([]byte(s.Service)) + h.Write([]byte(s.Instance)) + h.Write([]byte(s.PodNs)) + h.Write([]byte(s.PodName)) + h.Write([]byte(s.PodNode)) + h.Write([]byte([]byte(strconv.Itoa(int(s.Port))))) + h.Write([]byte(s.PodIP)) + h.Write([]byte(s.Registration)) + return h.Sum64() +} + +// compare registration slices ignoring order +func registrationsEqual(x, y []ServiceRegistration) bool { + if len(x) != len(y) { + return false + } + diff := make(map[uint64]int, len(x)) + for _, _x := range x { + diff[_x.Hash()]++ + } + for _, _y := range y { + h := _y.Hash() + if _, ok := diff[h]; !ok { + return false + } + diff[_y.Hash()] -= 1 + if diff[h] == 0 { + delete(diff, h) + } + } + return len(diff) == 0 +} diff --git a/cmd/meshregistrator/signal.go b/cmd/meshregistrator/signal.go new file mode 100644 index 0000000..dfb227f --- /dev/null +++ b/cmd/meshregistrator/signal.go @@ -0,0 +1,25 @@ +package main + +import ( + "context" + "os" + "os/signal" + + "k8s.io/klog/v2" +) + +func signalLoop(ctx context.Context, cancel context.CancelFunc) { + stopping := false + signalCh := make(chan os.Signal, 1) + signal.Notify(signalCh, os.Interrupt) + for s := range signalCh { + if stopping { + klog.Warningf("caught %v, still stopping...", s) + continue + } + + klog.Infof("caught %v, stopping...", s) + cancel() + stopping = true + } +} diff --git a/go.mod b/go.mod index e041b1d..ee562bc 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/pkg/errors v0.8.1 github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.3.0 // indirect - github.com/spf13/pflag v1.0.3 // indirect + github.com/spf13/pflag v1.0.3 github.com/stretchr/testify v1.4.0 github.com/subosito/gotenv v1.2.0 go.uber.org/zap v1.13.0 // indirect @@ -33,6 +33,7 @@ require ( k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/klog v1.0.0 + k8s.io/klog/v2 v2.8.0 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a // indirect k8s.io/kubernetes v1.14.0 k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 // indirect diff --git a/go.sum b/go.sum index 7268265..6a4a277 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,7 @@ github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5I github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -58,6 +59,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v0.1.1 h1:qXBXPDdNncunGs7XeEpsJt8wCjYBygluzfdLO0G5baE= github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= @@ -155,10 +158,12 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= @@ -175,9 +180,11 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a h1:TpvdAwDAt1K4ANVOfcihouRdvP+MgAfDWwBuct4l6ZY= @@ -208,9 +215,11 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= @@ -361,16 +370,19 @@ gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3m google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.20.0 h1:DlsSIrgEBuZAUFJcta2B5i/lzeHHbnfkNFAfFXLVFYQ= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= @@ -407,6 +419,8 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.1.0 h1:X3+Mru/L3jy4BI4vcAYkHvL6PyU+QBsuhEqwlI4mgkA= k8s.io/klog/v2 v2.1.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= @@ -420,6 +434,7 @@ sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHE sigs.k8s.io/controller-runtime v0.2.2 h1:JT/vJJhUjjL9NZNwnm8AXmqCBUXSCFKmTaNjwDi28N0= sigs.k8s.io/controller-runtime v0.2.2/go.mod h1:9dyohw3ZtoXQuV1e766PHUn+cmrRCIcBh6XIMFNMZ+I= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=