├── .dockerignore ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── cmd └── k8s-ec2-srcdst │ └── main.go ├── deploy ├── README.md ├── k8s-1.6 │ └── stable.yaml └── pre_k8s-1.6 │ └── stable.yaml ├── go.mod ├── go.sum ├── pkg ├── common │ └── util.go └── controller │ ├── srcdst_controller.go │ └── srcdst_controller_test.go └── version.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | vendor 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - "1.14" 4 | install: true 5 | sudo: required 6 | script: 7 | - make 8 | services: 9 | - docker 10 | after_success: 11 | - echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin 12 | - export REPO=ottoyiu/k8s-ec2-srcdst 13 | - export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; 14 | else echo $TRAVIS_PULL_REQUEST_BRANCH; fi) 15 | - export TAG=`if [ "$BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; 16 | fi` 17 | - docker build -t $REPO:$COMMIT . 18 | - docker tag $REPO:$COMMIT $REPO:$TAG 19 | - docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER 20 | - docker push $REPO 21 | - make push_image 22 | env: 23 | global: 24 | - COMMIT=${TRAVIS_COMMIT::8} 25 | - secure: or4vHnrTLAF36IVgzk9iHL43GQT6QkU+98FBpeArgIuxFpo0438WkaIE244553DCp5xf2YwjSyNA1+3u74eiywSgcYpikbnwWlDCpKjtJVIxmY18xdIqHDeisEGyV2GVfI7y5HwJCAfs8vbw7+uZ+2siyWSZ4r5VUGiGMyuAAcDvXBnGvbuPeuWShUmocMnuFQ9VTTJe/41mUAIRZ6bQH7BkWWZfCJibHHH8CiMFWWdcwBFqHpTiqfzfCayZAHqukh6+w+YfBGkIefgPB68KP5JXBVQVXvXKEDx6DGBbZ8CWLHOhGKvTD6w4rR0aYso9UXtmQoMhUSnJ5oDmtdoQmhPNskLKVLfCq8BaycfuCLn7izYkVn0ma3sa2zt4vQ57gxMA/fQPmMuaVpiasJQQwUXvv3tO6FwlQzZ9T5NqG1Ds067uFzgSg5+TrKQ//aFiO2aY7J+0QlJMp2BZrTFirmsNYpWVTYVss0U0OB0giibBK38F/B6VtUkVS0QwoE3ZUqPawpAbCQLjR/TUBO+9w9S6bDI739X/lDdnJQJ/4pN8mNstFrktrIk46LqSm9ob6sL2NOwJ+bCa4b6lx2v5qOeUhCM1tY4LHjZcCh3xpkGFVEQ9AIVSe6kcva0LmIEL4gCRbm3J3RWUWpPJWedDvvSOoWliRK81jPsPEPY/gCk= 26 | - secure: LDq8yIbwEZUZjqeqgcx8iAuasf8LWUmeof+C141Ch/EaGwTqCK94KPE7lcF9nRaaKztsfOCMDIpVi+Ko9z+crtbKLAYGdDJzEpMH+nYjikihg+q1MmDNB++OtsQgEm4BB7ps77jqz9wwY9CIkte3Jev+7AEgnBV5x4zpPSvU13N56S2NJeROdJy8SOZmKJ8Dpa78tBxo+SJk6HKKPumdaDgAMhRmmQJP4yg8IfvErVhdu2zokRefn69sk8dw4z2zBmHHZ0pjj8mOoBZWiVR+6h6ZrzXKAH2WNELng2MAULX3szP0sGfmYnlRREu24UsT7f1HsSANuAoY35wFB0YoAhhWOtlMSiBqOD79coVe54kqIef4wkwNF1qFasrlnyUofx7K455W8Y0nxnrIG9yG+XkObRIkaJBhdrAue+6NRtytNd/ijUPa7IhNYRePPPlG9dnL4zJW1g6fY7gAjoAbOvC/rdj3JpoOPmRoiK7Ng1STUXFkZvT6VZ9ARTDaVNhYVWIomPwHh1qPyps5EZcf3/vhS2OasmwvOdPRYKUlDHGs9hMrhn7ZsfaZg04vhzGAskvbLvw4STOaI3JcwfDdl+D52ph+QZP+uOhC2trgYFUlE8xDOPRjRLzka71UOypvC41CFLUGrB+avyv0L2Q/FY3p22QEcttynqe9XSft7pE= 27 | - secure: PzMHXjNkFcApP6KRAKKBjwfKR0HVrxA/kwjA0tAHVqpZwel+PKm7JPXc0jYNxJoij4gHjA7o48LdJs/83VciomPaUWngI9efHoXPSggSwTa5GyE24jzYShN9Owsq/pW7bdSFHvGOvrmXKWmi/bIIp2k9BTvSwF/jz4iVVhq+VTN0sCdUw2DxN0HZx/cLBIRkDX87pzesG8n0NqgTKrBIPNRrwr6uFFGhi9BPwh8BEIFm3kEcPPG3U2gYkOMDRapUDgD6YaalXkCsBi20pYzAAaGKW/wklQhnPGQXWxUo4nhWuXuXoTNLd7BRh6Ygc/WCFmqEeC0RQ5gscqBK4V7hpDx2LdUgoVBLMvPaMXVbAoxAhCbKlG1IhPCnXlbcbgFUTHuPLFIjeNQGjOgzUr/eOdcm2ruLRzrGd5yvyglt9uL9au+Ac3KbnJGp95V0IP3QKzI9zRYPlxLBQ/M7T/zjrQfQa1BRq+alssNdNHs1kESItcWvsK7wgqGkvzRVrK95O0senzNS2oRY9DF8cEOpvm7ljlHw35wBgZYYXei6cnXFlp5yGV3iSKguiswSeTqCWK2bb5kSJv9wUwlxDVbvulBuqT1h8q837hHYuNrKO+9znWmumFssg4o6jI4srny2hZbcav+O0MA9jxvW/tJubz17KSdttIYj681B6G4Zjl0= 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.6 2 | 3 | RUN apk add -U ca-certificates \ 4 | && update-ca-certificates \ 5 | && rm -rf /var/cache/apk/* 6 | 7 | ADD bin/linux/k8s-ec2-srcdst /k8s-ec2-srcdst 8 | 9 | CMD ["/k8s-ec2-srcdst"] 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := k8s-ec2-srcdst 2 | GOFILES:=$(shell find . -name '*.go' | grep -v -E '(./vendor)') 3 | VERSION?=$(shell git describe --tags --dirty) 4 | IMAGE_TAG:=ottoyiu/${PROJECT_NAME}:${VERSION} 5 | 6 | all: clean check bin image 7 | 8 | image: 9 | docker build -t ${IMAGE_TAG} . 10 | 11 | push_image: 12 | docker push ${IMAGE_TAG} 13 | 14 | bin: bin/linux/${PROJECT_NAME} 15 | 16 | bin/%: LDFLAGS=-X github.com/ottoyiu/${PROJECT_NAME}.Version=${VERSION} 17 | bin/%: $(GOFILES) 18 | mkdir -p $(dir $@) 19 | CGO_ENABLED=0 GOOS=$(word 1, $(subst /, ,$*)) GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o "$@" github.com/ottoyiu/k8s-ec2-srcdst/cmd/k8s-ec2-srcdst/... 20 | 21 | gofmt: 22 | gofmt -w -s pkg/ 23 | gofmt -w -s cmd/ 24 | 25 | test: 26 | go test github.com/ottoyiu/${PROJECT_NAME}/pkg/... -args -v=1 -logtostderr 27 | go test github.com/ottoyiu/${PROJECT_NAME}/cmd/... -args -v=1 -logtostderr 28 | 29 | check: 30 | @find . -name vendor -prune -o -name '*.go' -exec gofmt -s -d {} + 31 | @go vet $(shell go list ./... | grep -v '/vendor/') 32 | @go test -v $(shell go list ./... | grep -v '/vendor/') 33 | 34 | clean: 35 | rm -rf bin 36 | 37 | .PHONY: all bin check test 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # k8s-ec2-srcdst (formerly as kubernetes-ec2-srcdst-controller) 2 | [![Build Status](https://travis-ci.org/ottoyiu/k8s-ec2-srcdst.svg?branch=master)](https://travis-ci.org/ottoyiu/k8s-ec2-srcdst) [![Go Report Card](https://goreportcard.com/badge/github.com/ottoyiu/k8s-ec2-srcdst)](https://goreportcard.com/report/github.com/ottoyiu/k8s-ec2-srcdst) 3 | 4 | A Kubernetes Controller that will ensure that Source/Dest Check on the nodes within the cluster that are EC2 instances, are disabled. 5 | This is useful for Calico deployments in AWS where routing within a VPC subnet can be possible without IPIP encapsulation. 6 | 7 | ## Quick Start 8 | To deploy this controller into your Kubernetes cluster, please make sure your cluster fufills the requirements as listed below. 9 | Then go to `deploy/README.md` for a quick start guide on how to deploy this to your Kubernetes cluster. 10 | 11 | 12 | ## Requirements 13 | k8s-ec2-srcdst must have the ability to access the Kubernetes API for a list of nodes and also ability to add an annotation to a node (write access). Please ensure the service account has sufficient access if ran in-cluster. Otherwise, please make sure that the user specified in the kubeconfig has sufficient permissions. 14 | 15 | k8s-ec2-srcdst also needs the ability to modify the EC2 instance attributes of the nodes running in the Kubernetes cluster. Please make sure to schedule the controller on a node with the IAM policy: 16 | - `ec2:ModifyInstanceAttribute` 17 | 18 | If you are running a Kubernetes cluster in AWS created by kops, only the master node(s) have that IAM policy set (`ec2:*`). The deployment mainfest files (`deploy/*/*.yaml`) already sets the NodeAffinity and Tolerations to only deploy the controller on one of the master nodes. 19 | 20 | ## Kops Integration 21 | k8s-ec2-srcdst has been incorporated as an addon in Kops that deploys alongside with Calico when `cross-subnet` mode 22 | is set. Please read [this document](https://github.com/kubernetes/kops/blob/master/docs/networking.md#enable-cross-subnet-mode-in-calico-aws-only) for instructions on how to enable this on a cluster deployed using Kops. 23 | 24 | 25 | ## Usage 26 | ``` 27 | Usage of ./bin/linux/k8s-ec2-srcdst: 28 | -alsologtostderr 29 | log to standard error as well as files 30 | -kubeconfig string 31 | Path to a kubeconfig file 32 | -log_backtrace_at value 33 | when logging hits line file:N, emit a stack trace 34 | -log_dir string 35 | If non-empty, write log files in this directory 36 | -logtostderr 37 | log to standard error instead of files 38 | -stderrthreshold value 39 | logs at or above this threshold go to stderr 40 | -v value 41 | log level for V logs 42 | -version 43 | Prints current k8s-ec2-srcdst version 44 | -vmodule value 45 | comma-separated list of pattern=N settings for file-filtered logging 46 | ``` 47 | Specifying the verbosity level of logging to 4 using the `-v` flag will get debug level output. 48 | 49 | You only need to specify the location to kubeconfig using the `-kubeconfig` flag if you are running the controller out of the cluster for development and testing purpose. 50 | 51 | The AWS Region must be set as an environmental variable. As well, if you are running this controller outside of the cluster or a node that does not have the proper IAM instance profile, you will need to specify AWS credentials as environmental variables: 52 | 53 | ### Environmental Variables 54 | Variable | Description 55 | ------------------------------ | ---------- 56 | `AWS_REGION` | Region Name (eg. us-west-2) - *required* 57 | `AWS_ACCESS_KEY` | AWS Access Key (Optional if using IAM instance profiles) 58 | `AWS_SECRET_ACCESS_KEY` | AWS Secret Access Key (Optional if using IAM instance profiles) 59 | 60 | 61 | -------------------------------------------------------------------------------- /cmd/k8s-ec2-srcdst/main.go: -------------------------------------------------------------------------------- 1 | package main // import "github.com/ottoyiu/k8s-ec2-srcdst/cmd/k8s-ec2-srcdst" 2 | import ( 3 | "context" 4 | "flag" 5 | "fmt" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/aws/session" 12 | "github.com/aws/aws-sdk-go/service/ec2" 13 | "github.com/golang/glog" 14 | srcdst "github.com/ottoyiu/k8s-ec2-srcdst" 15 | "github.com/ottoyiu/k8s-ec2-srcdst/pkg/common" 16 | "github.com/ottoyiu/k8s-ec2-srcdst/pkg/controller" 17 | "k8s.io/client-go/kubernetes" 18 | ) 19 | 20 | func handleSignals(term func()) { 21 | c := make(chan os.Signal, 1) 22 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 23 | <-c 24 | signal.Stop(c) 25 | term() 26 | } 27 | 28 | func main() { 29 | kubeconfig := flag.String("kubeconfig", "", "Path to a kubeconfig file") 30 | version := flag.Bool("version", false, "Prints current k8s-ec2-srcdst version") 31 | 32 | flag.Set("logtostderr", "true") 33 | flag.Parse() 34 | 35 | if *version { 36 | fmt.Println(srcdst.Version) 37 | os.Exit(0) 38 | } 39 | 40 | glog.Infof("k8s-ec2-srcdst: %v", srcdst.Version) 41 | 42 | // Build the client config - optionally using a provided kubeconfig file. 43 | config, err := common.GetClientConfig(*kubeconfig) 44 | if err != nil { 45 | glog.Fatalf("Failed to load client config: %v", err) 46 | } 47 | 48 | // Construct the Kubernetes client 49 | client, err := kubernetes.NewForConfig(config) 50 | if err != nil { 51 | glog.Fatalf("Failed to create Kubernetes client: %v", err) 52 | } 53 | 54 | awsSession, err := session.NewSession(&aws.Config{}) 55 | if err != nil { 56 | glog.Fatalf("Failed to create an AWS API client session: %v", err) 57 | } 58 | ec2Client := ec2.New(awsSession) 59 | 60 | ctx := context.Background() 61 | ctx, cancel := context.WithCancel(ctx) 62 | defer cancel() 63 | 64 | go handleSignals(cancel) 65 | stop := ctx.Done() 66 | 67 | ctlr := controller.NewSrcDstController(client, ec2Client) 68 | ctlr.RunUntil(stop) 69 | } 70 | -------------------------------------------------------------------------------- /deploy/README.md: -------------------------------------------------------------------------------- 1 | # Deploy 2 | There are two folders: pre_k8s-1.6 and k8s-1.6. Please use the mainfest files that correspond to the version of your Kubernetes cluster. 3 | This is due to the new scheduler of Kubernetes 1.6 ignoring tolerations/taints specified as alpha annotations instead of actual fields, and additional RBAC mainifests (service account, cluster role, cluster role binding). 4 | 5 | 6 | # Quick Start 7 | Note that you likely want to change AWS_REGION. 8 | ``` 9 | AWS_REGION=us-east-1 10 | SSL_CERT_PATH="/etc/ssl/certs/ca-certificates.crt" 11 | 12 | wget -O k8s-ec2-srcdst.yaml https://raw.githubusercontent.com/ottoyiu/k8s-ec2-srcdst/master/deploy/pre_k8s-1.6/stable.yaml 13 | sed -i -e "s@{{AWS_REGION}}@${AWS_REGION}@g" k8s-ec2-srcdst.yaml 14 | sed -i -e "s@{{SSL_CERT_PATH}}@${SSL_CERT_PATH}@g" k8s-ec2-srcdst.yaml 15 | 16 | kubectl apply -f k8s-ec2-srcdst.yaml 17 | ``` 18 | -------------------------------------------------------------------------------- /deploy/k8s-1.6/stable.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | kind: ClusterRole 4 | apiVersion: rbac.authorization.k8s.io/v1beta1 5 | metadata: 6 | name: k8s-ec2-srcdst 7 | rules: 8 | - apiGroups: 9 | - "" 10 | resources: 11 | - nodes 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | - update 17 | - patch 18 | 19 | --- 20 | 21 | apiVersion: v1 22 | kind: ServiceAccount 23 | metadata: 24 | name: k8s-ec2-srcdst 25 | namespace: kube-system 26 | --- 27 | 28 | kind: ClusterRoleBinding 29 | apiVersion: rbac.authorization.k8s.io/v1beta1 30 | metadata: 31 | name: k8s-ec2-srcdst 32 | roleRef: 33 | apiGroup: rbac.authorization.k8s.io 34 | kind: ClusterRole 35 | name: k8s-ec2-srcdst 36 | subjects: 37 | - kind: ServiceAccount 38 | name: k8s-ec2-srcdst 39 | namespace: kube-system 40 | 41 | --- 42 | 43 | apiVersion: extensions/v1beta1 44 | kind: Deployment 45 | metadata: 46 | name: k8s-ec2-srcdst 47 | namespace: kube-system 48 | labels: 49 | k8s-app: k8s-ec2-srcdst 50 | spec: 51 | replicas: 1 52 | selector: 53 | matchLabels: 54 | k8s-app: k8s-ec2-srcdst 55 | template: 56 | metadata: 57 | labels: 58 | k8s-app: k8s-ec2-srcdst 59 | annotations: 60 | # For 1.6, we keep the old tolerations in case of a downgrade to 1.5 61 | scheduler.alpha.kubernetes.io/tolerations: '[{"key":"dedicated", "value":"master"}]' 62 | spec: 63 | serviceAccount: k8s-ec2-srcdst 64 | hostNetwork: true 65 | containers: 66 | - image: ottoyiu/k8s-ec2-srcdst:v0.0.3 67 | name: k8s-ec2-srcdst 68 | resources: 69 | limits: 70 | cpu: 10m 71 | memory: 64Mi 72 | requests: 73 | cpu: 10m 74 | memory: 64Mi 75 | command: 76 | - /k8s-ec2-srcdst 77 | env: 78 | - name: AWS_REGION 79 | value: {{AWS_REGION}} 80 | volumeMounts: 81 | - name: ssl-certs 82 | mountPath: "/etc/ssl/certs/ca-certificates.crt" 83 | readOnly: true 84 | imagePullPolicy: "Always" 85 | volumes: 86 | - name: ssl-certs 87 | hostPath: 88 | path: {{SSL_CERT_PATH}} 89 | nodeSelector: 90 | node-role.kubernetes.io/master: "" 91 | tolerations: 92 | - key: "node-role.kubernetes.io/master" 93 | effect: NoSchedule 94 | -------------------------------------------------------------------------------- /deploy/pre_k8s-1.6/stable.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: k8s-ec2-srcdst 5 | namespace: kube-system 6 | labels: 7 | k8s-app: k8s-ec2-srcdst 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | k8s-app: k8s-ec2-srcdst 13 | template: 14 | metadata: 15 | labels: 16 | k8s-app: k8s-ec2-srcdst 17 | annotations: 18 | scheduler.alpha.kubernetes.io/tolerations: '[{"key":"dedicated", "value":"master"}]' 19 | spec: 20 | hostNetwork: true 21 | containers: 22 | - image: ottoyiu/k8s-ec2-srcdst:v0.0.3 23 | name: k8s-ec2-srcdst 24 | resources: 25 | limits: 26 | cpu: 10m 27 | memory: 64Mi 28 | requests: 29 | cpu: 10m 30 | memory: 64Mi 31 | command: 32 | - /k8s-ec2-srcdst 33 | env: 34 | - name: AWS_REGION 35 | value: {{AWS_REGION}} 36 | volumeMounts: 37 | - name: ssl-certs 38 | mountPath: "/etc/ssl/certs/ca-certificates.crt" 39 | readOnly: true 40 | imagePullPolicy: "Always" 41 | volumes: 42 | - name: ssl-certs 43 | hostPath: 44 | path: {{SSL_CERT_PATH}} 45 | nodeSelector: 46 | kubernetes.io/role: master 47 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ottoyiu/k8s-ec2-srcdst 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.12.48 7 | github.com/go-ini/ini v1.32.0 // indirect 8 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b 9 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 // indirect 10 | github.com/smartystreets/goconvey v1.6.4 // indirect 11 | github.com/stretchr/testify v1.4.0 12 | gopkg.in/ini.v1 v1.57.0 // indirect 13 | k8s.io/api v0.18.6 14 | k8s.io/apimachinery v0.18.6 15 | k8s.io/client-go v0.18.6 16 | ) 17 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 5 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 6 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 7 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 8 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 9 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 10 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 11 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 12 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 13 | github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 14 | github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 15 | github.com/aws/aws-sdk-go v1.12.48 h1:4VnJbrhjiGvgxQWcIxKrtyjaJ203b6QxOh4rXlXyOR0= 16 | github.com/aws/aws-sdk-go v1.12.48/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= 17 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 18 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 21 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 22 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 23 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 24 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 25 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 26 | github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= 27 | github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 28 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 29 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 30 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 31 | github.com/go-ini/ini v1.32.0 h1:/MArBHSS0TFR28yPPDK1vPIjt4wUnPBfb81i6iiyKvA= 32 | github.com/go-ini/ini v1.32.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 33 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 34 | github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= 35 | github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= 36 | github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= 37 | github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= 38 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= 39 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 40 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 41 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 42 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= 43 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 44 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 45 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 46 | github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 47 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 48 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 49 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 50 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 51 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 52 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 53 | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= 54 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 55 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 56 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= 57 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 58 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 59 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 60 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 61 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 62 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 63 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 64 | github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= 65 | github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 66 | github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= 67 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 68 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 69 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 70 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 71 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 72 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 73 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 74 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 75 | github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= 76 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 77 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= 78 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 79 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 80 | github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= 81 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 82 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 83 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 84 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 85 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 86 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 87 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 88 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 89 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 90 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 91 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 92 | github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 93 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 94 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 95 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 96 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 97 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 98 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 99 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 100 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 101 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 102 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 103 | github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= 104 | github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 105 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 106 | github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= 107 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 108 | github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= 109 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 110 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 111 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 112 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 113 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 114 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 115 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 116 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 117 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 118 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 119 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 120 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 121 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 122 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 123 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 124 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 125 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 126 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 127 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= 128 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 129 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 130 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 131 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 132 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 133 | golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 134 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 135 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 136 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 137 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 138 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 139 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 140 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 141 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= 142 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 143 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 144 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 145 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 146 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 147 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 148 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 149 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 150 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 151 | golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 152 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 153 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 154 | golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 155 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 156 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 157 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= 158 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 159 | golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 160 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 161 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 162 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 163 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 164 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 165 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= 166 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 167 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 168 | golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 169 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 170 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 171 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 172 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 173 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 174 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 175 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 176 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 177 | google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= 178 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 179 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 180 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 181 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 182 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 183 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 184 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 185 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 186 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 187 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 188 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 189 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 190 | gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= 191 | gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 192 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 193 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 194 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 195 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 196 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 197 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 198 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 199 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 200 | k8s.io/api v0.18.6 h1:osqrAXbOQjkKIWDTjrqxWQ3w0GkKb1KA1XkUGHHYpeE= 201 | k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= 202 | k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag= 203 | k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= 204 | k8s.io/client-go v0.18.6 h1:I+oWqJbibLSGsZj8Xs8F0aWVXJVIoUHWaaJV3kUN/Zw= 205 | k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= 206 | k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 207 | k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 208 | k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 209 | k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= 210 | k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 211 | k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= 212 | k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= 213 | k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= 214 | k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 215 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 216 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= 217 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 218 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 219 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= 220 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 221 | -------------------------------------------------------------------------------- /pkg/common/util.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "k8s.io/client-go/rest" 5 | "k8s.io/client-go/tools/clientcmd" 6 | ) 7 | 8 | // GetClientConfig gets the credentials necessary to connect to the Kubernetes 9 | // cluster either through the specified kubeconfig or to get the necessary info 10 | // from the running pod within the cluster 11 | func GetClientConfig(kubeconfig string) (*rest.Config, error) { 12 | if kubeconfig != "" { 13 | return clientcmd.BuildConfigFromFlags("", kubeconfig) 14 | } 15 | return rest.InClusterConfig() 16 | } 17 | -------------------------------------------------------------------------------- /pkg/controller/srcdst_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/url" 7 | "strings" 8 | "time" 9 | 10 | "github.com/golang/glog" 11 | 12 | "github.com/aws/aws-sdk-go/aws" 13 | "github.com/aws/aws-sdk-go/service/ec2" 14 | "github.com/aws/aws-sdk-go/service/ec2/ec2iface" 15 | 16 | v1 "k8s.io/api/core/v1" 17 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | "k8s.io/apimachinery/pkg/fields" 19 | "k8s.io/client-go/kubernetes" 20 | corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 21 | "k8s.io/client-go/tools/cache" 22 | ) 23 | 24 | // Controller is a Kubernetes controller that watches Node objects and disables AWS EC2 25 | // source/destination checks on the underlying EC2 instances' attached ENIs. 26 | type Controller struct { 27 | nodes corev1.NodeInterface 28 | ec2Client ec2iface.EC2API 29 | controller cache.Controller 30 | } 31 | 32 | const ( 33 | srcDstCheckDisabledAnnotation = "kubernetes-ec2-srcdst-controller.ottoyiu.com/srcdst-check-disabled" // used as the Node annotation key 34 | ) 35 | 36 | // NewSrcDstController creates a new Kubernetes controller using client-go's Informer. 37 | func NewSrcDstController(client kubernetes.Interface, ec2Client *ec2.EC2) *Controller { 38 | c := &Controller{ 39 | nodes: client.CoreV1().Nodes(), 40 | ec2Client: ec2Client, 41 | } 42 | 43 | nodeListWatcher := cache.NewListWatchFromClient( 44 | client.CoreV1().RESTClient(), 45 | "nodes", 46 | v1.NamespaceAll, 47 | fields.Everything()) 48 | 49 | _, c.controller = cache.NewInformer( 50 | nodeListWatcher, 51 | &v1.Node{}, 52 | 60*time.Second, 53 | // Callback functions to trigger when nodes are added or updated: 54 | cache.ResourceEventHandlerFuncs{ 55 | AddFunc: c.handler, 56 | UpdateFunc: func(old, new interface{}) { c.handler(new) }, 57 | }, 58 | ) 59 | 60 | return c 61 | } 62 | 63 | // RunUntil sets this controller running, processing events observed via the Kubernetes API until 64 | // the supplied channel is closed. 65 | func (c *Controller) RunUntil(stop <-chan struct{}) { 66 | c.controller.Run(stop) 67 | } 68 | 69 | func (c *Controller) handler(obj interface{}) { 70 | ctx := context.TODO() 71 | node, ok := obj.(*v1.Node) 72 | if !ok { 73 | glog.Errorf("Expected Node but handler received: %+v", obj) 74 | return 75 | } 76 | glog.V(4).Infof("Received update of node: %s", node.Name) 77 | c.disableSrcDstIfEnabled(ctx, node) 78 | } 79 | 80 | func (c *Controller) disableSrcDstIfEnabled(ctx context.Context, node *v1.Node) { 81 | srcDstCheckEnabled := true 82 | if node.Annotations != nil { 83 | if _, ok := node.Annotations[srcDstCheckDisabledAnnotation]; ok { 84 | srcDstCheckEnabled = false 85 | } 86 | } 87 | 88 | if srcDstCheckEnabled { 89 | // The "source/destination check disabled" annotation does not exist. 90 | // Call the AWS EC2 API to disable the check. 91 | instanceID, err := getInstanceIDFromProviderID(node.Spec.ProviderID) 92 | if err != nil { 93 | glog.Errorf("Fail to retrieve Instance ID from Provider ID: %v", node.Spec.ProviderID) 94 | return 95 | } 96 | err = c.disableSrcDstCheck(*instanceID) 97 | if err != nil { 98 | glog.Errorf("Failed to disable source/destination check for EC2 instance: %v; %v", *instanceID, err) 99 | return 100 | } 101 | glog.Infof("Marking node %s with SrcDstCheckDisabledAnnotation", node.Name) 102 | // We should not modify the cache object directly, so we make a copy first. 103 | nodeCopy := node.DeepCopy() 104 | annotations := nodeCopy.GetAnnotations() 105 | if annotations == nil { 106 | annotations = make(map[string]string, 1) 107 | nodeCopy.SetAnnotations(annotations) 108 | } 109 | annotations[srcDstCheckDisabledAnnotation] = "true" 110 | if _, err := c.nodes.Update(ctx, nodeCopy, metav1.UpdateOptions{}); err != nil { 111 | glog.Errorf("Failed to set %s annotation: %v", srcDstCheckDisabledAnnotation, err) 112 | } 113 | } else { 114 | glog.V(4).Infof("Skipping node %s because it already has the SrcDstCheckDisabledAnnotation", node.Name) 115 | 116 | } 117 | } 118 | 119 | func (c *Controller) disableSrcDstCheck(instanceID string) error { 120 | _, err := c.ec2Client.ModifyInstanceAttribute( 121 | &ec2.ModifyInstanceAttributeInput{ 122 | InstanceId: aws.String(instanceID), 123 | SourceDestCheck: &ec2.AttributeBooleanValue{ 124 | Value: aws.Bool(false), 125 | }, 126 | }, 127 | ) 128 | 129 | return err 130 | } 131 | 132 | // getInstanceIDFromProviderID will retrieves the instance ID from a provider ID, so long as the 133 | // provider is AWS. 134 | func getInstanceIDFromProviderID(providerID string) (*string, error) { 135 | // providerID is in this format: aws:///availability-zone/instanceID 136 | // TODO: why the extra slash in the provider ID of Kubernetes anyways? 137 | if !strings.HasPrefix(providerID, "aws") { 138 | return nil, fmt.Errorf("node is not hosted in AWS EC2; skipping") 139 | } 140 | providerID = strings.Replace(providerID, "///", "//", 1) 141 | url, err := url.Parse(providerID) 142 | if err != nil { 143 | return nil, fmt.Errorf("invalid providerID %q: %v", providerID, err) 144 | } 145 | instanceID := url.Path 146 | instanceID = strings.Trim(instanceID, "/") 147 | 148 | // We sanity check the resulting volume; the two known formats are 149 | // i-12345678 and i-12345678abcdef01. 150 | // TODO: Regex match? 151 | if strings.Contains(instanceID, "/") || !strings.HasPrefix(instanceID, "i-") { 152 | return nil, fmt.Errorf("invalid format for AWS instance ID: %q", instanceID) 153 | } 154 | 155 | return &instanceID, nil 156 | } 157 | -------------------------------------------------------------------------------- /pkg/controller/srcdst_controller_test.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/aws/aws-sdk-go/service/ec2" 8 | "github.com/aws/aws-sdk-go/service/ec2/ec2iface" 9 | "github.com/stretchr/testify/assert" 10 | v1 "k8s.io/api/core/v1" 11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | "k8s.io/client-go/kubernetes/fake" 13 | ) 14 | 15 | type mockEC2Client struct { 16 | ec2iface.EC2API 17 | res *ec2.ModifyInstanceAttributeOutput 18 | err error 19 | CalledCounter int 20 | } 21 | 22 | func (c *mockEC2Client) ModifyInstanceAttribute(*ec2.ModifyInstanceAttributeInput) (*ec2.ModifyInstanceAttributeOutput, error) { 23 | c.CalledCounter = c.CalledCounter + 1 24 | return c.res, c.err 25 | } 26 | 27 | func newMockEC2Client() *mockEC2Client { 28 | return &mockEC2Client{CalledCounter: 0} 29 | } 30 | 31 | func TestDisableSrcDstIfEnabled(t *testing.T) { 32 | annotations := map[string]string{srcDstCheckDisabledAnnotation: "true"} 33 | masterTaint := &v1.Taint{ 34 | Key: "node-role.kubernetes.io/master", 35 | Effect: v1.TaintEffectNoSchedule, 36 | } 37 | node0 := &v1.Node{Spec: v1.NodeSpec{ProviderID: "aws:///us-mock-1/i-abcdefgh", Taints: []v1.Taint{*masterTaint}}, ObjectMeta: metav1.ObjectMeta{Name: "node0", UID: "01"}} 38 | node1 := &v1.Node{Spec: v1.NodeSpec{ProviderID: "aws:///us-mock-1/i-bcdefdaf", Taints: []v1.Taint{*masterTaint}}, ObjectMeta: metav1.ObjectMeta{Name: "node1", UID: "02"}} 39 | node1.Annotations = annotations 40 | 41 | var tests = []struct { 42 | node *v1.Node 43 | disableSrcDstCheckCalled bool 44 | }{ 45 | {node0, true}, 46 | {node1, false}, 47 | } 48 | 49 | ec2Client := newMockEC2Client() 50 | kubeClient := fake.NewSimpleClientset(&v1.NodeList{Items: []v1.Node{*node0, *node1}}) 51 | 52 | c := &Controller{ 53 | nodes: kubeClient.CoreV1().Nodes(), 54 | ec2Client: ec2Client, 55 | } 56 | ctx := context.Background() 57 | 58 | for _, tt := range tests { 59 | calledCount := ec2Client.CalledCounter 60 | c.disableSrcDstIfEnabled(ctx, tt.node) 61 | called := (ec2Client.CalledCounter - calledCount) > 0 62 | assert.Equal( 63 | t, 64 | called, 65 | tt.disableSrcDstCheckCalled, 66 | "Verify that ModifyInstanceAttribute will get called if node needs srcdstcheck disabled", 67 | ) 68 | } 69 | 70 | // Validate that node did get updated with SrcDstCheckDisabledAnnotation 71 | updatedNodes, err := kubeClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) 72 | assert.Nil(t, err) 73 | for _, updatedNode := range updatedNodes.Items { 74 | assert.NotEmpty(t, updatedNode.Annotations) 75 | assert.NotNil(t, updatedNode.Annotations[srcDstCheckDisabledAnnotation]) 76 | 77 | // K8s 1.6 support; ensure that taints still exists and have not been touched 78 | assert.NotEmpty(t, updatedNode.Spec.Taints) 79 | assert.Equal(t, updatedNode.Spec.Taints[0], *masterTaint) 80 | } 81 | } 82 | 83 | func TestGetInstanceIDFromProviderID(t *testing.T) { 84 | 85 | var tests = []struct { 86 | providerID string 87 | expectedInstanceID string 88 | expectedError bool 89 | }{ 90 | {"aws:///us-west-2a/i-09fc5a0ae524b0333", "i-09fc5a0ae524b0333", false}, 91 | {"aws://us-west-2a/i-a123hd52", "i-a123hd52", false}, 92 | {"gce://us-west-1a/test", "", true}, 93 | {"this_will_fail", "", true}, 94 | {"i-a123hd52", "", true}, 95 | } 96 | 97 | for _, tt := range tests { 98 | instanceID, err := getInstanceIDFromProviderID(tt.providerID) 99 | if !tt.expectedError { 100 | assert.Equal( 101 | t, 102 | tt.expectedInstanceID, 103 | *instanceID, 104 | "Check if instance ID is parsed out correctly from provider ID", 105 | ) 106 | } else { 107 | assert.NotNil( 108 | t, 109 | err, 110 | err.Error(), 111 | ) 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package srcdst 2 | 3 | // Version should be replaced by Makefile 4 | var Version = "" 5 | --------------------------------------------------------------------------------