diff --git a/.travis.yml b/.travis.yml index 9df872e..adaf008 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ language: go go: - - 1.12.x + - 1.13.x script: - go get -d ./... - - go vet ./... - - go test -v -race ./... \ No newline at end of file + - go vet ./... \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 77a00a4..caa1291 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,10 @@ -FROM golang:1.12 +FROM golang:1.13 WORKDIR /src/unload COPY . . RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" . FROM alpine:3.10 -RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf RUN apk --no-cache add ca-certificates COPY --from=0 /src/unload/unload /usr/local/bin EXPOSE 50051 -CMD ["unload"] \ No newline at end of file +ENTRYPOINT ["unload"] \ No newline at end of file diff --git a/api.go b/api.go deleted file mode 100644 index 15aba48..0000000 --- a/api.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "sync" -) - -var ( - gResolv = struct { - resolv map[string]*ring - sync.RWMutex - }{ - resolv: map[string]*ring{}, - } -) - -type ( - conf struct { - host string - target string - dst string - } -) - -func newConf(host string, target string) conf { - return conf{ - host: host, - target: target, - dst: host + target, - } -} - -func rmDst(c conf) { - gResolv.Lock() - defer gResolv.Unlock() - r, ok := gResolv.resolv[c.dst] - if !ok { - return - } - if r.len() == 1 && r.value == c.target { - delete(gResolv.resolv, c.dst) - return - } - for p := r.next(); p != r; p = p.nxt { - if p.value == c.target { - p.unlink(1) - break - } - } -} - -func addDst(c conf) { - gResolv.Lock() - defer gResolv.Unlock() - r, ok := gResolv.resolv[c.dst] - n := newRing(1) - n.value = c.target - if !ok { - gResolv.resolv[c.host] = n - } else { - var skip bool - // dedup - for p := r.next(); p != r; p = p.nxt { - if p.value == c.target { - skip = true - break - } - } - if !skip { - r.link(n) - } - } -} diff --git a/aws.go b/aws.go index 0a64653..70b5667 100644 --- a/aws.go +++ b/aws.go @@ -9,7 +9,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws/ec2metadata" "github.com/aws/aws-sdk-go-v2/aws/external" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "k8s.io/klog" + "github.com/google/logger" ) var ( @@ -18,7 +18,6 @@ var ( ) var ( - watchNlbList = make(map[string]struct{}) errSetupLbv2 = fmt.Errorf("lbv2 is not setup") ) @@ -26,14 +25,14 @@ func setupLbv2() error { setupLbv2Once.Do(func() { cfg, err := external.LoadDefaultAWSConfig() if err != nil { - klog.Errorln(err) + logger.Errorln(err) return } // work out aws current region meta := ec2metadata.New(cfg) cfg.Region, err = meta.Region() if err != nil { - klog.Errorln(err) + logger.Errorln(err) return } lbv2 = elasticloadbalancingv2.New(cfg) @@ -46,33 +45,33 @@ func setupLbv2() error { return nil } -func regPod(targetGroupArn string, ip string, port int64) { +func regPod(arn *string, ip string, port int64) { if err := setupLbv2(); err != nil { - klog.Warningln(err) + logger.Warningln(err) return } req := lbv2.RegisterTargetsRequest(&elasticloadbalancingv2.RegisterTargetsInput{ - TargetGroupArn: &targetGroupArn, + TargetGroupArn: arn, Targets: []elasticloadbalancingv2.TargetDescription{{ Id: &ip, Port: &port, }}, }) - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second) defer cancel() _, err := req.Send(ctx) if err != nil { - klog.Errorln(err) + logger.Errorln(err) } } -func deregPod(targetGroupArn string, ip string, port int64) { +func deregPod(arn *string, ip string, port int64) { if err := setupLbv2(); err != nil { - klog.Warningln(err) + logger.Warningln(err) return } req := lbv2.DeregisterTargetsRequest(&elasticloadbalancingv2.DeregisterTargetsInput{ - TargetGroupArn: &targetGroupArn, + TargetGroupArn: arn, Targets: []elasticloadbalancingv2.TargetDescription{{ Id: &ip, Port: &port, @@ -80,26 +79,25 @@ func deregPod(targetGroupArn string, ip string, port int64) { }) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - _, err := req.Send(ctx) - if err != nil { - klog.Errorln(err) + if _, err := req.Send(ctx); err != nil { + logger.Errorln(err) } } // this will remove out-of-synced unhealthy targets -func reconcile(targetGroupArn string) { +func reconcile(arn *string) { if err := setupLbv2(); err != nil { - klog.Warningln(err) + logger.Warningln(err) return } des := lbv2.DescribeTargetHealthRequest(&elasticloadbalancingv2.DescribeTargetHealthInput{ - TargetGroupArn: &targetGroupArn, + TargetGroupArn: arn, }) ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second) defer cancel() res, err := des.Send(ctx) if err != nil { - klog.Errorln(err) + logger.Errorln(err) return } var targets []elasticloadbalancingv2.TargetDescription @@ -110,24 +108,17 @@ func reconcile(targetGroupArn string) { } if len(targets) > 0 { dereg := lbv2.DeregisterTargetsRequest(&elasticloadbalancingv2.DeregisterTargetsInput{ - TargetGroupArn: &targetGroupArn, + TargetGroupArn: arn, Targets: targets, }) - _, err := dereg.Send(ctx) - if err != nil { - klog.Errorln(err) + if _, err := dereg.Send(ctx); err != nil { + logger.Errorln(err) } } } -func addWatchLbv2(targetGroupArn string) { - watchNlbList[targetGroupArn] = struct{}{} -} - func watchLbv2() { - for range time.Tick(20 * time.Second) { - for arn := range watchNlbList { - reconcile(arn) - } + for range time.Tick(3 * time.Minute) { + reconcile(targetGroupArn) } } diff --git a/ctl_k8s.go b/ctl_k8s.go index ff4d023..b539f1c 100644 --- a/ctl_k8s.go +++ b/ctl_k8s.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "k8s.io/klog" + "github.com/google/logger" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/fields" @@ -17,9 +17,8 @@ import ( ) const ( - unloadPodPort = 50051 - unloadIngressHostname = "unload.ingress.k8s.io/grpc-hostname" - unloadNlbTargetGroupArn = "unload.lb.k8s.io/aws-nlb-target-group-arn" + unloadPodPort = 50051 + unloadNlbIPTarget = "unload.lb.k8s.io/aws-nlb-ip-target" ) type controller struct { @@ -57,11 +56,11 @@ func (c *controller) processNextItem() bool { func (c *controller) updateLb(key string) error { obj, exists, err := c.indexer.GetByKey(key) if err != nil { - klog.Errorf("Fetching object with key %s from store failed with %v", key, err) + logger.Errorf("Fetching object with key %s from store failed with %v", key, err) return err } if !exists { - klog.Infof("Pod %s does not exist anymore\n", key) + logger.Infof("Pod %s does not exist anymore\n", key) return nil } // Note that you also have to check the uid if you have a local controlled resource, which @@ -74,13 +73,8 @@ func (c *controller) updateLb(key string) error { return nil } annotations := pod.GetAnnotations() - if host, ok := annotations[unloadIngressHostname]; ok { - // todo add pod port in - addDst(newConf(host, pod.Status.PodIP)) - } - if arn, ok := annotations[unloadNlbTargetGroupArn]; ok { - regPod(arn, pod.Status.PodIP, unloadPodPort) - addWatchLbv2(arn) + if _, ok := annotations[unloadNlbIPTarget]; ok { + regPod(targetGroupArn, pod.Status.PodIP, unloadPodPort) } return nil } @@ -97,7 +91,7 @@ func (c *controller) handleErr(err error, key interface{}) { // This controller retries 5 times if something goes wrong. After that, it stops trying. if c.queue.NumRequeues(key) < 5 { - klog.Infof("Error syncing pod %v: %v", key, err) + logger.Infof("Error syncing pod %v: %v", key, err) // Re-enqueue the key rate limited. Based on the rate limiter on the // queue and the re-enqueue history, the key will be processed later again. @@ -108,7 +102,7 @@ func (c *controller) handleErr(err error, key interface{}) { c.queue.Forget(key) // Report to an external entity that, even after several retries, we could not successfully process this key runtime.HandleError(err) - klog.Infof("Dropping pod %q out of the queue: %v", key, err) + logger.Infof("Dropping pod %q out of the queue: %v", key, err) } func (c *controller) run(threadiness int, stopCh chan struct{}) { @@ -116,7 +110,7 @@ func (c *controller) run(threadiness int, stopCh chan struct{}) { // Let the workers stop when we are done defer c.queue.ShutDown() - klog.Info("Starting Pod controller") + logger.Info("Starting Pod controller") go c.informer.Run(stopCh) @@ -131,7 +125,7 @@ func (c *controller) run(threadiness int, stopCh chan struct{}) { } <-stopCh - klog.Info("Stopping Pod controller") + logger.Info("Stopping Pod controller") } func (c *controller) runWorker() { @@ -142,11 +136,11 @@ func (c *controller) runWorker() { func startCtl() { config, err := rest.InClusterConfig() if err != nil { - klog.Fatal(err) + logger.Fatal(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { - klog.Fatal(err) + logger.Fatal(err) } // create the pod watcher podListWatcher := cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", v1.NamespaceDefault, fields.Everything()) @@ -179,11 +173,8 @@ func startCtl() { return } annotations := pod.GetAnnotations() - if host, ok := annotations[unloadIngressHostname]; ok { - rmDst(newConf(host, pod.Status.PodIP)) - } - if arn, ok := annotations[unloadNlbTargetGroupArn]; ok { - deregPod(arn, pod.Status.PodIP, unloadPodPort) + if _, ok := annotations[unloadNlbIPTarget]; ok { + deregPod(targetGroupArn, pod.Status.PodIP, unloadPodPort) } }, }, cache.Indexers{}) diff --git a/examples/fortune-teller.yml b/examples/fortune-teller.yml index 6682b95..38d30cc 100644 --- a/examples/fortune-teller.yml +++ b/examples/fortune-teller.yml @@ -13,8 +13,6 @@ spec: metadata: labels: app: fortune-teller-app - annotations: - unload.ingress.k8s.io/grpc-hostname: teller.local spec: containers: - name: fortune-teller-app diff --git a/go.mod b/go.mod index bdb937c..215c810 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,23 @@ module github.com/owlwalks/unload -go 1.12 +go 1.13 require ( - github.com/aws/aws-sdk-go-v2 v0.10.0 - golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 - k8s.io/api v0.0.0-20190620084959-7cf5895f2711 - k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719 - k8s.io/client-go v0.0.0-20190620085101-78d2af792bab - k8s.io/klog v0.3.1 + github.com/aws/aws-sdk-go-v2 v0.12.0 + github.com/gogo/protobuf v1.3.0 // indirect + github.com/google/logger v1.0.1 + github.com/googleapis/gnostic v0.3.1 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/json-iterator/go v1.1.7 // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect + golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/api v0.0.0-20190816222004-e3a6b8045b0b + k8s.io/apimachinery v0.0.0-20190816221834-a9f1d8a9c101 + k8s.io/client-go v11.0.1-0.20190918222721-c0e3722d5cf0+incompatible + k8s.io/klog v1.0.0 // indirect + k8s.io/utils v0.0.0-20190923111123-69764acb6e8e // indirect + sigs.k8s.io/yaml v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index 1c25c0b..2d8d039 100644 --- a/go.sum +++ b/go.sum @@ -1,93 +1,78 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/aws/aws-sdk-go-v2 v0.10.0 h1:qxZ7TyWFEIucMPQR2qymRx7JZ+hWF0N8HyCWh0XKh6Q= -github.com/aws/aws-sdk-go-v2 v0.10.0/go.mod h1:cpXCmy3BB+lqwGweJjdawczHW3a+g8QgcFHcoOVoHao= +github.com/aws/aws-sdk-go-v2 v0.12.0 h1:bPO4Z7ArhFC9XSfOhO0SgQNIfiLoSKBYzFjvw2qt2BQ= +github.com/aws/aws-sdk-go-v2 v0.12.0/go.mod h1:cpXCmy3BB+lqwGweJjdawczHW3a+g8QgcFHcoOVoHao= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCPyPYZfqHdJmc8MK4wrBjMft6BAM= -github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/logger v1.0.1 h1:Jtq7/44yDwUXMaLTYgXFC31zpm6Oku7OI/k4//yVANQ= +github.com/google/logger v1.0.1/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4= +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/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/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/crypto v0.0.0-20181025213731-e84da0312774 h1:a4tQYYYuK9QdeO/+kEvNYyuR21S+7ve5EANok6hABhI= -golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50= -k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= -k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719 h1:uV4S5IB5g4Nvi+TBVNf3e9L4wrirlwYJ6w88jUQxTUw= -k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= -k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g= -k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k= -k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= -k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20190816222004-e3a6b8045b0b h1:RXEExX+zpnAwh3WmvQMVy5albf6/wuIP1W2ehL2lTqc= +k8s.io/api v0.0.0-20190816222004-e3a6b8045b0b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apimachinery v0.0.0-20190816221834-a9f1d8a9c101 h1:QtHYUjIdgXTtJVdYQhWIQZZoXa32aF3O9BNX2up2plE= +k8s.io/apimachinery v0.0.0-20190816221834-a9f1d8a9c101/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/client-go v11.0.1-0.20190918222721-c0e3722d5cf0+incompatible h1:Qbgu1b9y8BUhpTZD5+6z2pt0YD57D7FGaCkBg2UFaEY= +k8s.io/client-go v11.0.1-0.20190918222721-c0e3722d5cf0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +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/utils v0.0.0-20190923111123-69764acb6e8e h1:BXSmdH6S3YGLlhC89DZp+sNdYSmwNeDU6Xu5ZpzGOlM= +k8s.io/utils v0.0.0-20190923111123-69764acb6e8e/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/main.go b/main.go index e826046..ea0434e 100644 --- a/main.go +++ b/main.go @@ -2,24 +2,33 @@ package main import ( "crypto/tls" + "flag" + "math/rand" "net" "net/http" "net/http/httputil" + "os" "strings" "time" + "github.com/google/logger" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" - "k8s.io/klog" +) + +var ( + resolves mstring + resolvesMap = make(map[string]string) + targetGroupArn = flag.String("tg-arn", "", "ec2 target group arn") ) var h2cProxy = &httputil.ReverseProxy{ Director: func(req *http.Request) { - target, ok := roundrobin(req.Host) + target, ok := resolve(req.Host) req.URL.Host = "" req.URL.Scheme = "https" if ok { - req.URL.Host = target + ":50051" + req.URL.Host = target } }, Transport: &http2.Transport{ @@ -31,7 +40,7 @@ var h2cProxy = &httputil.ReverseProxy{ var proxy = &httputil.ReverseProxy{ Director: func(req *http.Request) { - target, ok := roundrobin(req.Host) + target, ok := resolve(req.Host) req.URL.Host = "" req.URL.Scheme = "http" if ok { @@ -41,7 +50,16 @@ var proxy = &httputil.ReverseProxy{ } func main() { - klog.InitFlags(nil) + logger.Init("", false, false, os.Stderr) + rand.Seed(time.Now().UnixNano()) + flag.Var(&resolves, "resolve", "Resolve x.staging.service to x.default.svc.cluster.local: -resolve=staging.service,default.svc.cluster.local") + flag.Parse() + for _, r := range resolves { + splits := strings.Split(r, ",") + if len(splits) > 1 { + resolvesMap[strings.TrimSpace(splits[0])] = strings.TrimSpace(splits[1]) + } + } go startCtl() server := &http.Server{ Addr: ":50051", @@ -51,7 +69,7 @@ func main() { ReadHeaderTimeout: 5 * time.Second, IdleTimeout: 60 * time.Second, } - klog.Fatal(server.ListenAndServe()) + logger.Fatal(server.ListenAndServe()) } func handler(w http.ResponseWriter, r *http.Request) { @@ -61,3 +79,48 @@ func handler(w http.ResponseWriter, r *http.Request) { proxy.ServeHTTP(w, r) } } + +func resolve(hostport string) (target string, ok bool) { + host, port, err := net.SplitHostPort(hostport) + if err != nil { + // default fallback + host = hostport + port = "50051" + } + for k, v := range resolvesMap { + if strings.HasSuffix(host, k) { + sub := strings.TrimSuffix(host, k) + host = sub + v + break + } + } + ips, err := net.LookupIP(host) + if err != nil { + logger.Errorln(err) + return "", false + } + if len(ips) == 0 { + logger.Warningf("%s not found", host) + return "", false + } + var index int + if len(ips) > 1 { + index = random(0, len(ips)-1) + } + return ips[index].String() + ":" + port, true +} + +func random(min, max int) int { + return min + rand.Intn(max-min) +} + +type mstring []string + +func (m *mstring) String() string { + return "" +} + +func (m *mstring) Set(val string) error { + *m = append(*m, val) + return nil +} diff --git a/ring.go b/ring.go deleted file mode 100644 index 19b3127..0000000 --- a/ring.go +++ /dev/null @@ -1,92 +0,0 @@ -// https://github.com/golang/go/tree/master/src/container/ring - -package main - -type ring struct { - nxt, prv *ring - value string -} - -func (r *ring) init() *ring { - r.nxt = r - r.prv = r - return r -} - -func (r *ring) next() *ring { - if r.nxt == nil { - return r.init() - } - return r.nxt -} - -func (r *ring) prev() *ring { - if r.nxt == nil { - return r.init() - } - return r.prv -} - -func (r *ring) move(n int) *ring { - if r.nxt == nil { - return r.init() - } - switch { - case n < 0: - for ; n < 0; n++ { - r = r.prv - } - case n > 0: - for ; n > 0; n-- { - r = r.nxt - } - } - return r -} - -func newRing(n int) *ring { - if n <= 0 { - return nil - } - r := new(ring) - p := r - for i := 1; i < n; i++ { - p.nxt = &ring{prv: p} - p = p.nxt - } - p.nxt = r - r.prv = p - return r -} - -func (r *ring) link(s *ring) *ring { - n := r.next() - if s != nil { - p := s.prev() - // Note: Cannot use multiple assignment because - // evaluation order of LHS is not specified. - r.nxt = s - s.prv = r - n.prv = p - p.nxt = n - } - return n -} - -func (r *ring) unlink(n int) *ring { - if n <= 0 { - return nil - } - return r.link(r.move(n + 1)) -} - -func (r *ring) len() int { - n := 0 - if r != nil { - n = 1 - for p := r.next(); p != r; p = p.nxt { - n++ - } - } - return n -} diff --git a/rr.go b/rr.go deleted file mode 100644 index fbf9727..0000000 --- a/rr.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -func roundrobin(host string) (string, bool) { - var next string - gResolv.Lock() - defer gResolv.Unlock() - r, ok := gResolv.resolv[host] - if !ok { - return "", false - } - next = r.value - gResolv.resolv[host] = r.next() - return next, true -} diff --git a/rr_test.go b/rr_test.go deleted file mode 100644 index 3841c5b..0000000 --- a/rr_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "testing" -) - -func Test_roundrobin(t *testing.T) { - r := newRing(2) - r.value = "foo" - r.next().value = "bar" - gResolv.resolv["foo"] = r - type args struct { - host string - } - tests := []struct { - name string - args args - want string - want1 bool - }{ - {name: "r1", args: args{host: "foo"}, want: "foo", want1: true}, - {name: "r2", args: args{host: "foo"}, want: "bar", want1: true}, - {name: "r3", args: args{host: "foo"}, want: "foo", want1: true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, got1 := roundrobin(tt.args.host) - if got != tt.want { - t.Errorf("roundrobin() got = %v, want %v", got, tt.want) - } - if got1 != tt.want1 { - t.Errorf("roundrobin() got1 = %v, want %v", got1, tt.want1) - } - }) - } -}