├── .github └── ISSUE_TEMPLATE │ └── feature_request.md ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINERS ├── Makefile ├── README.md ├── artifacts └── examples │ ├── crd.yaml │ └── example-cron-hpa.yaml ├── build ├── docker │ ├── Dockerfile │ ├── Dockerfile_arch │ ├── ca.crt │ ├── tls.crt │ └── tls.key └── lib │ ├── common.mk │ ├── create-manifest.sh │ ├── image.mk │ └── install-buildx.sh ├── deployment └── cron-hpa-controller │ ├── crd.yaml │ └── deployment.yaml ├── design.md ├── go.mod ├── go.sum ├── hack ├── build-image.sh ├── build.sh ├── gencerts.sh ├── lib │ └── lib.sh ├── update-codegen.sh ├── update-gofmt.sh ├── verify-all.sh ├── verify-codegen.sh └── verify-gofmt.sh ├── main.go └── pkg ├── admission ├── admission.go └── util.go ├── apis └── cronhpacontroller │ ├── register.go │ └── v1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go ├── client ├── clientset │ └── versioned │ │ ├── clientset.go │ │ ├── doc.go │ │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ │ └── typed │ │ └── cronhpacontroller │ │ └── v1 │ │ ├── cronhpa.go │ │ ├── cronhpacontroller_client.go │ │ ├── doc.go │ │ ├── fake │ │ ├── doc.go │ │ ├── fake_cronhpa.go │ │ └── fake_cronhpacontroller_client.go │ │ └── generated_expansion.go ├── informers │ └── externalversions │ │ ├── cronhpacontroller │ │ ├── interface.go │ │ └── v1 │ │ │ ├── cronhpa.go │ │ │ └── interface.go │ │ ├── factory.go │ │ ├── generic.go │ │ └── internalinterfaces │ │ └── factory_interfaces.go └── listers │ └── cronhpacontroller │ └── v1 │ ├── cronhpa.go │ └── expansion_generated.go ├── cronhpa ├── controller.go ├── controller_test.go └── crd.go └── logs └── logs.go /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .version-defs 2 | bin/**/* 3 | go/**/* 4 | /.idea 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | Welcome to [report Issues](https://github.com/tkestack/tapp/issues) or [pull requests](https://github.com/tkestack/tapp/pulls). It's recommended to read the following Contributing Guide first before contributing. 4 | 5 | This document provides a set of best practices for open source contributions - bug reports, code submissions / pull requests, etc. 6 | 7 | ## Issues 8 | 9 | We use Github Issues to track public bugs and feature requests. 10 | 11 | ### Due diligence 12 | 13 | Before submitting a issue, please do the following: 14 | 15 | * Perform **basic troubleshooting** steps: 16 | * Make sure you’re on the latest version. If you’re not on the most recent version, your problem may have been solved already! Upgrading is always the best first step. 17 | * Try older versions. If you’re already on the latest release, try rolling back a few minor versions (e.g. if on 1.7, try 1.5 or 1.6) and see if the problem goes away. This will help the devs narrow down when the problem first arose in the commit log. 18 | * Try switching up dependency versions. If the software in question has dependencies (other libraries, etc) try upgrading/downgrading those as well. 19 | * Search the project’s bug/issue tracker to make sure it’s not a known issue. 20 | * If you don’t find a pre-existing issue, consider checking with the mailing list and/or IRC channel in case the problem is non-bug-related. 21 | 22 | ### What to put in your bug report 23 | 24 | Make sure your report gets the attention it deserves: bug reports with missing information may be ignored or punted back to you, delaying a fix. The below constitutes a bare minimum; more info is almost always better: 25 | 26 | * What version of the core programming language interpreter/compiler are you using? For example, if it’s a Golang project, are you using Golang 1.13? Golang 1.12? 27 | * What operating system are you on? Windows? (32-bit? 64-bit?) Mac OS X? (10.14? 10.10?) Linux? (Which distro? Which version of that distro? 32 or 64 bits?) Again, more detail is better. 28 | * Which version or versions of the software are you using? Ideally, you followed the advice above and have ruled out (or verified that the problem exists in) a few different versions. 29 | * How can the developers recreate the bug on their end? If possible, include a copy of your code, the command you used to invoke it, and the full output of your run (if applicable.) A common tactic is to pare down your code until a simple (but still bug-causing) “base case” remains. Not only can this help you identify problems which aren’t real bugs, but it means the developer can get to fixing the bug faster. 30 | 31 | ## Pull Requests 32 | 33 | We strongly welcome your pull request to make TKEStack project better. 34 | 35 | ### Licensing of contributed material 36 | 37 | Keep in mind as you contribute, that code, docs and other material submitted to open source projects are usually considered licensed under the same terms as the rest of the work. 38 | 39 | Anything submitted to a project falls under the licensing terms in the repository’s top level LICENSE file. Per-file copyright/license headers are typically extraneous and undesirable. Please don’t add your own copyright headers to new files unless the project’s license actually requires them! 40 | 41 | ### Branch Management 42 | 43 | There are three main branches here: 44 | 45 | 1. `master` branch. 46 | 1. It is the latest (pre-)release branch. We use `master` for tags, with version number `1.1.0`, `1.2.0`, `1.3.0`... 47 | 2. **Don't submit any PR on `master` branch.** 48 | 2. `dev` branch. 49 | 1. It is our stable developing branch. After full testing, `dev` will be merged to `master` branch for the next release. 50 | 2. **You are recommended to submit bugfix or feature PR on `dev` branch.** 51 | 3. `hotfix` branch. 52 | 1. It is the latest tag version for hot fix. If we accept your pull request, we may just tag with version number `1.1.1`, `1.2.3`. 53 | 2. **Only submit urgent PR on `hotfix` branch for next specific release.** 54 | 55 | Normal bugfix or feature request should be submitted to `dev` branch. After full testing, we will merge them to `master` branch for the next release. 56 | 57 | If you have some urgent bugfixes on a published version, but the `master` branch have already far away with the latest tag version, you can submit a PR on hotfix. And it will be cherry picked to `dev` branch if it is possible. 58 | 59 | ``` 60 | master 61 | ↑ 62 | dev <--- hotfix PR 63 | ↑ 64 | feature/bugfix PR 65 | ``` 66 | 67 | ### Make Pull Requests 68 | 69 | The code team will monitor all pull request, we run some code check and test on it. After all tests passed, we will accecpt this PR. But it won't merge to `master` branch at once, which have some delay. 70 | 71 | Before submitting a pull request, please make sure the followings are done: 72 | 73 | 1. Fork the repo and create your branch from `master` or `hotfix`. 74 | 2. Update code or documentation if you have changed APIs. 75 | 3. Add the copyright notice to the top of any new files you've added. 76 | 4. Check your code lints and checkstyles. 77 | 5. Test and test again your code. 78 | 6. Now, you can submit your pull request on `dev` or `hotfix` branch. 79 | 80 | ## Code Conventions 81 | 82 | Use [Kubernetes Code Conventions](https://github.com/kubernetes/community/blob/master/contributors/guide/coding-conventions.md) for all projects in the TKEStack organization. 83 | 84 | ## Documentation isn’t optional 85 | 86 | It’s not! Patches without documentation will be returned to sender. By “documentation” we mean: 87 | 88 | * Docstrings must be created or updated for public API functions/methods/etc. (This step is optional for some bugfixes.) 89 | * New features should ideally include updates to prose documentation, including useful example code snippets. 90 | * All submissions should have a changelog entry crediting the contributor and/or any individuals instrumental in identifying the problem. 91 | 92 | ## Tests aren’t optional 93 | 94 | Any bugfix that doesn’t include a test proving the existence of the bug being fixed, may be suspect. Ditto for new features that can’t prove they actually work. 95 | 96 | We’ve found that test-first development really helps make features better architected and identifies potential edge cases earlier instead of later. Writing tests before the implementation is strongly encouraged. 97 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | Jun Gong (@hex108) 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: verify-gofmt 3 | hack/build.sh 4 | 5 | .PHONY: clean 6 | clean: 7 | rm -rf bin/ _output/ go .version-defs 8 | 9 | .PHONY: build 10 | build: 11 | hack/build.sh 12 | 13 | # ============================================================================== 14 | # Includes 15 | 16 | include build/lib/common.mk 17 | include build/lib/image.mk 18 | 19 | .PHONY: verify 20 | verify: 21 | hack/verify-all.sh 22 | 23 | .PHONY: verify-gofmt 24 | verify-gofmt: 25 | hack/verify-gofmt.sh 26 | 27 | format: 28 | hack/format.sh 29 | 30 | image: 31 | hack/build-image.sh 32 | 33 | ## release.multiarch: Build docker images for multiple platforms and push manifest lists to registry. 34 | .PHONY: release.multiarch 35 | release.multiarch: 36 | @$(MAKE) image.manifest.push.multiarch BINS="cron-hpa-controller" 37 | 38 | # vim: set ts=2 sw=2 tw=0 noet : 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CronHPA 2 | 3 | Cron Horizontal Pod Autoscaler(CronHPA) enables us to auto scale workloads(those support `scale` subresource, e.g. deployment, statefulset) periodically using [crontab](https://en.wikipedia.org/wiki/Cron) scheme. 4 | 5 | 6 | `CronHPA` example: 7 | 8 | ``` 9 | apiVersion: extensions.tkestack.io/v1 10 | kind: CronHPA 11 | metadata: 12 | name: example-cron-hpa 13 | spec: 14 | scaleTargetRef: 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | name: demo-deployment 18 | crons: 19 | - schedule: "0 23 * * 5" // Set replicas to 60 every Friday 23:00 20 | targetReplicas: 60 21 | - schedule: "0 23 * * 7" // Set replicas to 30 every Sunday 23:00 22 | targetReplicas: 30 23 | ``` 24 | 25 | More design ideas could be found at [design.md](./design.md). 26 | 27 | ## Build 28 | 29 | ``` sh 30 | $ make build 31 | or 32 | $ go build -o bin/cron-hpa-controller . 33 | ``` 34 | 35 | ## Run 36 | 37 | ```sh 38 | # assumes you have a working kubeconfig, not required if operating in-cluster 39 | # It will create CRD `CronHPA` by default. 40 | $ bin/cron-hpa-controller --master=127.0.0.1:8080 --v=5 --stderrthreshold=0 // Assume 127.0.0.1:8080 is k8s master ip:port 41 | or 42 | $ bin/cron-hpa-controller --kubeconfig=$HOME/.kube/config --v=5 --stderrthreshold=0 43 | 44 | # create a custom resource of type cron-hpa 45 | $ kubectl create -f artifacts/examples/example-cron-hpa.yaml 46 | 47 | # check pods created through the custom resource 48 | $ kubectl get cronhpa 49 | ``` 50 | 51 | ## Cleanup 52 | 53 | You can clean up the created CustomResourceDefinition with: 54 | 55 | $ kubectl delete crd cronhpas.extensions.tkestack.io 56 | -------------------------------------------------------------------------------- /artifacts/examples/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: cronhpas.extensions.tkestack.io 5 | spec: 6 | group: extensions.tkestack.io 7 | version: v1 8 | names: 9 | kind: CronHPA 10 | listKind: CronHPAList 11 | plural: cronhpas 12 | singular: cronhpa 13 | scope: Namespaced 14 | -------------------------------------------------------------------------------- /artifacts/examples/example-cron-hpa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: extensions.tkestack.io/v1 3 | kind: CronHPA 4 | metadata: 5 | name: example-cron-hpa 6 | spec: 7 | scaleTargetRef: 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | name: demo-deployment 11 | crons: 12 | - schedule: "*/2 * * * *" 13 | targetReplicas: 3 14 | - schedule: "*/3 * * * *" 15 | targetReplicas: 6 16 | 17 | --- 18 | apiVersion: apps/v1 19 | kind: Deployment 20 | metadata: 21 | name: demo-deployment 22 | labels: 23 | app: nginx 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: nginx 29 | template: 30 | metadata: 31 | labels: 32 | app: nginx 33 | spec: 34 | containers: 35 | - name: nginx 36 | image: nginx 37 | ports: 38 | - containerPort: 80 39 | -------------------------------------------------------------------------------- /build/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | From alpine:3.10 2 | 3 | ADD cron-hpa-controller /usr/local/bin 4 | RUN mkdir /etc/certs 5 | ADD ca.crt /etc/certs 6 | ADD tls.crt /etc/certs 7 | ADD tls.key /etc/certs 8 | 9 | ENTRYPOINT ["/usr/local/bin/cron-hpa-controller"] 10 | -------------------------------------------------------------------------------- /build/docker/Dockerfile_arch: -------------------------------------------------------------------------------- 1 | # Tencent is pleased to support the open source community by making TKEStack 2 | # available. 3 | # 4 | # Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | # this file except in compliance with the License. You may obtain a copy of the 8 | # License at 9 | # 10 | # https://opensource.org/licenses/Apache-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations under the License. 16 | 17 | FROM golang:1.14.4 AS builder 18 | ARG TARGETPLATFORM 19 | RUN echo "building for ${TARGETPLATFORM}" 20 | ARG WORKDIR="/go/src/tkestack.io/cron-hpa/" 21 | RUN mkdir -p ${WORKDIR} 22 | WORKDIR ${WORKDIR} 23 | 24 | COPY . ${WORKDIR} 25 | RUN make build 26 | 27 | 28 | FROM alpine:3.10 29 | 30 | RUN mkdir /etc/certs 31 | ADD build/docker/ca.crt /etc/certs 32 | ADD build/docker/tls.crt /etc/certs 33 | ADD build/docker/tls.key /etc/certs 34 | COPY --from=builder /go/src/tkestack.io/cron-hpa/bin/cron-hpa-controller /usr/local/bin 35 | 36 | ENTRYPOINT ["/usr/local/bin/cron-hpa-controller"] -------------------------------------------------------------------------------- /build/docker/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICyjCCAbICCQClzVTuRuEnBTANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtB 3 | ZG1pc3Npb24gV2ViaG9vayBTZXJ2ZXIgQ0EwIBcNMjEwMzA5MDY0MTUyWhgPMjI5 4 | NDEyMjMwNjQxNTJaMCYxJDAiBgNVBAMMG0FkbWlzc2lvbiBXZWJob29rIFNlcnZl 5 | ciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcMtRva/0HuM/64 6 | Agf9LrJugPiBSEFFp331AXakrgBS1LqL57XSndupbHGVUtGZpeW29zvNuzS2ksqq 7 | XdkAuoCRxKFKM8nlZ+CLZt2qFzkUY0IFa7riU0n2uIXU231T0z3vurcSa9hI5Yl/ 8 | Ow+JVVFy3SD1lmgAo9+c9or9sqkxFZr9wJNWuz96oM98yOzOpgY8nkeQqAg2DDmQ 9 | P7pj/I6h6Ir+TpDHDWr+XQfdx8dXSZl7tVi8N8ugE6Hy98v2y1B5DcdEnfmPjzcc 10 | cRUBHNiwnFeJIiUYxfGcgYP31s6v0juMOX+qRue8WnEat2kTuW+c4O8UUoBoFhvB 11 | DykPSNsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQwXRQfVsRpAlkr3VJ49ACRlY 12 | k8XlyILL3f2FiYijLEYAHpqRt51CYGYqlFEZYFq2F7PB3lCAB+vAV/QvZjTXO9O2 13 | r+m6EGNSeoVBkfVhkFo4vFJLqrczG4kA6HCHhdu4qMhzfV5i5+kiG50iLcyWTHl+ 14 | npZm3cFzMxBlI/DjE/OfFDjn8+wzti8mjPtOY9Tw2+bml0urof81rOh50A7+D7t3 15 | a1cAMnmYjFojWtrBJmmjSb4x89agLhxgAN9wZ6PgCmvizftxB3ASNjhh9TiOmwmJ 16 | H30pznf4+Fgpze+qk0YQ2RQ29nCb+xKGp7dZX++i7tYEjNJLNoJ9net37oNN0w== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /build/docker/tls.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWjCCAkKgAwIBAgIJAPidYVq65UEMMA0GCSqGSIb3DQEBBQUAMCYxJDAiBgNV 3 | BAMMG0FkbWlzc2lvbiBXZWJob29rIFNlcnZlciBDQTAgFw0yMTAzMDkwNjQxNTJa 4 | GA8yMjk0MTIyMzA2NDE1MlowTjELMAkGA1UEBhMCQ04xETAPBgNVBAoMCHRrZXN0 5 | YWNrMSwwKgYDVQQDDCNjcm9uLWhwYS1jb250cm9sbGVyLmt1YmUtc3lzdGVtLnN2 6 | YzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtz5nHDIx+Sqmm1J2xy 7 | mYwKTkSEdZ+YiiyfQ7h+PgwyO54Im6F647CFfItS9CEARGdvItuZOLE2fq0icYh3 8 | YCj2z/BsjOi1oXQMgfXSG+4TY+UPTjMe8JfglGHECmN3Ggy7dIY0Yf1aUo7gj2Fh 9 | jFfNnTSZXaP+dU34Rev8bo0O0ODSpeJO38h16wqmD6sCnNEBQIhWGtPLhMGMoaed 10 | pg/IyLsVUAERhB1TVHWFmXglM6klSESGqqNTJSPYVfpg7SPC0raN2NiBP1sYZcke 11 | qNL/WCYQjig9ASpFNzbkZrVHbePLU5OhIPlVMYz3lZhRL/SSeH9BqcMalCbEwqBL 12 | 8/UCAwEAAaNhMF8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMC 13 | BggrBgEFBQcDATAuBgNVHREEJzAlgiNjcm9uLWhwYS1jb250cm9sbGVyLmt1YmUt 14 | c3lzdGVtLnN2YzANBgkqhkiG9w0BAQUFAAOCAQEAJQz2+A7eC1dptaHLnSqGtuLf 15 | DqHkPvFJ6ZTmak8/UlGrdO3y/LMk7eVSkwQ4F9zPz0D9Xd9Uw+biu1EOiiHetggY 16 | BVGRpfObxd54luA5EGVMHQy8IC9y5DOB/m4ehEq3An1zjS4yGTpozhf/R5+bbR3G 17 | 8pcNUCyXrzCpXLoSOzCtyCPcP80QrfncMgxpDQlrJVxuyT7qsCGddfTocbIiVZJE 18 | yew5OxppFtC0k+sL9IOHCgSK84DNsoHGkMmYzLY2U1ZpnNASYdNQaxkwZvsZh6Jy 19 | EN4/olD6tqJLkxOHfTCVN0ic07Hh6wSLUY1sEHuPFVO9RKU62XvTJ2KyHID27w== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /build/docker/tls.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAq3PmccMjH5KqabUnbHKZjApORIR1n5iKLJ9DuH4+DDI7ngib 3 | oXrjsIV8i1L0IQBEZ28i25k4sTZ+rSJxiHdgKPbP8GyM6LWhdAyB9dIb7hNj5Q9O 4 | Mx7wl+CUYcQKY3caDLt0hjRh/VpSjuCPYWGMV82dNJldo/51TfhF6/xujQ7Q4NKl 5 | 4k7fyHXrCqYPqwKc0QFAiFYa08uEwYyhp52mD8jIuxVQARGEHVNUdYWZeCUzqSVI 6 | RIaqo1MlI9hV+mDtI8LSto3Y2IE/WxhlyR6o0v9YJhCOKD0BKkU3NuRmtUdt48tT 7 | k6Eg+VUxjPeVmFEv9JJ4f0GpwxqUJsTCoEvz9QIDAQABAoIBAEzLKsqFprO7k4yp 8 | UTEn21J4Qzo5Qh3ryufVphV6pfv8e+t624pmaplkELauvx4Q6pKRmsFVTalCSVbu 9 | +H8xSObQNa7wT+TjhZ9fAs7B/zSRhsrQIiyPjR/ZvVxU3HpUnFxbkgOSbtl1nUjV 10 | mCL7+EpTlDg9AU406QG1VEww0qtm3ZOkpCys7Sw3hQBs0goIJc8fMrsj9MG/Mu5D 11 | 0h0XJvQ+n0EVslg3uW0zXoqDJHHIrRrb6F2m6GfS8OSFfvePoa92eACluelNZjtS 12 | dlVVlmWcPdqtpBHymGTeBmdRGRunOt294aetesfhJR6Y84Y71GcgtmB1w/Pl0HOy 13 | Gan3doECgYEA22Ydy42guuAdcG1mIXzbDOOmUUY3pDVplsmWfICv7e2fNqvXdQGT 14 | Ny/mlYZiznmGEYmRIITuyfUiXC+aUEzvtcQcZTnKMMqETEbUdLz3XwNIZ0feh8Gr 15 | cztlgLY4g8zkPGZ8cYRMWuY+++jWgERDJMb6dlG0dPQsqmKwNeCC+RECgYEAyA4k 16 | 2eaTO2pjmLPftwDEpghqtCS9gLPxCZEiAlRR2tlK1lk5L5f9i3wYcx0ZWS0CHD/W 17 | jBj5RlPYao+vLK/GOA/QyDrMzwvrIKq700IEDqvz0axVGEhV2LrtW+5D9jE9py5t 18 | f90jzy9cfjzwsorhqj49zS2aSMzSJFvXLRPqrKUCgYEAj9kHJgPI4123z5Pax5AO 19 | KwhDbrxEFQT0IuovIZhaQPxwTC8lB9EtjZx5aYX/2HJzBaKVpaWizoVLrveDDK00 20 | 6Y8YMwJN3+mYDk7OU2/mHMSRPy4u6AGCAP5rkZVnvnqjFjr30pG0YlDd8Np7cQPQ 21 | phdT9imh0KCbfGdSMzDtjpECgYBP+t+ewgEQ2vrQfPEuv77exjSqqpmcj9QIyB45 22 | oi5LeV3jDi6/qVszXbyEoRiWP1k9pAQJZJ6cED9QcvtMuUVc+m2071UcXZ52I+wN 23 | jLIEj5hdtjEbEShJCoqEm2BOV+dXJEegu+9qEHxA9+oe50lK/7FDizzIaCKHaLRB 24 | EFpdBQKBgGmV/X7pLS244Hmbt4HXLIzAE5CQg5IIdUKT+v0Ih3Hz3Ku1VlIZYnZ5 25 | 5NdULo5O79CkOBug5sSpd+AI8Q36qvzmLArcooFhmhpS/aCr8oZceJrcmb2Q8W2U 26 | fYM9Mj+KNIR883dk20/y2S96OpqmT4FVp7TH+S0qwKHbJsZZDmIi 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /build/lib/common.mk: -------------------------------------------------------------------------------- 1 | # Tencent is pleased to support the open source community by making TKEStack 2 | # available. 3 | # 4 | # Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | # this file except in compliance with the License. You may obtain a copy of the 8 | # License at 9 | # 10 | # https://opensource.org/licenses/Apache-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations under the License. 16 | 17 | SHELL := /bin/bash 18 | 19 | # include the common make file 20 | COMMON_SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 21 | 22 | ifeq ($(origin ROOT_DIR),undefined) 23 | ROOT_DIR := $(abspath $(shell cd $(COMMON_SELF_DIR)/../.. && pwd -P)) 24 | endif 25 | ifeq ($(origin OUTPUT_DIR),undefined) 26 | OUTPUT_DIR := $(ROOT_DIR)/_output 27 | $(shell mkdir -p $(OUTPUT_DIR)) 28 | endif 29 | ifeq ($(origin TOOLS_DIR),undefined) 30 | TOOLS_DIR := $(OUTPUT_DIR)/tools 31 | $(shell mkdir -p $(TOOLS_DIR)) 32 | endif 33 | ifeq ($(origin TMP_DIR),undefined) 34 | TMP_DIR := $(OUTPUT_DIR)/tmp 35 | $(shell mkdir -p $(TMP_DIR)) 36 | endif 37 | 38 | # set the version number. you should not need to do this 39 | # for the majority of scenarios. 40 | ifeq ($(origin VERSION), undefined) 41 | VERSION := $(shell git describe --dirty --always --tags | sed 's/-/./g') 42 | endif 43 | GIT_COMMIT:=$(shell git log --first-parent -1 --oneline | awk '{print $$1}') 44 | 45 | PLATFORMS ?= linux_amd64 linux_arm64 46 | 47 | # Set a specific PLATFORM 48 | # Target OS must be linux 49 | ifeq ($(origin PLATFORM), undefined) 50 | ifeq ($(origin GOOS), undefined) 51 | GOOS := linux 52 | endif 53 | ifeq ($(origin GOARCH), undefined) 54 | GOARCH := $(shell go env GOARCH) 55 | endif 56 | PLATFORM := $(GOOS)_$(GOARCH) 57 | else 58 | GOOS := $(word 1, $(subst _, ,$(PLATFORM))) 59 | GOARCH := $(word 2, $(subst _, ,$(PLATFORM))) 60 | endif 61 | 62 | COMMA := , 63 | SPACE := 64 | SPACE += 65 | -------------------------------------------------------------------------------- /build/lib/create-manifest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Tencent is pleased to support the open source community by making TKEStack 4 | # available. 5 | # 6 | # Copyright (C) 2012-2019 Tencent. All Rights Reserved. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use 9 | # this file except in compliance with the License. You may obtain a copy of the 10 | # License at 11 | # 12 | # https://opensource.org/licenses/Apache-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16 | # WARRANTIES OF ANY KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations under the License. 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | REGISTRY_PREFIX=${REGISTRY_PREFIX:-"tkestack"} 24 | PLATFORMS=${PLATFORMS:-"linux_amd64 linux_arm64"} 25 | 26 | if [ -z ${IMAGE} ]; then 27 | echo "Please provide IMAGE." 28 | exit 1 29 | fi 30 | 31 | if [ -z ${VERSION} ]; then 32 | echo "Please provide VERSION." 33 | exit 1 34 | fi 35 | 36 | rm -rf ${HOME}/.docker/manifests/docker.io_${REGISTRY_PREFIX}_${IMAGE}-${VERSION} 37 | DES_REGISTRY=${REGISTRY_PREFIX}/${IMAGE} 38 | for platform in ${PLATFORMS}; do 39 | os=${platform%_*} 40 | arch=${platform#*_} 41 | variant="" 42 | if [ ${arch} == "arm64" ]; then 43 | variant="--variant unknown" 44 | fi 45 | 46 | docker manifest create --amend ${DES_REGISTRY}:${VERSION} \ 47 | ${DES_REGISTRY}-${arch}:${VERSION} 48 | 49 | docker manifest annotate ${DES_REGISTRY}:${VERSION} \ 50 | ${DES_REGISTRY}-${arch}:${VERSION} \ 51 | --os ${os} --arch ${arch} ${variant} 52 | done 53 | docker manifest push --purge ${DES_REGISTRY}:${VERSION} -------------------------------------------------------------------------------- /build/lib/image.mk: -------------------------------------------------------------------------------- 1 | # Tencent is pleased to support the open source community by making TKEStack 2 | # available. 3 | # 4 | # Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | # this file except in compliance with the License. You may obtain a copy of the 8 | # License at 9 | # 10 | # https://opensource.org/licenses/Apache-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations under the License. 16 | 17 | # ============================================================================== 18 | # Makefile helper functions for docker image 19 | 20 | DOCKER := DOCKER_CLI_EXPERIMENTAL=enabled docker 21 | DOCKER_SUPPORTED_API_VERSION ?= 1.40 22 | DOCKER_VERSION ?= 19.03 23 | 24 | REGISTRY_PREFIX ?= tkestack 25 | 26 | EXTRA_ARGS ?= 27 | _DOCKER_BUILD_EXTRA_ARGS := 28 | 29 | ifdef HTTP_PROXY 30 | _DOCKER_BUILD_EXTRA_ARGS += --build-arg http_proxy=${HTTP_PROXY} 31 | endif 32 | ifdef HTTPS_PROXY 33 | _DOCKER_BUILD_EXTRA_ARGS += --build-arg https_proxy=${HTTPS_PROXY} 34 | endif 35 | 36 | ifneq ($(EXTRA_ARGS), ) 37 | _DOCKER_BUILD_EXTRA_ARGS += $(EXTRA_ARGS) 38 | endif 39 | 40 | .PHONY: image.verify 41 | image.verify: 42 | $(eval API_VERSION := $(shell $(DOCKER) version | grep -E 'API version: {1,6}[0-9]' | head -n1 | awk '{print $$3} END { if (NR==0) print 0}' )) 43 | $(eval PASS := $(shell echo "$(API_VERSION) >= $(DOCKER_SUPPORTED_API_VERSION)" | bc)) 44 | @if [ $(PASS) -ne 1 ]; then \ 45 | $(DOCKER) -v ;\ 46 | echo "Unsupported docker version. Docker API version should be greater than $(DOCKER_SUPPORTED_API_VERSION) (Or docker version: $(DOCKER_VERSION))"; \ 47 | exit 1; \ 48 | fi 49 | 50 | .PHONY: image.buildx.verify 51 | image.buildx.verify: image.verify 52 | $(eval PASS := $(shell $(DOCKER) buildx version > /dev/null && echo 1 || echo 0)) 53 | @if [ $(PASS) -ne 1 ]; then \ 54 | $(MAKE) image.buildx.install; \ 55 | fi 56 | 57 | .PHONY: image.buildx.install 58 | image.buildx.install: 59 | @$(ROOT_DIR)/build/lib/install-buildx.sh 60 | 61 | .PHONY: image.build 62 | image.build: image.buildx.verify $(addprefix image.build., $(addprefix $(PLATFORM)., $(BINS))) 63 | 64 | .PHONY: image.build.multiarch 65 | image.build.multiarch: image.buildx.verify $(foreach p,$(PLATFORMS),$(addprefix image.build., $(addprefix $(p)., $(BINS)))) 66 | 67 | .PHONY: image.build.% 68 | image.build.%: 69 | $(eval PLATFORM := $(word 1,$(subst ., ,$*))) 70 | $(eval IMAGE := $(word 2,$(subst ., ,$*))) 71 | $(eval OS := $(word 1,$(subst _, ,$(PLATFORM)))) 72 | $(eval ARCH := $(word 2,$(subst _, ,$(PLATFORM)))) 73 | $(eval IMAGE_PLAT := $(subst _,/,$(PLATFORM))) 74 | $(eval IMAGE_NAME := $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION)) 75 | @echo "===========> Building docker image $(IMAGE) $(VERSION) for $(IMAGE_PLAT)" 76 | $(DOCKER) buildx build --platform $(IMAGE_PLAT) --load -t $(IMAGE_NAME) $(_DOCKER_BUILD_EXTRA_ARGS) \ 77 | -f $(ROOT_DIR)/build/docker/Dockerfile_arch $(ROOT_DIR) 78 | 79 | .PHONY: image.push 80 | image.push: image.buildx.verify $(addprefix image.push., $(addprefix $(PLATFORM)., $(BINS))) 81 | 82 | .PHONY: image.push.multiarch 83 | image.push.multiarch: image.buildx.verify $(foreach p,$(PLATFORMS),$(addprefix image.push., $(addprefix $(p)., $(BINS)))) 84 | 85 | .PHONY: image.push.% 86 | image.push.%: image.build.% 87 | @echo "===========> Pushing image $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX)" 88 | $(DOCKER) push $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) 89 | 90 | .PHONY: image.manifest.push 91 | image.manifest.push: export DOCKER_CLI_EXPERIMENTAL := enabled 92 | image.manifest.push: image.buildx.verify $(addprefix image.manifest.push., $(addprefix $(PLATFORM)., $(BINS))) 93 | 94 | .PHONY: image.manifest.push.% 95 | image.manifest.push.%: image.push.% image.manifest.remove.% 96 | @echo "===========> Pushing manifest $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" 97 | @$(DOCKER) manifest create $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ 98 | $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) 99 | @$(DOCKER) manifest annotate $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ 100 | $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) \ 101 | --os $(OS) --arch ${ARCH} 102 | @$(DOCKER) manifest push --purge $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) 103 | 104 | # Docker cli has a bug: https://github.com/docker/cli/issues/954 105 | # If you find your manifests were not updated, 106 | # Please manually delete them in $HOME/.docker/manifests/ 107 | # and re-run. 108 | .PHONY: image.manifest.remove.% 109 | image.manifest.remove.%: 110 | @rm -rf ${HOME}/.docker/manifests/docker.io_$(REGISTRY_PREFIX)_$(IMAGE)-$(VERSION) 111 | 112 | .PHONY: image.manifest.push.multiarch 113 | image.manifest.push.multiarch: image.push.multiarch $(addprefix image.manifest.push.multiarch., $(BINS)) 114 | 115 | .PHONY: image.manifest.push.multiarch.% 116 | image.manifest.push.multiarch.%: 117 | @echo "===========> Pushing manifest $* $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" 118 | REGISTRY_PREFIX=$(REGISTRY_PREFIX) PLATFROMS="$(PLATFORMS)" IMAGE=$* VERSION=$(VERSION) DOCKER_CLI_EXPERIMENTAL=enabled \ 119 | $(ROOT_DIR)/build/lib/create-manifest.sh 120 | -------------------------------------------------------------------------------- /build/lib/install-buildx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Tencent is pleased to support the open source community by making TKEStack 4 | # available. 5 | # 6 | # Copyright (C) 2012-2019 Tencent. All Rights Reserved. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use 9 | # this file except in compliance with the License. You may obtain a copy of the 10 | # License at 11 | # 12 | # https://opensource.org/licenses/Apache-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16 | # WARRANTIES OF ANY KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations under the License. 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | BUILDX_VERSION=${BUILDX_VERSION:-"v0.4.1"} 24 | ARCH=${ARCH:-"amd64"} 25 | BUILDX_BIN="https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-${ARCH}" 26 | 27 | echo "Downloading docker-buildx" 28 | wget -c ${BUILDX_BIN} -O ./docker-buildx 29 | mkdir -p ~/.docker/cli-plugins/ 30 | mv ./docker-buildx ~/.docker/cli-plugins/ 31 | chmod a+x ~/.docker/cli-plugins/docker-buildx 32 | docker buildx version -------------------------------------------------------------------------------- /deployment/cron-hpa-controller/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: cronhpas.extensions.tkestack.io 5 | spec: 6 | group: extensions.tkestack.io 7 | version: v1 8 | names: 9 | kind: CronHPA 10 | listKind: CronHPAList 11 | plural: cronhpas 12 | singular: cronhpa 13 | scope: Namespaced 14 | -------------------------------------------------------------------------------- /deployment/cron-hpa-controller/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: cron-hpa-controller 5 | labels: 6 | app: cron-hpa-controller 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: cron-hpa-controller 12 | template: 13 | metadata: 14 | labels: 15 | app: cron-hpa-controller 16 | spec: 17 | containers: 18 | - name: cron-hpa-controller 19 | image: "{{ .Values.image.repository }}/kube-batch:{{ .Values.image.tag }}" 20 | args: ["--logtostderr", "--v", "3"] 21 | imagePullPolicy: {{ .Values.image.pullPolicy }} 22 | resources: 23 | {{ toYaml .Values.resources | indent 10 }} 24 | -------------------------------------------------------------------------------- /design.md: -------------------------------------------------------------------------------- 1 | # Cron Horizontal Pod Autoscaler 2 | 3 | Table of Contents 4 | ================= 5 | 6 | * [Cron Horizontal Pod Autoscaler](#cron-horizontal-pod-autoscaler) 7 | * [Summary](#summary) 8 | * [Motivation](#motivation) 9 | * [Goals](#goals) 10 | * [Non-Goals](#non-goals) 11 | * [Proposal](#proposal) 12 | * [User Stories](#user-stories) 13 | * [Story 1](#story-1) 14 | * [Story 2](#story-2) 15 | * [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints) 16 | * [Future work](#future-work) 17 | 18 | ## Summary 19 | 20 | Cron Horizontal Pod Autoscaler(CronHPA) enables us to auto scale workloads(those support `scale`subresource, e.g. deployment, statefulset) periodically using [crontab](https://en.wikipedia.org/wiki/Cron) scheme. 21 | 22 | ## Motivation 23 | 24 | A lot of game players will play games from Friday evening to Sunday evening. It will be better to provide a better experience for players if game servers(pods) could be scaled to a lager size at Friday evening and scaled to normal size at Sunday evening. And that's what game server admins do every week. 25 | 26 | Some other customers also do similar things because their products' usage also have peaks and valleys periodically. Time based auto scheduler could scale pods in advance, and will provide a better experience for users. CronHPA is for their requirement. 27 | 28 | ### Goals 29 | 30 | * Users could auto scale their workloads those support `scale` subresource periodically using crontab scheme. 31 | 32 | ### Non-Goals 33 | 34 | * CronHPA does not support workloads that does not support `scale` subresource now. 35 | 36 | ## Proposal 37 | 38 | At first, we'd like to use [CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) to implement this feature. Howerver `CronJob` only supports one `schedule` and users must specify an image and commands, it will be a little inappropriate for above use cases. 39 | 40 | We propose a new CRD `CronHPA` which is inspired by `CronJob` (thanks a lot!) to meet users' requirement. Users could specify as many `schedule`s as they want. 41 | 42 | `CronHPA` example: 43 | 44 | ``` 45 | apiVersion: extensions.tkestack.io/v1 46 | kind: CronHPA 47 | metadata: 48 | name: example-cron-hpa 49 | spec: 50 | scaleTargetRef: 51 | apiVersion: apps/v1 52 | kind: Deployment 53 | name: demo-deployment 54 | crons: 55 | - schedule: "0 23 * * 5" // Set replicas to 60 every Friday 23:00 56 | targetReplicas: 60 57 | - schedule: "0 23 * * 7" // Set replicas to 30 every Sunday 23:00 58 | targetReplicas: 30 59 | ``` 60 | 61 | ### User Stories 62 | 63 | #### Story 1 64 | 65 | As a game server admin, I find there will be a lot of game players logining to our servers and playing games from Friday 20:00 to Sunday 23:00 every week, I'd better to auto scale game servers at that time. And I will use following `CronHPA` to solve my problem. 66 | 67 | ``` 68 | apiVersion: extensions.tkestack.io/v1 69 | kind: CronHPA 70 | metadata: 71 | name: game-servers-cronhpa 72 | spec: 73 | scaleTargetRef: 74 | apiVersion: apps/v1 75 | kind: Deployment 76 | name: game-servers 77 | crons: 78 | - schedule: "0 20 * * 5" // Set replicas to 60 every Friday 20:00 79 | targetReplicas: 60 80 | - schedule: "0 23 * * 7" // Set replicas to 30 every Sunday 23:00 81 | targetReplicas: 30 82 | ``` 83 | 84 | #### Story 2 85 | 86 | As a web server admin, I find pageviews for my web is high at every day 8:00~9:00 am and 7:00~9:00 pm. And I will use following `CronHPA` to solve my problem. 87 | 88 | ``` 89 | apiVersion: extensions.tkestack.io/v1 90 | kind: CronHPA 91 | metadata: 92 | name: web-servers-cronhpa 93 | spec: 94 | scaleTargetRef: 95 | apiVersion: apps/v1 96 | kind: Deployment 97 | name: web-servers 98 | crons: 99 | - schedule: "0 8 * * *" // Set replicas to 60 every day 8:00 100 | targetReplicas: 60 101 | - schedule: "0 9 * * *" // Set replicas to 10 every day 9:00 102 | targetReplicas: 10 103 | - schedule: "0 19 * * *" // Set replicas to 60 every day 19:00 104 | targetReplicas: 60 105 | - schedule: "0 21 * * *" // Set replicas to 10 every day 21:00 106 | targetReplicas: 10 107 | ``` 108 | 109 | ### Implementation Details/Notes/Constraints 110 | 111 | We have implenented the corresponding controller manager which is similar to `CroJob` controller manager. 112 | 113 | CRD `CronHPA` realated data structure is defined as following: 114 | 115 | ``` 116 | // CronHPA represents a set of crontabs to set target's replicas. 117 | type CronHPA struct { 118 | metav1.TypeMeta `json:",inline"` 119 | metav1.ObjectMeta `json:"metadata,omitempty"` 120 | 121 | // Spec defines the desired identities of pods in this cronhpa. 122 | Spec CronHPASpec `json:"spec,omitempty"` 123 | 124 | // Status is the current status of pods in this CronHPA. This data 125 | // may be out of date by some window of time. 126 | Status CronHPAStatus `json:"status,omitempty"` 127 | } 128 | 129 | // A CronHPASpec is the specification of a CronHPA. 130 | type CronHPASpec struct { 131 | // scaleTargetRef points to the target resource to scale 132 | ScaleTargetRef autoscalingv2.CrossVersionObjectReference `json:"scaleTargetRef" protobuf:"bytes,1,opt,name=scaleTargetRef"` 133 | 134 | Crons []Cron `json:"crons" protobuf:"bytes,2,opt,name=crons"` 135 | } 136 | 137 | type Cron struct { 138 | // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. 139 | Schedule string `json:"schedule" protobuf:"bytes,1,opt,name=schedule"` 140 | 141 | TargetReplicas int32 `json:"targetReplicas" protobuf:"varint,2,opt,name=targetReplicas"` 142 | } 143 | 144 | // CronHPAStatus represents the current state of a CronHPA. 145 | type CronHPAStatus struct { 146 | // Information when was the last time the schedule was successfully scheduled. 147 | // +optional 148 | LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty" protobuf:"bytes,2,opt,name=lastScheduleTime"` 149 | } 150 | 151 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 152 | 153 | // CronHPAList is a collection of CronHPA. 154 | type CronHPAList struct { 155 | metav1.TypeMeta `json:",inline"` 156 | metav1.ListMeta `json:"metadata,omitempty"` 157 | Items []CronHPA `json:"items"` 158 | } 159 | ``` 160 | 161 | In the conroller, it will list `CronHPA` periodically, and scale workloads using `scale` subresource if needed. 162 | 163 | ## Future work 164 | 165 | We will try to integrate `HPA` and `CronHPA` for a better experience. 166 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module tkestack.io/cron-hpa 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/coreos/etcd v3.3.25+incompatible // indirect 7 | github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible // indirect 8 | github.com/evanphx/json-patch v4.1.0+incompatible // indirect 9 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect 10 | github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 // indirect 11 | github.com/imdario/mergo v0.3.5 // indirect 12 | github.com/onsi/ginkgo v1.16.3 // indirect 13 | github.com/onsi/gomega v1.13.0 // indirect 14 | github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420 // indirect 15 | github.com/pborman/uuid v1.2.1 // indirect 16 | github.com/peterbourgon/diskv v2.0.1+incompatible // indirect 17 | github.com/prometheus/client_golang v1.10.0 // indirect 18 | github.com/robfig/cron v1.2.0 19 | github.com/spf13/afero v1.6.0 // indirect 20 | github.com/spf13/pflag v1.0.3 21 | github.com/stretchr/testify v1.7.0 // indirect 22 | google.golang.org/grpc v1.38.0 // indirect 23 | gopkg.in/inf.v0 v0.9.0 // indirect 24 | gopkg.in/square/go-jose.v2 v2.1.7-0.20180411045311-89060dee6a84 // indirect 25 | k8s.io/api v0.0.0-20181221193117-173ce66c1e39 26 | k8s.io/apiextensions-apiserver v0.0.0-20181221201254-261a947e2c38 27 | k8s.io/apimachinery v0.0.0-20181220065808-98853ca904e8 28 | k8s.io/apiserver v0.0.0-20181228033655-459e5d098d2b 29 | k8s.io/client-go v0.0.0-20181228233426-7856fdbcc3be 30 | k8s.io/klog v0.1.1-0.20181227134420-3aab9e5c735f 31 | k8s.io/kube-openapi v0.0.0-20181109181836-c59034cc13d5 // indirect 32 | k8s.io/kubernetes v1.14.0-alpha.0.0.20181229071411-173846b056a6 33 | k8s.io/utils v0.0.0-20180726175726-66066c83e385 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /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 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 6 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 7 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 8 | github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= 9 | github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= 10 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 11 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 12 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 13 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 14 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 15 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 16 | github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 17 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 18 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 19 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 20 | github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= 21 | github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= 22 | github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 23 | github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= 24 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 25 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 26 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 27 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 28 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 29 | github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= 30 | github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 31 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 32 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 33 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 34 | github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 35 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 36 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 37 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= 38 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= 39 | github.com/coreos/etcd v3.3.25+incompatible h1:0GQEw6h3YnuOVdtwygkIfJ+Omx0tZ8/QkVyXI4LkbeY= 40 | github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 41 | github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= 42 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 43 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= 44 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 45 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf h1:CAKfRE2YtTUIjjh1bkBtyYFaUT/WmOqsJjgtihT0vMI= 46 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 47 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 48 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 49 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 50 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 51 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 52 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 53 | github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible h1:357nGVUC8gSpeSc2Axup8HfrfTLLUfWfCsCUhiQSKIg= 54 | github.com/docker/distribution v2.6.0-rc.1.0.20170726174610-edc3ab29cdff+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 55 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 56 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 57 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 58 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 59 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 60 | github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 61 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 62 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 63 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 64 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 65 | github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= 66 | github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 67 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 68 | github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= 69 | github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= 70 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 71 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 72 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 73 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 74 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 75 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 76 | github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= 77 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 78 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 79 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 80 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 81 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 82 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 83 | github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= 84 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 85 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 86 | github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= 87 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 88 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 89 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 90 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= 91 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 92 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 93 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 94 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 95 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 96 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 97 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 98 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 99 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 100 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 101 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 102 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 103 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 104 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 105 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 106 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 107 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 108 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 109 | github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 110 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 111 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 112 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 113 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 114 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 115 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 116 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 117 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 118 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 119 | github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= 120 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 121 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 122 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 123 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 124 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 125 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= 126 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 127 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 128 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 129 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 130 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 131 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 132 | github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w= 133 | github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 134 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 135 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= 136 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 137 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 138 | github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= 139 | github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 140 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 141 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 142 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 143 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 144 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 145 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 146 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 147 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 148 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 149 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 150 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 151 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 152 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 153 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 154 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 155 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 156 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 157 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 158 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 159 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 160 | github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= 161 | github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= 162 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 163 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 164 | github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= 165 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 166 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 167 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 168 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 169 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 170 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 171 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 172 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 173 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 174 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 175 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 176 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 177 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 178 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 179 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 180 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 181 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 182 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 183 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 184 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 185 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 186 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 187 | github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= 188 | github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= 189 | github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= 190 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 191 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 192 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 193 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 194 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 195 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 196 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 197 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 198 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 199 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 200 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 201 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 202 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 203 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 204 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 205 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 206 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 207 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 208 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 209 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 210 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 211 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 212 | github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= 213 | github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= 214 | github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= 215 | github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= 216 | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 217 | github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 218 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 219 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 220 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 221 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 222 | github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= 223 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 224 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 225 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 226 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 227 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 228 | github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= 229 | github.com/onsi/ginkgo v1.16.3 h1:3s86PZkI1ApJh6HFIzC1gXby/mIyZqfE5zxSvtoBSsM= 230 | github.com/onsi/ginkgo v1.16.3/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= 231 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 232 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 233 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 234 | github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= 235 | github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= 236 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 237 | github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420 h1:Yu3681ykYHDfLoI6XVjL4JWmkE+3TX9yfIWwRCh1kFM= 238 | github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 239 | github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= 240 | github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= 241 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 242 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 243 | github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= 244 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 245 | github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= 246 | github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= 247 | github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= 248 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 249 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 250 | github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= 251 | github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 252 | github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= 253 | github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= 254 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 255 | github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= 256 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 257 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 258 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 259 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 260 | github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= 261 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 262 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 263 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 264 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 265 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 266 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 267 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 268 | github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= 269 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 270 | github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= 271 | github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= 272 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 273 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 274 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 275 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 276 | github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 277 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 278 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 279 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 280 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 281 | github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= 282 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 283 | github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y= 284 | github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= 285 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 286 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 287 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 288 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 289 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 290 | github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= 291 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 292 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 293 | github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= 294 | github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= 295 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 296 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 297 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 298 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 299 | github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= 300 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 301 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 302 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 303 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 304 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 305 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 306 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 307 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 308 | github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= 309 | github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= 310 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 311 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 312 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 313 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 314 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 315 | github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 316 | github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 317 | github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= 318 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 319 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 320 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 321 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 322 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 323 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 324 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 325 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 326 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 327 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 328 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 329 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 330 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 331 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 332 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= 333 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 334 | go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 335 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 336 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 337 | go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= 338 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 339 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 340 | go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= 341 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 342 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= 343 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 344 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 345 | go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= 346 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 347 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 348 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 349 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 350 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 351 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 352 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 353 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 354 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 355 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 356 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 357 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 358 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 359 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 360 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 361 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 362 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 363 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 364 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 365 | golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= 366 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 367 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 368 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 369 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 370 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 371 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 372 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 373 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 374 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 375 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 376 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 377 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 378 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 379 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 380 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 381 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 382 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 383 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 384 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 385 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 386 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= 387 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 388 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 389 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= 390 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 391 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 392 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 393 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 394 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 395 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 396 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 397 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 398 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 399 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 400 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 401 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 402 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 403 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 404 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 405 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 406 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 407 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 408 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 409 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 410 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 411 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 412 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 413 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 414 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 415 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 416 | golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 417 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 418 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 419 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 420 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 421 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 422 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 423 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 424 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 425 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 426 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= 427 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 428 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 429 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 430 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 431 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 432 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 433 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 434 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 435 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= 436 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 437 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 438 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 439 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 440 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 441 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 442 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 443 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 444 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 445 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 446 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 447 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 448 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 449 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 450 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 451 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= 452 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 453 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 454 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 455 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 456 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 457 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 458 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 459 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 460 | google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 461 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= 462 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 463 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 464 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 465 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 466 | google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 467 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 468 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 469 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 470 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 471 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 472 | google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 473 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 474 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 475 | google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 476 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 477 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 478 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 479 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 480 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 481 | google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= 482 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 483 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 484 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 485 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 486 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 487 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 488 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 489 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 490 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 491 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 492 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 493 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 494 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 495 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 496 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 497 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 498 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 499 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 500 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 501 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 502 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 503 | gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= 504 | gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= 505 | gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 506 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 507 | gopkg.in/square/go-jose.v2 v2.1.7-0.20180411045311-89060dee6a84 h1:FyyRwUG3E9uRnGzcuQrZYcOCjcmFUtMN/SYawfb+08Y= 508 | gopkg.in/square/go-jose.v2 v2.1.7-0.20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 509 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 510 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 511 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 512 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 513 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 514 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 515 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 516 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 517 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 518 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 519 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 520 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 521 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 522 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 523 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 524 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 525 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= 526 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 527 | k8s.io/api v0.0.0-20181221193117-173ce66c1e39 h1:iGq7zEPXFb0IeXAQK5RiYT1SVKX/af9F9Wv0M+yudPY= 528 | k8s.io/api v0.0.0-20181221193117-173ce66c1e39/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= 529 | k8s.io/apiextensions-apiserver v0.0.0-20181221201254-261a947e2c38 h1:SdLKoAFmrkExcKa/ypTCKH1O0nS1RT9h2o+CEyzgvcY= 530 | k8s.io/apiextensions-apiserver v0.0.0-20181221201254-261a947e2c38/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= 531 | k8s.io/apimachinery v0.0.0-20181220065808-98853ca904e8 h1:WLypux0abPAfOJJKJNA1+g5yphAOk+ESOeSqWMwMnqA= 532 | k8s.io/apimachinery v0.0.0-20181220065808-98853ca904e8/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= 533 | k8s.io/apiserver v0.0.0-20181228033655-459e5d098d2b h1:xVLrS6h9zy+Nz/iK7K3YZA7F8FRLaD19+wf6an5cGBs= 534 | k8s.io/apiserver v0.0.0-20181228033655-459e5d098d2b/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= 535 | k8s.io/client-go v0.0.0-20181228233426-7856fdbcc3be h1:tVLMFPfMjoGBG9yv3UUtvstg5ViFmraGWcC9ADtkeh8= 536 | k8s.io/client-go v0.0.0-20181228233426-7856fdbcc3be/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= 537 | k8s.io/klog v0.1.1-0.20181227134420-3aab9e5c735f h1:XeRcm2cZrNNeohFgdhTu5mK8g5hq8xheDoY1iHi06jI= 538 | k8s.io/klog v0.1.1-0.20181227134420-3aab9e5c735f/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 539 | k8s.io/kube-openapi v0.0.0-20181109181836-c59034cc13d5 h1:MH8SvyTlIiLt8b1oHy4Dtp1zPpLGp6lTOjvfzPTkoQE= 540 | k8s.io/kube-openapi v0.0.0-20181109181836-c59034cc13d5/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= 541 | k8s.io/kubernetes v1.14.0-alpha.0.0.20181229071411-173846b056a6 h1:rG3z+qSN0SU9ltolv2PY18gqK1KzhUY9u5R19QQyavc= 542 | k8s.io/kubernetes v1.14.0-alpha.0.0.20181229071411-173846b056a6/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= 543 | k8s.io/utils v0.0.0-20180726175726-66066c83e385 h1:q6/yuHLLw/uZczdu8EHklikYXSpvKeoqLlt2k99lUUU= 544 | k8s.io/utils v0.0.0-20180726175726-66066c83e385/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= 545 | sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= 546 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 547 | sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= 548 | -------------------------------------------------------------------------------- /hack/build-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -o errexit 16 | set -o nounset 17 | set -o pipefail 18 | 19 | BIN="build/docker/cron-hpa-controller" 20 | 21 | go get github.com/mitchellh/gox 22 | 23 | CGO_ENABLED=0 gox -osarch="linux/amd64" -output=$BIN 24 | docker build build/docker/ -t tkestack/cron-hpa-controller:v1.0.0 25 | rm $BIN 26 | -------------------------------------------------------------------------------- /hack/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -o errexit 16 | set -o nounset 17 | set -o pipefail 18 | 19 | CGO_ENABLED=0 go build -o bin/cron-hpa-controller . 20 | if [ $? -eq 0 ]; then 21 | echo "Build success!" 22 | else 23 | echo "Faild to build!" 24 | fi 25 | -------------------------------------------------------------------------------- /hack/gencerts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # Generate a (self-signed) CA certificate and a certificate and private key to be used by the webhook server. 18 | # The certificate will be issued for the Common Name (CN) of `webhook-server.{namespace}.svc`, which is the 19 | # cluster-internal DNS name for the service. 20 | # 21 | 22 | set -e 23 | set -x 24 | 25 | if [ $# -ne 2 ]; then 26 | echo "Usage: $0 $key_dir $namespace" 27 | echo " key_dir: used to put certs in" 28 | echo " namespace: the namespace that webhook-server will be deployed in" 29 | exit 1 30 | fi 31 | 32 | key_dir="$1" 33 | namespace="$2" 34 | 35 | mkdir -p $key_dir 36 | chmod 0700 $key_dir 37 | cd $key_dir 38 | 39 | SANCNF=san.cnf 40 | 41 | cat << EOF > ${SANCNF} 42 | [req] 43 | distinguished_name = req_distinguished_name 44 | req_extensions = v3_req 45 | prompt = no 46 | 47 | [req_distinguished_name] 48 | C = CN 49 | O = tkestack 50 | CN = cron-hpa-controller.kube-system.svc 51 | 52 | [v3_req] 53 | keyUsage = critical, digitalSignature, keyEncipherment 54 | extendedKeyUsage = clientAuth, serverAuth 55 | subjectAltName = @alt_names 56 | [alt_names] 57 | DNS.1=cron-hpa-controller.kube-system.svc 58 | EOF 59 | 60 | # Generate the CA cert and private key 61 | openssl req -nodes -new -x509 -days 100000 -keyout ca.key -out ca.crt -subj "/CN=Admission Webhook Server CA" 62 | # Generate the private key for the webhook server 63 | openssl genrsa -out tls.key 2048 64 | # Generate a Certificate Signing Request (CSR) for the private key, and sign it with the private key of the CA. 65 | openssl req -new -sha256 -days 100000 -key tls.key -subj "/cron-hpa-controller.kube-system.svc" -reqexts v3_req -config ${SANCNF} \ 66 | | openssl x509 -req -days 100000 -CA ca.crt -CAkey ca.key -CAcreateserial -extensions v3_req -extfile ${SANCNF} -out tls.crt 67 | -------------------------------------------------------------------------------- /hack/lib/lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | find_files() { 16 | find . -not \( \ 17 | \( \ 18 | -wholename './output' \ 19 | -o -wholename './_output' \ 20 | -o -wholename './_gopath' \ 21 | -o -wholename './release' \ 22 | -o -wholename './target' \ 23 | -o -wholename '*/third_party/*' \ 24 | -o -wholename '*/vendor/*' \ 25 | -o -wholename './staging' \ 26 | -o -wholename './pkg/client' \ 27 | \) -prune \ 28 | \) -name '*.go' 29 | } 30 | -------------------------------------------------------------------------------- /hack/update-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | set -x 21 | 22 | SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. 23 | CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../../../k8s.io/code-generator)} 24 | 25 | # generate the code with: 26 | # --output-base because this script should also be able to run inside the vendor dir of 27 | # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir 28 | # instead of the $GOPATH directly. For normal projects this can be dropped. 29 | ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ 30 | tkestack.io/cron-hpa/pkg/client tkestack.io/cron-hpa/pkg/apis \ 31 | cronhpacontroller:v1 \ 32 | --output-base "$(dirname ${BASH_SOURCE})/../../../../" 33 | 34 | # To use your own boilerplate text append: 35 | # --go-header-file ${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt 36 | -------------------------------------------------------------------------------- /hack/update-gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -o errexit 16 | set -o nounset 17 | set -o pipefail 18 | 19 | ROOT=$(cd $(dirname "${BASH_SOURCE}")/.. && pwd -P) 20 | source $ROOT/hack/lib/lib.sh 21 | 22 | echo $(find_files) | xargs -n 1 -I {} goimports -w {} 23 | -------------------------------------------------------------------------------- /hack/verify-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # GoFmt apparently is changing @ head... 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | ROOT=$(cd $(dirname "${BASH_SOURCE}")/.. && pwd -P) 22 | 23 | # verify gofmt 24 | ${ROOT}/hack/verify-gofmt.sh 25 | 26 | # verify codegen 27 | ${ROOT}/hack/verify-codegen.sh 28 | -------------------------------------------------------------------------------- /hack/verify-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. 22 | 23 | DIFFROOT="${SCRIPT_ROOT}/pkg" 24 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg" 25 | _tmp="${SCRIPT_ROOT}/_tmp" 26 | 27 | cleanup() { 28 | rm -rf "${_tmp}" 29 | } 30 | trap "cleanup" EXIT SIGINT 31 | 32 | cleanup 33 | 34 | mkdir -p "${TMP_DIFFROOT}" 35 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" 36 | 37 | "${SCRIPT_ROOT}/hack/update-codegen.sh" 38 | echo "diffing ${DIFFROOT} against freshly generated codegen" 39 | ret=0 40 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? 41 | cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" 42 | if [[ $ret -eq 0 ]] 43 | then 44 | echo "${DIFFROOT} up to date." 45 | else 46 | echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" 47 | exit 1 48 | fi 49 | -------------------------------------------------------------------------------- /hack/verify-gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # GoFmt apparently is changing @ head... 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | ROOT=$(cd $(dirname "${BASH_SOURCE}")/.. && pwd -P) 22 | source $ROOT/hack/lib/lib.sh 23 | 24 | GOFMT="gofmt -s" 25 | bad_files=$(find_files | xargs $GOFMT -l) 26 | if [[ -n "${bad_files}" ]]; then 27 | echo "!!! '$GOFMT -w' needs to be run on the following files: " 28 | echo "${bad_files}" 29 | echo "run 'git ls-files -m | grep .go | xargs -n1 gofmt -s -w' to format your own code" 30 | exit 1 31 | fi 32 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "context" 22 | "flag" 23 | "os" 24 | "time" 25 | 26 | "tkestack.io/cron-hpa/pkg/admission" 27 | clientset "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 28 | "tkestack.io/cron-hpa/pkg/cronhpa" 29 | "tkestack.io/cron-hpa/pkg/logs" 30 | 31 | "github.com/spf13/pflag" 32 | apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 | "k8s.io/apimachinery/pkg/util/wait" 35 | apiserverconfig "k8s.io/apiserver/pkg/apis/config" 36 | "k8s.io/client-go/kubernetes" 37 | restclient "k8s.io/client-go/rest" 38 | "k8s.io/client-go/tools/clientcmd" 39 | "k8s.io/client-go/tools/leaderelection" 40 | "k8s.io/client-go/tools/leaderelection/resourcelock" 41 | "k8s.io/klog" 42 | "k8s.io/kubernetes/pkg/client/leaderelectionconfig" 43 | controllerpkg "k8s.io/kubernetes/pkg/controller" 44 | ) 45 | 46 | const ( 47 | DefaultLeaseDuration = 15 * time.Second 48 | DefaultRenewDeadline = 10 * time.Second 49 | DefaultRetryPeriod = 2 * time.Second 50 | ) 51 | 52 | var ( 53 | masterURL string 54 | kubeconfig string 55 | createCRD bool 56 | // kubeAPIQPS is the QPS to use while talking with kubernetes apiserver. 57 | kubeAPIQPS float32 58 | // kubeAPIBurst is the burst to use while talking with kubernetes apiserver. 59 | kubeAPIBurst int 60 | // leaderElection defines the configuration of leader election client. 61 | leaderElection = apiserverconfig.LeaderElectionConfiguration{ 62 | LeaderElect: false, 63 | LeaseDuration: metav1.Duration{Duration: DefaultLeaseDuration}, 64 | RenewDeadline: metav1.Duration{Duration: DefaultRenewDeadline}, 65 | RetryPeriod: metav1.Duration{Duration: DefaultRetryPeriod}, 66 | ResourceLock: resourcelock.EndpointsResourceLock, 67 | } 68 | 69 | // Admission related config 70 | registerAdmission bool 71 | tlsCAfile string 72 | tlsCertFile string 73 | tlsKeyFile string 74 | listenAddress string 75 | // namespace to deploy CronHPA controller 76 | namespace string 77 | ) 78 | 79 | func main() { 80 | pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 81 | addFlags(pflag.CommandLine) 82 | pflag.Parse() 83 | 84 | logs.InitLogs() 85 | defer logs.FlushLogs() 86 | 87 | cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig) 88 | if err != nil { 89 | klog.Fatalf("Error building kubeconfig: %s", err.Error()) 90 | } 91 | cfg.QPS = kubeAPIQPS 92 | cfg.Burst = kubeAPIBurst 93 | 94 | kubeClient, err := kubernetes.NewForConfig(cfg) 95 | if err != nil { 96 | klog.Fatalf("Error building kubernetes clientset: %s", err.Error()) 97 | } 98 | 99 | cronhpaClient, err := clientset.NewForConfig(cfg) 100 | if err != nil { 101 | klog.Fatalf("Error building example clientset: %s", err.Error()) 102 | } 103 | 104 | extensionsClient, err := apiextensionsclient.NewForConfig(cfg) 105 | if err != nil { 106 | klog.Fatalf("Error instantiating apiextensions client: %s", err.Error()) 107 | } 108 | 109 | rootClientBuilder := controllerpkg.SimpleControllerClientBuilder{ 110 | ClientConfig: cfg, 111 | } 112 | 113 | controller, err := cronhpa.NewController(kubeClient, cronhpaClient, rootClientBuilder) 114 | if err != nil { 115 | klog.Fatalf("Failed to new controller: %s", err) 116 | } 117 | 118 | run := func(ctx context.Context) { 119 | if createCRD { 120 | wait.PollUntil(time.Second*5, func() (bool, error) { return cronhpa.EnsureCRDCreated(extensionsClient) }, ctx.Done()) 121 | } 122 | 123 | if registerAdmission { 124 | wait.PollImmediateUntil(time.Second*5, func() (bool, error) { 125 | return admission.Register(kubeClient, namespace, tlsCAfile) 126 | }, ctx.Done()) 127 | server, err := admission.NewServer(listenAddress, tlsCertFile, tlsKeyFile) 128 | if err != nil { 129 | klog.Fatalf("Error new admission server: %v", err) 130 | } 131 | go server.Run(ctx.Done()) 132 | } 133 | 134 | if err = controller.Run(ctx.Done()); err != nil { 135 | klog.Fatalf("Error running controller: %s", err.Error()) 136 | } 137 | } 138 | 139 | if !leaderElection.LeaderElect { 140 | run(context.Background()) 141 | panic("unreachable") 142 | } 143 | 144 | id, err := os.Hostname() 145 | if err != nil { 146 | klog.Fatalf("Failed to get hostname: %s", err.Error()) 147 | } 148 | 149 | leaderElectionClient := kubernetes.NewForConfigOrDie(restclient.AddUserAgent(cfg, "cron-hpa-leader-election")) 150 | rl, err := resourcelock.New(leaderElection.ResourceLock, 151 | "kube-system", 152 | "cron-hpa-controller", 153 | leaderElectionClient.CoreV1(), 154 | resourcelock.ResourceLockConfig{ 155 | Identity: id, 156 | EventRecorder: controller.GetEventRecorder(), 157 | }) 158 | if err != nil { 159 | klog.Fatalf("error creating lock: %v", err) 160 | } 161 | 162 | leaderelection.RunOrDie(context.Background(), leaderelection.LeaderElectionConfig{ 163 | Lock: rl, 164 | LeaseDuration: leaderElection.LeaseDuration.Duration, 165 | RenewDeadline: leaderElection.RenewDeadline.Duration, 166 | RetryPeriod: leaderElection.RetryPeriod.Duration, 167 | Callbacks: leaderelection.LeaderCallbacks{ 168 | OnStartedLeading: run, 169 | OnStoppedLeading: func() { 170 | klog.Fatalf("leaderelection lost") 171 | }, 172 | }, 173 | }) 174 | panic("unreachable") 175 | } 176 | 177 | func addFlags(fs *pflag.FlagSet) { 178 | fs.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") 179 | fs.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") 180 | fs.BoolVar(&createCRD, "create-crd", true, "Create cronhpa CRD if it does not exist") 181 | fs.Float32Var(&kubeAPIQPS, "kube-api-qps", kubeAPIQPS, "QPS to use while talking with kubernetes apiserver") 182 | fs.IntVar(&kubeAPIBurst, "kube-api-burst", kubeAPIBurst, "Burst to use while talking with kubernetes apiserver") 183 | 184 | // Admission related 185 | fs.BoolVar(®isterAdmission, "register-admission", false, "Register admission for CronHPA controller") 186 | fs.StringVar(&tlsCAfile, "tlsCAFile", "/etc/certs/ca.crt", "File containing the x509 CA for HTTPS") 187 | fs.StringVar(&listenAddress, "listen-address", ":8443", "The address to listen on for HTTP requests.") 188 | fs.StringVar(&tlsCertFile, "tlsCertFile", "/etc/certs/tls.crt", "File containing the x509 Certificate for HTTPS.") 189 | fs.StringVar(&tlsKeyFile, "tlsKeyFile", "/etc/certs/tls.key", "File containing the x509 private key to for HTTPS.") 190 | fs.StringVar(&namespace, "namespace", "kube-system", "Namespace to deploy tapp controller") 191 | 192 | leaderelectionconfig.BindFlags(&leaderElection, fs) 193 | } 194 | -------------------------------------------------------------------------------- /pkg/admission/admission.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package admission 19 | 20 | import ( 21 | "encoding/json" 22 | "fmt" 23 | "io/ioutil" 24 | "net/http" 25 | "reflect" 26 | 27 | "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller" 28 | cronhpav1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 29 | 30 | admissionv1beta1 "k8s.io/api/admission/v1beta1" 31 | admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" 32 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 | "k8s.io/client-go/kubernetes" 34 | "k8s.io/klog" 35 | ) 36 | 37 | const ( 38 | validatingWebhookConfiguration = "cron-hpa-admission" 39 | ) 40 | 41 | var validatePath = "/validate/cronhpa" 42 | var failPolicy admissionregistrationv1beta1.FailurePolicyType = "Fail" 43 | 44 | // Register registers the validatingWebhookConfiguration to kube-apiserver 45 | // Note: always return err as nil, it will be used by wait.PollUntil(). 46 | func Register(clientset *kubernetes.Clientset, namespace string, caFile string) (bool, error) { 47 | klog.Infof("Starting to register validatingWebhookConfiguration") 48 | defer func() { 49 | klog.Infof("Finished registering validatingWebhookConfiguration") 50 | }() 51 | 52 | caCert, err := ioutil.ReadFile(caFile) 53 | if err != nil { 54 | klog.Errorf("Failed to read certificate authority from %s: %v", caFile, err) 55 | return false, nil 56 | } 57 | 58 | webhookConfig := &admissionregistrationv1beta1.ValidatingWebhookConfiguration{ 59 | ObjectMeta: metav1.ObjectMeta{ 60 | Name: validatingWebhookConfiguration, 61 | }, 62 | Webhooks: []admissionregistrationv1beta1.Webhook{ 63 | { 64 | Name: fmt.Sprintf("cron-hpa-controller.%s.svc", namespace), 65 | Rules: []admissionregistrationv1beta1.RuleWithOperations{{ 66 | Operations: []admissionregistrationv1beta1.OperationType{admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Update}, 67 | Rule: admissionregistrationv1beta1.Rule{ 68 | APIGroups: []string{cronhpacontroller.GroupName}, 69 | APIVersions: []string{"v1"}, 70 | Resources: []string{"cronhpas"}, 71 | }, 72 | }}, 73 | FailurePolicy: &failPolicy, 74 | ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{ 75 | Service: &admissionregistrationv1beta1.ServiceReference{ 76 | Namespace: namespace, 77 | Name: "cron-hpa-controller", 78 | Path: &validatePath, 79 | }, 80 | CABundle: caCert, 81 | }, 82 | }, 83 | }, 84 | } 85 | 86 | client := clientset.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations() 87 | if present, err := client.Get(validatingWebhookConfiguration, metav1.GetOptions{}); err == nil { 88 | if !reflect.DeepEqual(present.Webhooks, webhookConfig.Webhooks) { 89 | klog.V(1).Infof("Update validationWebhookConfiguration from %+v to %+v", present, webhookConfig) 90 | webhookConfig.ResourceVersion = present.ResourceVersion 91 | if _, err := client.Update(webhookConfig); err != nil { 92 | klog.Errorf("Failed to update validationWebhookConfiguration: %v", err) 93 | return false, nil 94 | } 95 | } 96 | } else { 97 | if _, err := client.Create(webhookConfig); err != nil { 98 | klog.Errorf("Failed to create validatingWebhookConfiguration: %v", err) 99 | return false, nil 100 | } 101 | } 102 | 103 | return true, nil 104 | } 105 | 106 | // Server will start a https server for admitting. 107 | type Server struct { 108 | listenAddress string 109 | certFile string 110 | keyFile string 111 | } 112 | 113 | // NewServer create a new Server for admitting. 114 | func NewServer(listenAddress, certFile, keyFile string) (*Server, error) { 115 | server := &Server{ 116 | listenAddress: listenAddress, 117 | certFile: certFile, 118 | keyFile: keyFile, 119 | } 120 | 121 | return server, nil 122 | } 123 | 124 | // Run starts informers, and listens for accepting request. 125 | func (ws *Server) Run(stopCh <-chan struct{}) { 126 | mux := http.NewServeMux() 127 | mux.HandleFunc(validatePath, func(writer http.ResponseWriter, request *http.Request) { 128 | Serve(writer, request, admitCronHPA) 129 | }) 130 | 131 | server := &http.Server{ 132 | Addr: ws.listenAddress, 133 | Handler: mux, 134 | } 135 | klog.Fatal(server.ListenAndServeTLS(ws.certFile, ws.keyFile)) 136 | } 137 | 138 | func admitCronHPA(ar *admissionv1beta1.AdmissionReview) *admissionv1beta1.AdmissionResponse { 139 | klog.V(4).Info("Admitting CronHPA") 140 | 141 | reviewResponse := &admissionv1beta1.AdmissionResponse{} 142 | reviewResponse.Allowed = true 143 | 144 | var cronHPA cronhpav1.CronHPA 145 | raw := ar.Request.Object.Raw 146 | if err := json.Unmarshal(raw, &cronHPA); err != nil { 147 | klog.Errorf("Failed to unmarshal CronHPA from %s: %v", raw, err) 148 | return ToAdmissionResponse(err) 149 | } 150 | 151 | return reviewResponse 152 | } 153 | -------------------------------------------------------------------------------- /pkg/admission/util.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package admission 19 | 20 | import ( 21 | "encoding/json" 22 | "io/ioutil" 23 | "net/http" 24 | 25 | "k8s.io/api/admission/v1beta1" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | "k8s.io/klog" 28 | ) 29 | 30 | // ToAdmissionResponse is a helper function to create an AdmissionResponse 31 | // with an embedded error 32 | func ToAdmissionResponse(err error) *v1beta1.AdmissionResponse { 33 | return &v1beta1.AdmissionResponse{ 34 | Allowed: false, 35 | Result: &metav1.Status{ 36 | Message: err.Error(), 37 | }, 38 | } 39 | } 40 | 41 | // Serve handles the http portion of a request prior to handing to an admit 42 | // function 43 | func Serve(w http.ResponseWriter, r *http.Request, admitter func(*v1beta1.AdmissionReview) *v1beta1.AdmissionResponse) { 44 | var body []byte 45 | if r.Body != nil { 46 | if data, err := ioutil.ReadAll(r.Body); err == nil { 47 | body = data 48 | } 49 | } 50 | 51 | // verify the content type is accurate 52 | contentType := r.Header.Get("Content-Type") 53 | if contentType != "application/json" { 54 | klog.Errorf("contentType=%s, expect application/json", contentType) 55 | w.WriteHeader(http.StatusBadRequest) 56 | return 57 | } 58 | 59 | klog.V(4).Infof("Handling request: %s", body) 60 | 61 | // The AdmissionReview that was sent to the webhook 62 | requestedAdmissionReview := v1beta1.AdmissionReview{} 63 | 64 | // The AdmissionReview that will be returned 65 | responseAdmissionReview := v1beta1.AdmissionReview{} 66 | 67 | if err := json.Unmarshal(body, &requestedAdmissionReview); err != nil { 68 | klog.Errorf("Failed to unmarshal %s: %v", body, err) 69 | responseAdmissionReview.Response = ToAdmissionResponse(err) 70 | } else { 71 | // pass to admitFunc 72 | responseAdmissionReview.Response = admitter(&requestedAdmissionReview) 73 | } 74 | 75 | // Return the same UID 76 | responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID 77 | 78 | klog.V(4).Infof("Sending response: %v", responseAdmissionReview.Response) 79 | 80 | respBytes, err := json.Marshal(responseAdmissionReview) 81 | if err != nil { 82 | klog.Errorf("Failed to marshal response %+v: %v", responseAdmissionReview, err) 83 | } 84 | if _, err := w.Write(respBytes); err != nil { 85 | klog.Errorf("Failed to write response %s: %v", respBytes, err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /pkg/apis/cronhpacontroller/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package cronhpacontroller 19 | 20 | const ( 21 | GroupName = "extensions.tkestack.io" 22 | ) 23 | -------------------------------------------------------------------------------- /pkg/apis/cronhpacontroller/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | // +k8s:deepcopy-gen=package 19 | 20 | // Package v1 is the v1 version of the API. 21 | // +groupName=cronhpacontroller.extensions.tkestack.io 22 | package v1 23 | -------------------------------------------------------------------------------- /pkg/apis/cronhpacontroller/v1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package v1 19 | 20 | import ( 21 | "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller" 22 | 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/apimachinery/pkg/runtime" 25 | "k8s.io/apimachinery/pkg/runtime/schema" 26 | ) 27 | 28 | // SchemeGroupVersion is group version used to register these objects 29 | var SchemeGroupVersion = schema.GroupVersion{Group: cronhpacontroller.GroupName, Version: "v1"} 30 | 31 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 32 | func Kind(kind string) schema.GroupKind { 33 | return SchemeGroupVersion.WithKind(kind).GroupKind() 34 | } 35 | 36 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 37 | func Resource(resource string) schema.GroupResource { 38 | return SchemeGroupVersion.WithResource(resource).GroupResource() 39 | } 40 | 41 | var ( 42 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 43 | AddToScheme = SchemeBuilder.AddToScheme 44 | ) 45 | 46 | // Adds the list of known types to Scheme. 47 | func addKnownTypes(scheme *runtime.Scheme) error { 48 | scheme.AddKnownTypes(SchemeGroupVersion, 49 | &CronHPA{}, 50 | &CronHPAList{}, 51 | ) 52 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /pkg/apis/cronhpacontroller/v1/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package v1 19 | 20 | import ( 21 | autoscalingv2 "k8s.io/api/autoscaling/v2beta1" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | ) 24 | 25 | // +genclient 26 | // +genclient:noStatus 27 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 28 | 29 | // CronHPA represents a set of crontabs to set target's replicas. 30 | type CronHPA struct { 31 | metav1.TypeMeta `json:",inline"` 32 | metav1.ObjectMeta `json:"metadata,omitempty"` 33 | 34 | // Spec defines the desired identities of pods in this cronhpa. 35 | Spec CronHPASpec `json:"spec,omitempty"` 36 | 37 | // Status is the current status of pods in this CronHPA. This data 38 | // may be out of date by some window of time. 39 | Status CronHPAStatus `json:"status,omitempty"` 40 | } 41 | 42 | // A CronHPASpec is the specification of a CronHPA. 43 | type CronHPASpec struct { 44 | // scaleTargetRef points to the target resource to scale 45 | ScaleTargetRef autoscalingv2.CrossVersionObjectReference `json:"scaleTargetRef" protobuf:"bytes,1,opt,name=scaleTargetRef"` 46 | 47 | Crons []Cron `json:"crons" protobuf:"bytes,2,opt,name=crons"` 48 | } 49 | 50 | type Cron struct { 51 | // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. 52 | Schedule string `json:"schedule" protobuf:"bytes,1,opt,name=schedule"` 53 | 54 | TargetReplicas int32 `json:"targetReplicas" protobuf:"varint,2,opt,name=targetReplicas"` 55 | } 56 | 57 | // CronHPAStatus represents the current state of a CronHPA. 58 | type CronHPAStatus struct { 59 | // Information when was the last time the schedule was successfully scheduled. 60 | // +optional 61 | LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty" protobuf:"bytes,2,opt,name=lastScheduleTime"` 62 | } 63 | 64 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 65 | 66 | // CronHPAList is a collection of CronHPA. 67 | type CronHPAList struct { 68 | metav1.TypeMeta `json:",inline"` 69 | metav1.ListMeta `json:"metadata,omitempty"` 70 | Items []CronHPA `json:"items"` 71 | } 72 | -------------------------------------------------------------------------------- /pkg/apis/cronhpacontroller/v1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | /* 4 | Copyright The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // Code generated by deepcopy-gen. DO NOT EDIT. 20 | 21 | package v1 22 | 23 | import ( 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | ) 26 | 27 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 28 | func (in *Cron) DeepCopyInto(out *Cron) { 29 | *out = *in 30 | return 31 | } 32 | 33 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cron. 34 | func (in *Cron) DeepCopy() *Cron { 35 | if in == nil { 36 | return nil 37 | } 38 | out := new(Cron) 39 | in.DeepCopyInto(out) 40 | return out 41 | } 42 | 43 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 44 | func (in *CronHPA) DeepCopyInto(out *CronHPA) { 45 | *out = *in 46 | out.TypeMeta = in.TypeMeta 47 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 48 | in.Spec.DeepCopyInto(&out.Spec) 49 | in.Status.DeepCopyInto(&out.Status) 50 | return 51 | } 52 | 53 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronHPA. 54 | func (in *CronHPA) DeepCopy() *CronHPA { 55 | if in == nil { 56 | return nil 57 | } 58 | out := new(CronHPA) 59 | in.DeepCopyInto(out) 60 | return out 61 | } 62 | 63 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 64 | func (in *CronHPA) DeepCopyObject() runtime.Object { 65 | if c := in.DeepCopy(); c != nil { 66 | return c 67 | } 68 | return nil 69 | } 70 | 71 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 72 | func (in *CronHPAList) DeepCopyInto(out *CronHPAList) { 73 | *out = *in 74 | out.TypeMeta = in.TypeMeta 75 | out.ListMeta = in.ListMeta 76 | if in.Items != nil { 77 | in, out := &in.Items, &out.Items 78 | *out = make([]CronHPA, len(*in)) 79 | for i := range *in { 80 | (*in)[i].DeepCopyInto(&(*out)[i]) 81 | } 82 | } 83 | return 84 | } 85 | 86 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronHPAList. 87 | func (in *CronHPAList) DeepCopy() *CronHPAList { 88 | if in == nil { 89 | return nil 90 | } 91 | out := new(CronHPAList) 92 | in.DeepCopyInto(out) 93 | return out 94 | } 95 | 96 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 97 | func (in *CronHPAList) DeepCopyObject() runtime.Object { 98 | if c := in.DeepCopy(); c != nil { 99 | return c 100 | } 101 | return nil 102 | } 103 | 104 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 105 | func (in *CronHPASpec) DeepCopyInto(out *CronHPASpec) { 106 | *out = *in 107 | out.ScaleTargetRef = in.ScaleTargetRef 108 | if in.Crons != nil { 109 | in, out := &in.Crons, &out.Crons 110 | *out = make([]Cron, len(*in)) 111 | copy(*out, *in) 112 | } 113 | return 114 | } 115 | 116 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronHPASpec. 117 | func (in *CronHPASpec) DeepCopy() *CronHPASpec { 118 | if in == nil { 119 | return nil 120 | } 121 | out := new(CronHPASpec) 122 | in.DeepCopyInto(out) 123 | return out 124 | } 125 | 126 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 127 | func (in *CronHPAStatus) DeepCopyInto(out *CronHPAStatus) { 128 | *out = *in 129 | if in.LastScheduleTime != nil { 130 | in, out := &in.LastScheduleTime, &out.LastScheduleTime 131 | *out = (*in).DeepCopy() 132 | } 133 | return 134 | } 135 | 136 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronHPAStatus. 137 | func (in *CronHPAStatus) DeepCopy() *CronHPAStatus { 138 | if in == nil { 139 | return nil 140 | } 141 | out := new(CronHPAStatus) 142 | in.DeepCopyInto(out) 143 | return out 144 | } 145 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package versioned 20 | 21 | import ( 22 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/client/clientset/versioned/typed/cronhpacontroller/v1" 23 | discovery "k8s.io/client-go/discovery" 24 | rest "k8s.io/client-go/rest" 25 | flowcontrol "k8s.io/client-go/util/flowcontrol" 26 | ) 27 | 28 | type Interface interface { 29 | Discovery() discovery.DiscoveryInterface 30 | CronhpacontrollerV1() cronhpacontrollerv1.CronhpacontrollerV1Interface 31 | } 32 | 33 | // Clientset contains the clients for groups. Each group has exactly one 34 | // version included in a Clientset. 35 | type Clientset struct { 36 | *discovery.DiscoveryClient 37 | cronhpacontrollerV1 *cronhpacontrollerv1.CronhpacontrollerV1Client 38 | } 39 | 40 | // CronhpacontrollerV1 retrieves the CronhpacontrollerV1Client 41 | func (c *Clientset) CronhpacontrollerV1() cronhpacontrollerv1.CronhpacontrollerV1Interface { 42 | return c.cronhpacontrollerV1 43 | } 44 | 45 | // Discovery retrieves the DiscoveryClient 46 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 47 | if c == nil { 48 | return nil 49 | } 50 | return c.DiscoveryClient 51 | } 52 | 53 | // NewForConfig creates a new Clientset for the given config. 54 | func NewForConfig(c *rest.Config) (*Clientset, error) { 55 | configShallowCopy := *c 56 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 57 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 58 | } 59 | var cs Clientset 60 | var err error 61 | cs.cronhpacontrollerV1, err = cronhpacontrollerv1.NewForConfig(&configShallowCopy) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) 67 | if err != nil { 68 | return nil, err 69 | } 70 | return &cs, nil 71 | } 72 | 73 | // NewForConfigOrDie creates a new Clientset for the given config and 74 | // panics if there is an error in the config. 75 | func NewForConfigOrDie(c *rest.Config) *Clientset { 76 | var cs Clientset 77 | cs.cronhpacontrollerV1 = cronhpacontrollerv1.NewForConfigOrDie(c) 78 | 79 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) 80 | return &cs 81 | } 82 | 83 | // New creates a new Clientset for the given RESTClient. 84 | func New(c rest.Interface) *Clientset { 85 | var cs Clientset 86 | cs.cronhpacontrollerV1 = cronhpacontrollerv1.New(c) 87 | 88 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 89 | return &cs 90 | } 91 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | clientset "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 23 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/client/clientset/versioned/typed/cronhpacontroller/v1" 24 | fakecronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/client/clientset/versioned/typed/cronhpacontroller/v1/fake" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/watch" 27 | "k8s.io/client-go/discovery" 28 | fakediscovery "k8s.io/client-go/discovery/fake" 29 | "k8s.io/client-go/testing" 30 | ) 31 | 32 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement 35 | // for a real clientset and is mostly useful in simple unit tests. 36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 38 | for _, obj := range objects { 39 | if err := o.Add(obj); err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | cs := &Clientset{} 45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 46 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 48 | gvr := action.GetResource() 49 | ns := action.GetNamespace() 50 | watch, err := o.Watch(gvr, ns) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | return true, watch, nil 55 | }) 56 | 57 | return cs 58 | } 59 | 60 | // Clientset implements clientset.Interface. Meant to be embedded into a 61 | // struct to get a default implementation. This makes faking out just the method 62 | // you want to test easier. 63 | type Clientset struct { 64 | testing.Fake 65 | discovery *fakediscovery.FakeDiscovery 66 | } 67 | 68 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 69 | return c.discovery 70 | } 71 | 72 | var _ clientset.Interface = &Clientset{} 73 | 74 | // CronhpacontrollerV1 retrieves the CronhpacontrollerV1Client 75 | func (c *Clientset) CronhpacontrollerV1() cronhpacontrollerv1.CronhpacontrollerV1Interface { 76 | return &fakecronhpacontrollerv1.FakeCronhpacontrollerV1{Fake: &c.Fake} 77 | } 78 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var scheme = runtime.NewScheme() 31 | var codecs = serializer.NewCodecFactory(scheme) 32 | var parameterCodec = runtime.NewParameterCodec(scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | cronhpacontrollerv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var Scheme = runtime.NewScheme() 31 | var Codecs = serializer.NewCodecFactory(Scheme) 32 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | cronhpacontrollerv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(Scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/cronhpa.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "time" 23 | 24 | v1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 25 | scheme "tkestack.io/cron-hpa/pkg/client/clientset/versioned/scheme" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | types "k8s.io/apimachinery/pkg/types" 28 | watch "k8s.io/apimachinery/pkg/watch" 29 | rest "k8s.io/client-go/rest" 30 | ) 31 | 32 | // CronHPAsGetter has a method to return a CronHPAInterface. 33 | // A group's client should implement this interface. 34 | type CronHPAsGetter interface { 35 | CronHPAs(namespace string) CronHPAInterface 36 | } 37 | 38 | // CronHPAInterface has methods to work with CronHPA resources. 39 | type CronHPAInterface interface { 40 | Create(*v1.CronHPA) (*v1.CronHPA, error) 41 | Update(*v1.CronHPA) (*v1.CronHPA, error) 42 | Delete(name string, options *metav1.DeleteOptions) error 43 | DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error 44 | Get(name string, options metav1.GetOptions) (*v1.CronHPA, error) 45 | List(opts metav1.ListOptions) (*v1.CronHPAList, error) 46 | Watch(opts metav1.ListOptions) (watch.Interface, error) 47 | Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CronHPA, err error) 48 | CronHPAExpansion 49 | } 50 | 51 | // cronHPAs implements CronHPAInterface 52 | type cronHPAs struct { 53 | client rest.Interface 54 | ns string 55 | } 56 | 57 | // newCronHPAs returns a CronHPAs 58 | func newCronHPAs(c *CronhpacontrollerV1Client, namespace string) *cronHPAs { 59 | return &cronHPAs{ 60 | client: c.RESTClient(), 61 | ns: namespace, 62 | } 63 | } 64 | 65 | // Get takes name of the cronHPA, and returns the corresponding cronHPA object, and an error if there is any. 66 | func (c *cronHPAs) Get(name string, options metav1.GetOptions) (result *v1.CronHPA, err error) { 67 | result = &v1.CronHPA{} 68 | err = c.client.Get(). 69 | Namespace(c.ns). 70 | Resource("cronhpas"). 71 | Name(name). 72 | VersionedParams(&options, scheme.ParameterCodec). 73 | Do(). 74 | Into(result) 75 | return 76 | } 77 | 78 | // List takes label and field selectors, and returns the list of CronHPAs that match those selectors. 79 | func (c *cronHPAs) List(opts metav1.ListOptions) (result *v1.CronHPAList, err error) { 80 | var timeout time.Duration 81 | if opts.TimeoutSeconds != nil { 82 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 83 | } 84 | result = &v1.CronHPAList{} 85 | err = c.client.Get(). 86 | Namespace(c.ns). 87 | Resource("cronhpas"). 88 | VersionedParams(&opts, scheme.ParameterCodec). 89 | Timeout(timeout). 90 | Do(). 91 | Into(result) 92 | return 93 | } 94 | 95 | // Watch returns a watch.Interface that watches the requested cronHPAs. 96 | func (c *cronHPAs) Watch(opts metav1.ListOptions) (watch.Interface, error) { 97 | var timeout time.Duration 98 | if opts.TimeoutSeconds != nil { 99 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 100 | } 101 | opts.Watch = true 102 | return c.client.Get(). 103 | Namespace(c.ns). 104 | Resource("cronhpas"). 105 | VersionedParams(&opts, scheme.ParameterCodec). 106 | Timeout(timeout). 107 | Watch() 108 | } 109 | 110 | // Create takes the representation of a cronHPA and creates it. Returns the server's representation of the cronHPA, and an error, if there is any. 111 | func (c *cronHPAs) Create(cronHPA *v1.CronHPA) (result *v1.CronHPA, err error) { 112 | result = &v1.CronHPA{} 113 | err = c.client.Post(). 114 | Namespace(c.ns). 115 | Resource("cronhpas"). 116 | Body(cronHPA). 117 | Do(). 118 | Into(result) 119 | return 120 | } 121 | 122 | // Update takes the representation of a cronHPA and updates it. Returns the server's representation of the cronHPA, and an error, if there is any. 123 | func (c *cronHPAs) Update(cronHPA *v1.CronHPA) (result *v1.CronHPA, err error) { 124 | result = &v1.CronHPA{} 125 | err = c.client.Put(). 126 | Namespace(c.ns). 127 | Resource("cronhpas"). 128 | Name(cronHPA.Name). 129 | Body(cronHPA). 130 | Do(). 131 | Into(result) 132 | return 133 | } 134 | 135 | // Delete takes name of the cronHPA and deletes it. Returns an error if one occurs. 136 | func (c *cronHPAs) Delete(name string, options *metav1.DeleteOptions) error { 137 | return c.client.Delete(). 138 | Namespace(c.ns). 139 | Resource("cronhpas"). 140 | Name(name). 141 | Body(options). 142 | Do(). 143 | Error() 144 | } 145 | 146 | // DeleteCollection deletes a collection of objects. 147 | func (c *cronHPAs) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { 148 | var timeout time.Duration 149 | if listOptions.TimeoutSeconds != nil { 150 | timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second 151 | } 152 | return c.client.Delete(). 153 | Namespace(c.ns). 154 | Resource("cronhpas"). 155 | VersionedParams(&listOptions, scheme.ParameterCodec). 156 | Timeout(timeout). 157 | Body(options). 158 | Do(). 159 | Error() 160 | } 161 | 162 | // Patch applies the patch and returns the patched cronHPA. 163 | func (c *cronHPAs) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CronHPA, err error) { 164 | result = &v1.CronHPA{} 165 | err = c.client.Patch(pt). 166 | Namespace(c.ns). 167 | Resource("cronhpas"). 168 | SubResource(subresources...). 169 | Name(name). 170 | Body(data). 171 | Do(). 172 | Into(result) 173 | return 174 | } 175 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/cronhpacontroller_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 23 | "tkestack.io/cron-hpa/pkg/client/clientset/versioned/scheme" 24 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 25 | rest "k8s.io/client-go/rest" 26 | ) 27 | 28 | type CronhpacontrollerV1Interface interface { 29 | RESTClient() rest.Interface 30 | CronHPAsGetter 31 | } 32 | 33 | // CronhpacontrollerV1Client is used to interact with features provided by the cronhpacontroller.extensions.tkestack.io group. 34 | type CronhpacontrollerV1Client struct { 35 | restClient rest.Interface 36 | } 37 | 38 | func (c *CronhpacontrollerV1Client) CronHPAs(namespace string) CronHPAInterface { 39 | return newCronHPAs(c, namespace) 40 | } 41 | 42 | // NewForConfig creates a new CronhpacontrollerV1Client for the given config. 43 | func NewForConfig(c *rest.Config) (*CronhpacontrollerV1Client, error) { 44 | config := *c 45 | if err := setConfigDefaults(&config); err != nil { 46 | return nil, err 47 | } 48 | client, err := rest.RESTClientFor(&config) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &CronhpacontrollerV1Client{client}, nil 53 | } 54 | 55 | // NewForConfigOrDie creates a new CronhpacontrollerV1Client for the given config and 56 | // panics if there is an error in the config. 57 | func NewForConfigOrDie(c *rest.Config) *CronhpacontrollerV1Client { 58 | client, err := NewForConfig(c) 59 | if err != nil { 60 | panic(err) 61 | } 62 | return client 63 | } 64 | 65 | // New creates a new CronhpacontrollerV1Client for the given RESTClient. 66 | func New(c rest.Interface) *CronhpacontrollerV1Client { 67 | return &CronhpacontrollerV1Client{c} 68 | } 69 | 70 | func setConfigDefaults(config *rest.Config) error { 71 | gv := v1.SchemeGroupVersion 72 | config.GroupVersion = &gv 73 | config.APIPath = "/apis" 74 | config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} 75 | 76 | if config.UserAgent == "" { 77 | config.UserAgent = rest.DefaultKubernetesUserAgent() 78 | } 79 | 80 | return nil 81 | } 82 | 83 | // RESTClient returns a RESTClient that is used to communicate 84 | // with API server by this client implementation. 85 | func (c *CronhpacontrollerV1Client) RESTClient() rest.Interface { 86 | if c == nil { 87 | return nil 88 | } 89 | return c.restClient 90 | } 91 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/fake/fake_cronhpa.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | labels "k8s.io/apimachinery/pkg/labels" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | types "k8s.io/apimachinery/pkg/types" 27 | watch "k8s.io/apimachinery/pkg/watch" 28 | testing "k8s.io/client-go/testing" 29 | ) 30 | 31 | // FakeCronHPAs implements CronHPAInterface 32 | type FakeCronHPAs struct { 33 | Fake *FakeCronhpacontrollerV1 34 | ns string 35 | } 36 | 37 | var cronhpasResource = schema.GroupVersionResource{Group: "cronhpacontroller.extensions.tkestack.io", Version: "v1", Resource: "cronhpas"} 38 | 39 | var cronhpasKind = schema.GroupVersionKind{Group: "cronhpacontroller.extensions.tkestack.io", Version: "v1", Kind: "CronHPA"} 40 | 41 | // Get takes name of the cronHPA, and returns the corresponding cronHPA object, and an error if there is any. 42 | func (c *FakeCronHPAs) Get(name string, options v1.GetOptions) (result *cronhpacontrollerv1.CronHPA, err error) { 43 | obj, err := c.Fake. 44 | Invokes(testing.NewGetAction(cronhpasResource, c.ns, name), &cronhpacontrollerv1.CronHPA{}) 45 | 46 | if obj == nil { 47 | return nil, err 48 | } 49 | return obj.(*cronhpacontrollerv1.CronHPA), err 50 | } 51 | 52 | // List takes label and field selectors, and returns the list of CronHPAs that match those selectors. 53 | func (c *FakeCronHPAs) List(opts v1.ListOptions) (result *cronhpacontrollerv1.CronHPAList, err error) { 54 | obj, err := c.Fake. 55 | Invokes(testing.NewListAction(cronhpasResource, cronhpasKind, c.ns, opts), &cronhpacontrollerv1.CronHPAList{}) 56 | 57 | if obj == nil { 58 | return nil, err 59 | } 60 | 61 | label, _, _ := testing.ExtractFromListOptions(opts) 62 | if label == nil { 63 | label = labels.Everything() 64 | } 65 | list := &cronhpacontrollerv1.CronHPAList{ListMeta: obj.(*cronhpacontrollerv1.CronHPAList).ListMeta} 66 | for _, item := range obj.(*cronhpacontrollerv1.CronHPAList).Items { 67 | if label.Matches(labels.Set(item.Labels)) { 68 | list.Items = append(list.Items, item) 69 | } 70 | } 71 | return list, err 72 | } 73 | 74 | // Watch returns a watch.Interface that watches the requested cronHPAs. 75 | func (c *FakeCronHPAs) Watch(opts v1.ListOptions) (watch.Interface, error) { 76 | return c.Fake. 77 | InvokesWatch(testing.NewWatchAction(cronhpasResource, c.ns, opts)) 78 | 79 | } 80 | 81 | // Create takes the representation of a cronHPA and creates it. Returns the server's representation of the cronHPA, and an error, if there is any. 82 | func (c *FakeCronHPAs) Create(cronHPA *cronhpacontrollerv1.CronHPA) (result *cronhpacontrollerv1.CronHPA, err error) { 83 | obj, err := c.Fake. 84 | Invokes(testing.NewCreateAction(cronhpasResource, c.ns, cronHPA), &cronhpacontrollerv1.CronHPA{}) 85 | 86 | if obj == nil { 87 | return nil, err 88 | } 89 | return obj.(*cronhpacontrollerv1.CronHPA), err 90 | } 91 | 92 | // Update takes the representation of a cronHPA and updates it. Returns the server's representation of the cronHPA, and an error, if there is any. 93 | func (c *FakeCronHPAs) Update(cronHPA *cronhpacontrollerv1.CronHPA) (result *cronhpacontrollerv1.CronHPA, err error) { 94 | obj, err := c.Fake. 95 | Invokes(testing.NewUpdateAction(cronhpasResource, c.ns, cronHPA), &cronhpacontrollerv1.CronHPA{}) 96 | 97 | if obj == nil { 98 | return nil, err 99 | } 100 | return obj.(*cronhpacontrollerv1.CronHPA), err 101 | } 102 | 103 | // Delete takes name of the cronHPA and deletes it. Returns an error if one occurs. 104 | func (c *FakeCronHPAs) Delete(name string, options *v1.DeleteOptions) error { 105 | _, err := c.Fake. 106 | Invokes(testing.NewDeleteAction(cronhpasResource, c.ns, name), &cronhpacontrollerv1.CronHPA{}) 107 | 108 | return err 109 | } 110 | 111 | // DeleteCollection deletes a collection of objects. 112 | func (c *FakeCronHPAs) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { 113 | action := testing.NewDeleteCollectionAction(cronhpasResource, c.ns, listOptions) 114 | 115 | _, err := c.Fake.Invokes(action, &cronhpacontrollerv1.CronHPAList{}) 116 | return err 117 | } 118 | 119 | // Patch applies the patch and returns the patched cronHPA. 120 | func (c *FakeCronHPAs) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *cronhpacontrollerv1.CronHPA, err error) { 121 | obj, err := c.Fake. 122 | Invokes(testing.NewPatchSubresourceAction(cronhpasResource, c.ns, name, pt, data, subresources...), &cronhpacontrollerv1.CronHPA{}) 123 | 124 | if obj == nil { 125 | return nil, err 126 | } 127 | return obj.(*cronhpacontrollerv1.CronHPA), err 128 | } 129 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/fake/fake_cronhpacontroller_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1 "tkestack.io/cron-hpa/pkg/client/clientset/versioned/typed/cronhpacontroller/v1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeCronhpacontrollerV1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeCronhpacontrollerV1) CronHPAs(namespace string) v1.CronHPAInterface { 32 | return &FakeCronHPAs{c, namespace} 33 | } 34 | 35 | // RESTClient returns a RESTClient that is used to communicate 36 | // with API server by this client implementation. 37 | func (c *FakeCronhpacontrollerV1) RESTClient() rest.Interface { 38 | var ret *rest.RESTClient 39 | return ret 40 | } 41 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/cronhpacontroller/v1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | type CronHPAExpansion interface{} 22 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/cronhpacontroller/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package cronhpacontroller 20 | 21 | import ( 22 | v1 "tkestack.io/cron-hpa/pkg/client/informers/externalversions/cronhpacontroller/v1" 23 | internalinterfaces "tkestack.io/cron-hpa/pkg/client/informers/externalversions/internalinterfaces" 24 | ) 25 | 26 | // Interface provides access to each of this group's versions. 27 | type Interface interface { 28 | // V1 provides access to shared informers for resources in V1. 29 | V1() v1.Interface 30 | } 31 | 32 | type group struct { 33 | factory internalinterfaces.SharedInformerFactory 34 | namespace string 35 | tweakListOptions internalinterfaces.TweakListOptionsFunc 36 | } 37 | 38 | // New returns a new Interface. 39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 41 | } 42 | 43 | // V1 returns a new v1.Interface. 44 | func (g *group) V1() v1.Interface { 45 | return v1.New(g.factory, g.namespace, g.tweakListOptions) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/cronhpacontroller/v1/cronhpa.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | time "time" 23 | 24 | cronhpacontrollerv1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 25 | versioned "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 26 | internalinterfaces "tkestack.io/cron-hpa/pkg/client/informers/externalversions/internalinterfaces" 27 | v1 "tkestack.io/cron-hpa/pkg/client/listers/cronhpacontroller/v1" 28 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | runtime "k8s.io/apimachinery/pkg/runtime" 30 | watch "k8s.io/apimachinery/pkg/watch" 31 | cache "k8s.io/client-go/tools/cache" 32 | ) 33 | 34 | // CronHPAInformer provides access to a shared informer and lister for 35 | // CronHPAs. 36 | type CronHPAInformer interface { 37 | Informer() cache.SharedIndexInformer 38 | Lister() v1.CronHPALister 39 | } 40 | 41 | type cronHPAInformer struct { 42 | factory internalinterfaces.SharedInformerFactory 43 | tweakListOptions internalinterfaces.TweakListOptionsFunc 44 | namespace string 45 | } 46 | 47 | // NewCronHPAInformer constructs a new informer for CronHPA type. 48 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 49 | // one. This reduces memory footprint and number of connections to the server. 50 | func NewCronHPAInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 51 | return NewFilteredCronHPAInformer(client, namespace, resyncPeriod, indexers, nil) 52 | } 53 | 54 | // NewFilteredCronHPAInformer constructs a new informer for CronHPA type. 55 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 56 | // one. This reduces memory footprint and number of connections to the server. 57 | func NewFilteredCronHPAInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 58 | return cache.NewSharedIndexInformer( 59 | &cache.ListWatch{ 60 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 61 | if tweakListOptions != nil { 62 | tweakListOptions(&options) 63 | } 64 | return client.CronhpacontrollerV1().CronHPAs(namespace).List(options) 65 | }, 66 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 67 | if tweakListOptions != nil { 68 | tweakListOptions(&options) 69 | } 70 | return client.CronhpacontrollerV1().CronHPAs(namespace).Watch(options) 71 | }, 72 | }, 73 | &cronhpacontrollerv1.CronHPA{}, 74 | resyncPeriod, 75 | indexers, 76 | ) 77 | } 78 | 79 | func (f *cronHPAInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 80 | return NewFilteredCronHPAInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 81 | } 82 | 83 | func (f *cronHPAInformer) Informer() cache.SharedIndexInformer { 84 | return f.factory.InformerFor(&cronhpacontrollerv1.CronHPA{}, f.defaultInformer) 85 | } 86 | 87 | func (f *cronHPAInformer) Lister() v1.CronHPALister { 88 | return v1.NewCronHPALister(f.Informer().GetIndexer()) 89 | } 90 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/cronhpacontroller/v1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | internalinterfaces "tkestack.io/cron-hpa/pkg/client/informers/externalversions/internalinterfaces" 23 | ) 24 | 25 | // Interface provides access to all the informers in this group version. 26 | type Interface interface { 27 | // CronHPAs returns a CronHPAInformer. 28 | CronHPAs() CronHPAInformer 29 | } 30 | 31 | type version struct { 32 | factory internalinterfaces.SharedInformerFactory 33 | namespace string 34 | tweakListOptions internalinterfaces.TweakListOptionsFunc 35 | } 36 | 37 | // New returns a new Interface. 38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 40 | } 41 | 42 | // CronHPAs returns a CronHPAInformer. 43 | func (v *version) CronHPAs() CronHPAInformer { 44 | return &cronHPAInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 45 | } 46 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | reflect "reflect" 23 | sync "sync" 24 | time "time" 25 | 26 | versioned "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 27 | cronhpacontroller "tkestack.io/cron-hpa/pkg/client/informers/externalversions/cronhpacontroller" 28 | internalinterfaces "tkestack.io/cron-hpa/pkg/client/informers/externalversions/internalinterfaces" 29 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | schema "k8s.io/apimachinery/pkg/runtime/schema" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // SharedInformerOption defines the functional option type for SharedInformerFactory. 36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory 37 | 38 | type sharedInformerFactory struct { 39 | client versioned.Interface 40 | namespace string 41 | tweakListOptions internalinterfaces.TweakListOptionsFunc 42 | lock sync.Mutex 43 | defaultResync time.Duration 44 | customResync map[reflect.Type]time.Duration 45 | 46 | informers map[reflect.Type]cache.SharedIndexInformer 47 | // startedInformers is used for tracking which informers have been started. 48 | // This allows Start() to be called multiple times safely. 49 | startedInformers map[reflect.Type]bool 50 | } 51 | 52 | // WithCustomResyncConfig sets a custom resync period for the specified informer types. 53 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { 54 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 55 | for k, v := range resyncConfig { 56 | factory.customResync[reflect.TypeOf(k)] = v 57 | } 58 | return factory 59 | } 60 | } 61 | 62 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. 63 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { 64 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 65 | factory.tweakListOptions = tweakListOptions 66 | return factory 67 | } 68 | } 69 | 70 | // WithNamespace limits the SharedInformerFactory to the specified namespace. 71 | func WithNamespace(namespace string) SharedInformerOption { 72 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 73 | factory.namespace = namespace 74 | return factory 75 | } 76 | } 77 | 78 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. 79 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { 80 | return NewSharedInformerFactoryWithOptions(client, defaultResync) 81 | } 82 | 83 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. 84 | // Listers obtained via this SharedInformerFactory will be subject to the same filters 85 | // as specified here. 86 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead 87 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { 88 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) 89 | } 90 | 91 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. 92 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { 93 | factory := &sharedInformerFactory{ 94 | client: client, 95 | namespace: v1.NamespaceAll, 96 | defaultResync: defaultResync, 97 | informers: make(map[reflect.Type]cache.SharedIndexInformer), 98 | startedInformers: make(map[reflect.Type]bool), 99 | customResync: make(map[reflect.Type]time.Duration), 100 | } 101 | 102 | // Apply all options 103 | for _, opt := range options { 104 | factory = opt(factory) 105 | } 106 | 107 | return factory 108 | } 109 | 110 | // Start initializes all requested informers. 111 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { 112 | f.lock.Lock() 113 | defer f.lock.Unlock() 114 | 115 | for informerType, informer := range f.informers { 116 | if !f.startedInformers[informerType] { 117 | go informer.Run(stopCh) 118 | f.startedInformers[informerType] = true 119 | } 120 | } 121 | } 122 | 123 | // WaitForCacheSync waits for all started informers' cache were synced. 124 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { 125 | informers := func() map[reflect.Type]cache.SharedIndexInformer { 126 | f.lock.Lock() 127 | defer f.lock.Unlock() 128 | 129 | informers := map[reflect.Type]cache.SharedIndexInformer{} 130 | for informerType, informer := range f.informers { 131 | if f.startedInformers[informerType] { 132 | informers[informerType] = informer 133 | } 134 | } 135 | return informers 136 | }() 137 | 138 | res := map[reflect.Type]bool{} 139 | for informType, informer := range informers { 140 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) 141 | } 142 | return res 143 | } 144 | 145 | // InternalInformerFor returns the SharedIndexInformer for obj using an internal 146 | // client. 147 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { 148 | f.lock.Lock() 149 | defer f.lock.Unlock() 150 | 151 | informerType := reflect.TypeOf(obj) 152 | informer, exists := f.informers[informerType] 153 | if exists { 154 | return informer 155 | } 156 | 157 | resyncPeriod, exists := f.customResync[informerType] 158 | if !exists { 159 | resyncPeriod = f.defaultResync 160 | } 161 | 162 | informer = newFunc(f.client, resyncPeriod) 163 | f.informers[informerType] = informer 164 | 165 | return informer 166 | } 167 | 168 | // SharedInformerFactory provides shared informers for resources in all known 169 | // API group versions. 170 | type SharedInformerFactory interface { 171 | internalinterfaces.SharedInformerFactory 172 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error) 173 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool 174 | 175 | Cronhpacontroller() cronhpacontroller.Interface 176 | } 177 | 178 | func (f *sharedInformerFactory) Cronhpacontroller() cronhpacontroller.Interface { 179 | return cronhpacontroller.New(f, f.namespace, f.tweakListOptions) 180 | } 181 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | "fmt" 23 | 24 | v1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | cache "k8s.io/client-go/tools/cache" 27 | ) 28 | 29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other 30 | // sharedInformers based on type 31 | type GenericInformer interface { 32 | Informer() cache.SharedIndexInformer 33 | Lister() cache.GenericLister 34 | } 35 | 36 | type genericInformer struct { 37 | informer cache.SharedIndexInformer 38 | resource schema.GroupResource 39 | } 40 | 41 | // Informer returns the SharedIndexInformer. 42 | func (f *genericInformer) Informer() cache.SharedIndexInformer { 43 | return f.informer 44 | } 45 | 46 | // Lister returns the GenericLister. 47 | func (f *genericInformer) Lister() cache.GenericLister { 48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) 49 | } 50 | 51 | // ForResource gives generic access to a shared informer of the matching type 52 | // TODO extend this to unknown resources with a client pool 53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { 54 | switch resource { 55 | // Group=cronhpacontroller.extensions.tkestack.io, Version=v1 56 | case v1.SchemeGroupVersion.WithResource("cronhpas"): 57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Cronhpacontroller().V1().CronHPAs().Informer()}, nil 58 | 59 | } 60 | 61 | return nil, fmt.Errorf("no informer found for %v", resource) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package internalinterfaces 20 | 21 | import ( 22 | time "time" 23 | 24 | versioned "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | cache "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. 31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 32 | 33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 34 | type SharedInformerFactory interface { 35 | Start(stopCh <-chan struct{}) 36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 37 | } 38 | 39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions. 40 | type TweakListOptionsFunc func(*v1.ListOptions) 41 | -------------------------------------------------------------------------------- /pkg/client/listers/cronhpacontroller/v1/cronhpa.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // CronHPALister helps list CronHPAs. 29 | type CronHPALister interface { 30 | // List lists all CronHPAs in the indexer. 31 | List(selector labels.Selector) (ret []*v1.CronHPA, err error) 32 | // CronHPAs returns an object that can list and get CronHPAs. 33 | CronHPAs(namespace string) CronHPANamespaceLister 34 | CronHPAListerExpansion 35 | } 36 | 37 | // cronHPALister implements the CronHPALister interface. 38 | type cronHPALister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewCronHPALister returns a new CronHPALister. 43 | func NewCronHPALister(indexer cache.Indexer) CronHPALister { 44 | return &cronHPALister{indexer: indexer} 45 | } 46 | 47 | // List lists all CronHPAs in the indexer. 48 | func (s *cronHPALister) List(selector labels.Selector) (ret []*v1.CronHPA, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1.CronHPA)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // CronHPAs returns an object that can list and get CronHPAs. 56 | func (s *cronHPALister) CronHPAs(namespace string) CronHPANamespaceLister { 57 | return cronHPANamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // CronHPANamespaceLister helps list and get CronHPAs. 61 | type CronHPANamespaceLister interface { 62 | // List lists all CronHPAs in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1.CronHPA, err error) 64 | // Get retrieves the CronHPA from the indexer for a given namespace and name. 65 | Get(name string) (*v1.CronHPA, error) 66 | CronHPANamespaceListerExpansion 67 | } 68 | 69 | // cronHPANamespaceLister implements the CronHPANamespaceLister 70 | // interface. 71 | type cronHPANamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all CronHPAs in the indexer for a given namespace. 77 | func (s cronHPANamespaceLister) List(selector labels.Selector) (ret []*v1.CronHPA, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1.CronHPA)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the CronHPA from the indexer for a given namespace and name. 85 | func (s cronHPANamespaceLister) Get(name string) (*v1.CronHPA, error) { 86 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) 87 | if err != nil { 88 | return nil, err 89 | } 90 | if !exists { 91 | return nil, errors.NewNotFound(v1.Resource("cronhpa"), name) 92 | } 93 | return obj.(*v1.CronHPA), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/client/listers/cronhpacontroller/v1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | // CronHPAListerExpansion allows custom methods to be added to 22 | // CronHPALister. 23 | type CronHPAListerExpansion interface{} 24 | 25 | // CronHPANamespaceListerExpansion allows custom methods to be added to 26 | // CronHPANamespaceLister. 27 | type CronHPANamespaceListerExpansion interface{} 28 | -------------------------------------------------------------------------------- /pkg/cronhpa/controller.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package cronhpa 19 | 20 | import ( 21 | "fmt" 22 | "time" 23 | 24 | "tkestack.io/cron-hpa/pkg/apis/cronhpacontroller/v1" 25 | clientset "tkestack.io/cron-hpa/pkg/client/clientset/versioned" 26 | cronhpascheme "tkestack.io/cron-hpa/pkg/client/clientset/versioned/scheme" 27 | 28 | cronutil "github.com/robfig/cron" 29 | autoscalingv1 "k8s.io/api/autoscaling/v1" 30 | corev1 "k8s.io/api/core/v1" 31 | apimeta "k8s.io/apimachinery/pkg/api/meta" 32 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 | "k8s.io/apimachinery/pkg/runtime/schema" 34 | "k8s.io/apimachinery/pkg/util/runtime" 35 | "k8s.io/apimachinery/pkg/util/wait" 36 | cacheddiscovery "k8s.io/client-go/discovery/cached" 37 | "k8s.io/client-go/dynamic" 38 | "k8s.io/client-go/kubernetes" 39 | "k8s.io/client-go/kubernetes/scheme" 40 | typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" 41 | "k8s.io/client-go/restmapper" 42 | scaleclient "k8s.io/client-go/scale" 43 | "k8s.io/client-go/tools/record" 44 | "k8s.io/klog" 45 | controllerpkg "k8s.io/kubernetes/pkg/controller" 46 | ) 47 | 48 | const controllerAgentName = "cronhpa-controller" 49 | 50 | // Controller is the controller implementation for cronhpa resources 51 | type Controller struct { 52 | // kubeclientset is a standard kubernetes clientset 53 | kubeclientset kubernetes.Interface 54 | // cronhpaclientset is a clientset for our own API group 55 | cronhpaclientset clientset.Interface 56 | 57 | restMapper *restmapper.DeferredDiscoveryRESTMapper 58 | scaleNamespacer scaleclient.ScalesGetter 59 | 60 | // recorder is an event recorder for recording Event resources to the 61 | // Kubernetes API. 62 | recorder record.EventRecorder 63 | } 64 | 65 | // NewController returns a new cronhpa controller 66 | func NewController( 67 | kubeclientset kubernetes.Interface, 68 | cronhpaclientset clientset.Interface, 69 | rootClientBuilder controllerpkg.ControllerClientBuilder) (*Controller, error) { 70 | 71 | // Create event broadcaster 72 | // Add cronhpa-controller types to the default Kubernetes Scheme so Events can be 73 | // logged for cronhpa-controller types. 74 | cronhpascheme.AddToScheme(scheme.Scheme) 75 | klog.V(4).Info("Creating event broadcaster") 76 | eventBroadcaster := record.NewBroadcaster() 77 | eventBroadcaster.StartLogging(klog.Infof) 78 | eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")}) 79 | recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) 80 | 81 | // Use a discovery client capable of being refreshed. 82 | discoveryClient := rootClientBuilder.ClientOrDie("cron-hpa-controller") 83 | cronhpaClientConfig := rootClientBuilder.ConfigOrDie("cron-hpa-controller") 84 | 85 | cachedClient := cacheddiscovery.NewMemCacheClient(discoveryClient.Discovery()) 86 | restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedClient) 87 | //restMapper := discovery.NewDeferredDiscoveryRESTMapper(cachedDiscovery, apimeta.InterfacesForUnstructured) 88 | restMapper.Reset() 89 | // we don't use cached discovery because DiscoveryScaleKindResolver does its own caching, 90 | // so we want to re-fetch every time when we actually ask for it 91 | scaleKindResolver := scaleclient.NewDiscoveryScaleKindResolver(discoveryClient.Discovery()) 92 | scaleClient, err := scaleclient.NewForConfig(cronhpaClientConfig, restMapper, dynamic.LegacyAPIPathResolverFunc, scaleKindResolver) 93 | if err != nil { 94 | return nil, err 95 | } 96 | 97 | controller := &Controller{ 98 | kubeclientset: kubeclientset, 99 | cronhpaclientset: cronhpaclientset, 100 | restMapper: restMapper, 101 | scaleNamespacer: scaleClient, 102 | recorder: recorder, 103 | } 104 | 105 | return controller, nil 106 | } 107 | 108 | func (c *Controller) Run(stopCh <-chan struct{}) error { 109 | defer runtime.HandleCrash() 110 | 111 | // Start the informer factories to begin populating the informer caches 112 | klog.Info("Starting cronhpa controller") 113 | 114 | go wait.Until(c.syncAll, 10*time.Second, stopCh) 115 | go wait.Until(func() { c.restMapper.Reset() }, 30*time.Second, stopCh) 116 | <-stopCh 117 | klog.Info("Shutting down") 118 | 119 | return nil 120 | } 121 | 122 | func (c *Controller) GetEventRecorder() record.EventRecorder { 123 | return c.recorder 124 | } 125 | 126 | func (c *Controller) syncAll() { 127 | klog.V(4).Infof("Starting sync all") 128 | cronhpas, err := c.cronhpaclientset.CronhpacontrollerV1().CronHPAs(metav1.NamespaceAll).List(metav1.ListOptions{}) 129 | if err != nil { 130 | klog.Errorf("Failed to list cronhpas") 131 | return 132 | } 133 | for _, cronhpa := range cronhpas.Items { 134 | klog.V(4).Infof("Sync cronhpa: %s", cronhpa.Name) 135 | c.syncOne(&cronhpa) 136 | } 137 | } 138 | 139 | func (c *Controller) syncOne(cronhpa *v1.CronHPA) { 140 | now := time.Now() 141 | latestSchedledTime := getLatestScheduledTime(cronhpa) 142 | for _, cron := range cronhpa.Spec.Crons { 143 | sched, err := cronutil.ParseStandard(cron.Schedule) 144 | if err != nil { 145 | klog.Errorf("Unparseable schedule: %s : %s", cron.Schedule, err) 146 | } 147 | t := sched.Next(latestSchedledTime) 148 | klog.V(4).Infof("Next schedule for %s of cronhpa %s: %v", cron.Schedule, getCronHPAFullName(cronhpa), t) 149 | if !t.After(now) { 150 | klog.V(4).Infof("Scale %s to replicas %d for schedule %s", getCronHPAFullName(cronhpa), 151 | cron.TargetReplicas, cron.Schedule) 152 | // Set new replicas 153 | if err := c.scale(cronhpa, cron.TargetReplicas); err != nil { 154 | klog.Errorf("Failed to scale %s to replicas %d: %v", getCronHPAFullName(cronhpa), cron.TargetReplicas, err) 155 | return 156 | } 157 | // Update status 158 | cronhpa.Status.LastScheduleTime = &metav1.Time{Time: time.Now()} 159 | if _, err := c.cronhpaclientset.CronhpacontrollerV1().CronHPAs(cronhpa.Namespace).Update(cronhpa); err != nil { 160 | klog.Errorf("Failed to update cronhpa %s's LastScheduleTime(%+v): %v", 161 | getCronHPAFullName(cronhpa), cronhpa.Status.LastScheduleTime.Time, err) 162 | } 163 | 164 | return 165 | } 166 | } 167 | } 168 | 169 | func (c *Controller) scale(cronhpa *v1.CronHPA, replicas int32) error { 170 | reference := fmt.Sprintf("%s/%s/%s", cronhpa.Spec.ScaleTargetRef.Kind, cronhpa.Namespace, cronhpa.Spec.ScaleTargetRef.Name) 171 | 172 | targetGV, err := schema.ParseGroupVersion(cronhpa.Spec.ScaleTargetRef.APIVersion) 173 | if err != nil { 174 | c.recorder.Eventf(cronhpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) 175 | return fmt.Errorf("invalid API version in scale target reference: %v", err) 176 | } 177 | 178 | targetGK := schema.GroupKind{ 179 | Group: targetGV.Group, 180 | Kind: cronhpa.Spec.ScaleTargetRef.Kind, 181 | } 182 | 183 | mappings, err := c.restMapper.RESTMappings(targetGK) 184 | if err != nil { 185 | c.recorder.Eventf(cronhpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) 186 | return fmt.Errorf("unable to determine resource for scale target reference: %v", err) 187 | } 188 | 189 | scale, targetGR, err := c.scaleForResourceMappings(cronhpa.Namespace, cronhpa.Spec.ScaleTargetRef.Name, mappings) 190 | if err != nil { 191 | c.recorder.Eventf(cronhpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) 192 | return fmt.Errorf("failed to query scale subresource for %s: %v", reference, err) 193 | } 194 | 195 | if scale.Spec.Replicas != replicas { 196 | oldReplicas := scale.Spec.Replicas 197 | scale.Spec.Replicas = replicas 198 | _, err = c.scaleNamespacer.Scales(cronhpa.Namespace).Update(targetGR, scale) 199 | if err != nil { 200 | c.recorder.Eventf(cronhpa, corev1.EventTypeWarning, "FailedRescale", err.Error()) 201 | return fmt.Errorf("failed to rescale %s: %v", reference, err) 202 | } 203 | c.recorder.Eventf(cronhpa, corev1.EventTypeNormal, "SuccessfulRescale", "New size: %d", replicas) 204 | klog.Infof("Successful scale of %s, old size: %d, new size: %d", 205 | getCronHPAFullName(cronhpa), oldReplicas, replicas) 206 | } else { 207 | klog.V(4).Infof("No need to scale %s to %v, same replicas", getCronHPAFullName(cronhpa), replicas) 208 | } 209 | 210 | return nil 211 | } 212 | 213 | // scaleForResourceMappings attempts to fetch the scale for the 214 | // resource with the given name and namespace, trying each RESTMapping 215 | // in turn until a working one is found. If none work, the first error 216 | // is returned. It returns both the scale, as well as the group-resource from 217 | // the working mapping. 218 | func (c *Controller) scaleForResourceMappings(namespace, name string, mappings []*apimeta.RESTMapping) (*autoscalingv1.Scale, schema.GroupResource, error) { 219 | var firstErr error 220 | for i, mapping := range mappings { 221 | targetGR := mapping.Resource.GroupResource() 222 | scale, err := c.scaleNamespacer.Scales(namespace).Get(targetGR, name) 223 | if err == nil { 224 | return scale, targetGR, nil 225 | } 226 | 227 | // if this is the first error, remember it, 228 | // then go on and try other mappings until we find a good one 229 | if i == 0 { 230 | firstErr = err 231 | } 232 | } 233 | 234 | // make sure we handle an empty set of mappings 235 | if firstErr == nil { 236 | firstErr = fmt.Errorf("unrecognized resource") 237 | } 238 | 239 | return nil, schema.GroupResource{}, firstErr 240 | } 241 | 242 | func getLatestScheduledTime(cronhpa *v1.CronHPA) time.Time { 243 | if cronhpa.Status.LastScheduleTime != nil { 244 | return cronhpa.Status.LastScheduleTime.Time 245 | } else { 246 | return cronhpa.CreationTimestamp.Time 247 | } 248 | } 249 | 250 | func getCronHPAFullName(cronhpa *v1.CronHPA) string { 251 | return cronhpa.Namespace + "/" + cronhpa.Name 252 | } 253 | -------------------------------------------------------------------------------- /pkg/cronhpa/controller_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package cronhpa 19 | 20 | // TODO: add test cases 21 | -------------------------------------------------------------------------------- /pkg/cronhpa/crd.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package cronhpa 19 | 20 | import ( 21 | "reflect" 22 | 23 | extensionsobj "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" 24 | apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/klog" 27 | ) 28 | 29 | var CRD = &extensionsobj.CustomResourceDefinition{ 30 | ObjectMeta: metav1.ObjectMeta{ 31 | Name: "cronhpas.extensions.tkestack.io", 32 | }, 33 | TypeMeta: metav1.TypeMeta{ 34 | Kind: "CustomResourceDefinition", 35 | APIVersion: "apiextensions.k8s.io/v1beta1", 36 | }, 37 | Spec: extensionsobj.CustomResourceDefinitionSpec{ 38 | Group: "extensions.tkestack.io", 39 | Version: "v1", 40 | Scope: extensionsobj.ResourceScope("Namespaced"), 41 | Names: extensionsobj.CustomResourceDefinitionNames{ 42 | Plural: "cronhpas", 43 | Singular: "cronhpa", 44 | Kind: "CronHPA", 45 | ListKind: "CronHPAList", 46 | }, 47 | }, 48 | } 49 | 50 | func EnsureCRDCreated(client apiextensionsclient.Interface) (created bool, err error) { 51 | crdClient := client.ApiextensionsV1beta1().CustomResourceDefinitions() 52 | presetCRD, err := crdClient.Get(CRD.Name, metav1.GetOptions{}) 53 | if err == nil { 54 | if reflect.DeepEqual(presetCRD.Spec, CRD.Spec) { 55 | klog.V(1).Infof("CRD %s already exists", CRD.Name) 56 | } else { 57 | klog.V(3).Infof("Update CRD %s: %+v -> %+v", CRD.Name, presetCRD.Spec, CRD.Spec) 58 | newCRD := CRD 59 | newCRD.ResourceVersion = presetCRD.ResourceVersion 60 | // Update CRD 61 | if _, err := crdClient.Update(newCRD); err != nil { 62 | klog.Errorf("Error update CRD %s: %v", CRD.Name, err) 63 | return false, err 64 | } 65 | klog.V(1).Infof("Update CRD %s successfully.", CRD.Name) 66 | } 67 | } else { 68 | // If not exist, create a new one 69 | if _, err := crdClient.Create(CRD); err != nil { 70 | klog.Errorf("Error creating CRD %s: %v", CRD.Name, err) 71 | return false, err 72 | } 73 | klog.V(1).Infof("Create CRD %s successfully.", CRD.Name) 74 | } 75 | 76 | return true, nil 77 | } 78 | -------------------------------------------------------------------------------- /pkg/logs/logs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making TKEStack available. 3 | * 4 | * Copyright (C) 2012-2019 Tencent. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 7 | * this file except in compliance with the License. You may obtain a copy of the 8 | * License at 9 | * 10 | * https://opensource.org/licenses/Apache-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OF ANY KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations under the License. 16 | */ 17 | 18 | package logs 19 | 20 | import ( 21 | "flag" 22 | "log" 23 | "time" 24 | 25 | "github.com/spf13/pflag" 26 | "k8s.io/apimachinery/pkg/util/wait" 27 | "k8s.io/klog" 28 | ) 29 | 30 | var logFlushFreq = pflag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes") 31 | 32 | func init() { 33 | klog.InitFlags(flag.CommandLine) 34 | flag.Set("logtostderr", "true") 35 | } 36 | 37 | // KlogWriter serves as a bridge between the standard log package and the glog package. 38 | type KlogWriter struct{} 39 | 40 | // Write implements the io.Writer interface. 41 | func (writer KlogWriter) Write(data []byte) (n int, err error) { 42 | klog.InfoDepth(1, string(data)) 43 | return len(data), nil 44 | } 45 | 46 | // InitLogs initializes logs the way we want for kubernetes. 47 | func InitLogs() { 48 | log.SetOutput(KlogWriter{}) 49 | log.SetFlags(0) 50 | // The default glog flush interval is 5 seconds. 51 | go wait.Until(klog.Flush, *logFlushFreq, wait.NeverStop) 52 | } 53 | 54 | // FlushLogs flushes logs immediately. 55 | func FlushLogs() { 56 | klog.Flush() 57 | } 58 | --------------------------------------------------------------------------------