diff --git a/.gitignore b/.gitignore index 9e57e241d0..d8d5e72370 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,127 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` -*.test +# OSX leaves these everywhere on SMB shares +._* + +# OSX trash +.DS_Store + +# Eclipse files +.classpath +.project +.settings/** -# Output of the go coverage tool, specifically when used with LiteIDE -*.out +# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA +.idea/ +*.iml -# editor and IDE paraphernalia -.idea +# Vscode files .vscode -*.swp -*.swo + +# This is where the result of the go build goes +/output*/ +/_output*/ +/_output + +# Emacs save files *~ +\#*\# +.\#* + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# cscope-related files +cscope.* + +# Go test binaries +*.test +/hack/.test-cmd-auth + +# JUnit test output from ginkgo e2e tests +/junit*.xml + +# Mercurial files +**/.hg +**/.hg* + +# Vagrant +.vagrant +network_closure.sh + +# Local cluster env variables +/cluster/env.sh + +# Compiled binaries in third_party +/third_party/pkg + +# Also ignore etcd installed by hack/install-etcd.sh +/third_party/etcd* +/default.etcd + +# User cluster configs +.kubeconfig + +.tags* + +# Version file for dockerized build +.dockerized-kube-version-defs + +# Web UI +/www/master/node_modules/ +/www/master/npm-debug.log +/www/master/shared/config/development.json + +# Karma output +/www/test_out + +# precommit temporary directories created by ./hack/verify-generated-docs.sh and ./hack/lib/util.sh +/_tmp/ +/doc_tmp/ + +# Test artifacts produced by Jenkins jobs +/_artifacts/ + +# Go dependencies installed on Jenkins +/_gopath/ + +# Config directories created by gcloud and gsutil on Jenkins +/.config/gcloud*/ +/.gsutil/ + +# CoreOS stuff +/cluster/libvirt-coreos/coreos_*.img + +# Juju Stuff +/cluster/juju/charms/* +/cluster/juju/bundles/local.yaml + +# Downloaded Kubernetes binary release +/kubernetes/ + +# direnv .envrc files +.envrc + +# Downloaded kubernetes binary release tar ball +kubernetes.tar.gz + +# generated files in any directory +# TODO(thockin): uncomment this when we stop committing the generated files. +#zz_generated.* +#zz_generated.openapi.go + +# make-related metadata +/.make/ +# Just in time generated data in the source, should never be commited +/test/e2e/generated/bindata.go + +# This file used by some vendor repos (e.g. github.com/go-openapi/...) to store secret variables and should not be ignored +!\.drone\.sec + +/bazel-* +*.pyc -_output +# e2e log files +/hack/*.log diff --git a/Gopkg.lock b/Gopkg.lock index 53a3eedf84..b838137c68 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -187,7 +187,7 @@ version = "1.1.4" [[projects]] - digest = "1:2e5b5bac4f747101897401aba132817ab6b939120de01feb9e81e6322d118881" + digest = "1:e968e93cc59d6e1d913f881809239827f45c067e5ee5025002e68e39bba7dc87" name = "github.com/kubernetes-sigs/kube-batch" packages = [ "cmd/kube-batch/app", @@ -203,6 +203,7 @@ "pkg/client/informers/externalversions/scheduling/v1alpha1", "pkg/client/listers/scheduling/v1alpha1", "pkg/scheduler", + "pkg/scheduler/actions", "pkg/scheduler/actions/allocate", "pkg/scheduler/actions/backfill", "pkg/scheduler/actions/preempt", @@ -212,8 +213,12 @@ "pkg/scheduler/cache", "pkg/scheduler/conf", "pkg/scheduler/framework", + "pkg/scheduler/metrics", + "pkg/scheduler/plugins", + "pkg/scheduler/plugins/conformance", "pkg/scheduler/plugins/drf", "pkg/scheduler/plugins/gang", + "pkg/scheduler/plugins/nodeorder", "pkg/scheduler/plugins/predicates", "pkg/scheduler/plugins/priority", "pkg/scheduler/plugins/proportion", @@ -221,8 +226,8 @@ "pkg/version", ] pruneopts = "UT" - revision = "1d38effcf9cdec90d43c4782ad129282aa16cc12" - version = "v0.4" + revision = "3a1f9d7d0a7f7f12be6dd52927fcd0cd9de72ec7" + version = "v0.4.1" [[projects]] digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" @@ -327,11 +332,17 @@ version = "v2.0.1" [[projects]] - digest = "1:1cec06981f734a2a5927ce17a22b34e9f3fa458b5c70f5db9ed58f7e389338f7" + digest = "1:ef03fb1dae4d010196652653f00a8002e94c19bcabdc8ca5100a804ffef63a47" name = "github.com/prometheus/client_golang" - packages = ["prometheus"] + packages = [ + "prometheus", + "prometheus/internal", + "prometheus/promauto", + "prometheus/promhttp", + ] pruneopts = "UT" - revision = "e7e903064f5e9eb5da98208bae10b475d4db0f8c" + revision = "505eaef017263e299324067d40ca2c48f6a2cf50" + version = "v0.9.2" [[projects]] branch = "master" @@ -848,6 +859,34 @@ pruneopts = "UT" revision = "2325825fd8d83744804a701fd1e00d2ebee92cb3" +[[projects]] + digest = "1:dc1ae99dcab96913d81ae970b1f7a7411a54199b14bfb17a7e86f9a56979c720" + name = "k8s.io/code-generator" + packages = [ + "cmd/client-gen", + "cmd/client-gen/args", + "cmd/client-gen/generators", + "cmd/client-gen/generators/fake", + "cmd/client-gen/generators/scheme", + "cmd/client-gen/generators/util", + "cmd/client-gen/path", + "cmd/client-gen/types", + "cmd/deepcopy-gen", + "cmd/deepcopy-gen/args", + "cmd/defaulter-gen", + "cmd/defaulter-gen/args", + "cmd/informer-gen", + "cmd/informer-gen/args", + "cmd/informer-gen/generators", + "cmd/lister-gen", + "cmd/lister-gen/args", + "cmd/lister-gen/generators", + "pkg/util", + ] + pruneopts = "T" + revision = "c2090bec4d9b1fb25de3812f868accc2bc9ecbae" + version = "kubernetes-1.13.2" + [[projects]] branch = "master" digest = "1:e79eeb85f6f9636d4a9f1c36f1bdab1b2684db3621d7feea1d087edab281154c" @@ -863,11 +902,12 @@ [[projects]] branch = "master" - digest = "1:28514fabca4356625720ffb012408790a9d00d31963a9bd9daf7b5ccd894c301" + digest = "1:61024ed77a53ac618effed55043bf6a9afbdeb64136bd6a5b0c992d4c0363766" name = "k8s.io/gengo" packages = [ "args", "examples/deepcopy-gen/generators", + "examples/defaulter-gen/generators", "examples/set-gen/sets", "generator", "namer", @@ -894,7 +934,7 @@ revision = "ced9eb3070a5f1c548ef46e8dfe2a97c208d9f03" [[projects]] - digest = "1:17143472ba531e409a230b49319bb339dc6c898e77a6a537e8532c9b7a724735" + digest = "1:c42bc2f7b63720036166c67e48f2d2187e99626d677ef52a1baa3fc56b21efa6" name = "k8s.io/kubernetes" packages = [ "pkg/api/legacyscheme", @@ -923,6 +963,7 @@ "pkg/master/ports", "pkg/scheduler/algorithm", "pkg/scheduler/algorithm/predicates", + "pkg/scheduler/algorithm/priorities", "pkg/scheduler/algorithm/priorities/util", "pkg/scheduler/api", "pkg/scheduler/cache", @@ -937,6 +978,7 @@ "pkg/util/io", "pkg/util/mount", "pkg/util/net/sets", + "pkg/util/node", "pkg/util/nsenter", "pkg/util/parsers", "pkg/util/resizefs", @@ -983,8 +1025,10 @@ "github.com/kubernetes-sigs/kube-batch/pkg/client/informers/externalversions", "github.com/kubernetes-sigs/kube-batch/pkg/client/informers/externalversions/scheduling/v1alpha1", "github.com/kubernetes-sigs/kube-batch/pkg/client/listers/scheduling/v1alpha1", + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions", "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api", "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework", + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins", "github.com/onsi/ginkgo", "github.com/onsi/gomega", "github.com/spf13/cobra", @@ -1028,6 +1072,11 @@ "k8s.io/client-go/tools/record", "k8s.io/client-go/util/flowcontrol", "k8s.io/client-go/util/workqueue", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/lister-gen", "k8s.io/gengo/args", "k8s.io/gengo/examples/deepcopy-gen/generators", "k8s.io/kubernetes/pkg/scheduler/api", diff --git a/Gopkg.toml b/Gopkg.toml index b136a9b46f..20e72c11da 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -24,13 +24,21 @@ # go-tests = true # unused-packages = true +required = [ + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", +] + [[constraint]] branch = "master" name = "github.com/golang/glog" [[constraint]] name = "github.com/kubernetes-sigs/kube-batch" - version = "0.4.0" + version = "0.4.1" [[constraint]] name = "github.com/onsi/ginkgo" @@ -76,6 +84,14 @@ name = "k8s.io/apiextensions-apiserver" version = "kubernetes-1.13.2" +[[constraint]] + name = "k8s.io/code-generator" + version = "kubernetes-1.13.2" + [prune] go-tests = true unused-packages = true + + [[prune.project]] + name = "k8s.io/code-generator" + unused-packages = false diff --git a/Makefile b/Makefile index 15fd91b353..c64b75f745 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ BIN_DIR=_output/bin +IMAGE=volcano +TAG = 1.0 -all: controllers scheduler cli +all: controllers scheduler cli admission init: mkdir -p ${BIN_DIR} @@ -14,13 +16,38 @@ scheduler: cli: go build -o ${BIN_DIR}/vkctl ./cmd/cli +admission: + go build -o ${BIN_DIR}/vk-admission ./cmd/admission + +release: + CGO_ENABLED=0 go build -o ${BIN_DIR}/rel/vk-controllers ./cmd/controllers + CGO_ENABLED=0 go build -o ${BIN_DIR}/rel/vk-scheduler ./cmd/scheduler + CGO_ENABLED=0 go build -o ${BIN_DIR}/rel/vk-admission ./cmd/admission + +docker: release + for name in controllers scheduler admission; do\ + cp ${BIN_DIR}/rel/vk-$$name ./installer/dockerfile/$$name/; \ + docker build --no-cache -t $(IMAGE)-$$name:$(TAG) ./installer/dockerfile/$$name; \ + rm installer/dockerfile/$$name/vk-$$name; \ + done + generate-code: - go build -o ${BIN_DIR}/deepcopy-gen ./cmd/deepcopy-gen/ - ${BIN_DIR}/deepcopy-gen -i ./pkg/apis/batch/v1alpha1/ -O zz_generated.deepcopy - ${BIN_DIR}/deepcopy-gen -i ./pkg/apis/bus/v1alpha1/ -O zz_generated.deepcopy + ./hack/update-gencode.sh -e2e-test: all +e2e-test: ./hack/run-e2e.sh +unit-test: + go list ./... | grep -v e2e | xargs go test -v + +e2e-test-kind: + ./hack/run-e2e-kind.sh + clean: rm -rf _output/ + rm -f *.log + +verify: generate-code + hack/verify-gofmt.sh + hack/verify-golint.sh + hack/verify-gencode.sh diff --git a/example/job.yaml b/example/job.yaml index e4876a89c5..6c263be99c 100644 --- a/example/job.yaml +++ b/example/job.yaml @@ -18,7 +18,7 @@ spec: resources: requests: storage: 1Gi - taskSpecs: + tasks: - replicas: 6 template: metadata: diff --git a/hack/.golint_failures b/hack/.golint_failures new file mode 100644 index 0000000000..d3b42ea044 --- /dev/null +++ b/hack/.golint_failures @@ -0,0 +1,22 @@ +volcano.sh/volcano/cmd/admission/app +volcano.sh/volcano/cmd/admission/app/configure +volcano.sh/volcano/cmd/controllers/app +volcano.sh/volcano/cmd/controllers/app/options +volcano.sh/volcano/pkg/admission +volcano.sh/volcano/pkg/apis/batch/v1alpha1 +volcano.sh/volcano/pkg/apis/bus/v1alpha1 +volcano.sh/volcano/pkg/apis/helpers +volcano.sh/volcano/pkg/cli/job +volcano.sh/volcano/pkg/client/clientset/versioned +volcano.sh/volcano/pkg/client/clientset/versioned/fake +volcano.sh/volcano/pkg/client/clientset/versioned/scheme +volcano.sh/volcano/pkg/client/clientset/versioned/typed/batch/v1alpha1 +volcano.sh/volcano/pkg/client/clientset/versioned/typed/batch/v1alpha1/fake +volcano.sh/volcano/pkg/client/clientset/versioned/typed/bus/v1alpha1 +volcano.sh/volcano/pkg/client/clientset/versioned/typed/bus/v1alpha1/fake +volcano.sh/volcano/pkg/controllers/job +volcano.sh/volcano/pkg/controllers/job/apis +volcano.sh/volcano/pkg/controllers/job/cache +volcano.sh/volcano/pkg/controllers/job/state +volcano.sh/volcano/pkg/scheduler/algorithm/fairshare +volcano.sh/volcano/test/e2e diff --git a/hack/boilerplate/boilerplate.go.txt b/hack/boilerplate/boilerplate.go.txt index 239c0f288b..1f18995ab7 100644 --- a/hack/boilerplate/boilerplate.go.txt +++ b/hack/boilerplate/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright YEAR The Vulcan Authors. +Copyright YEAR The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/hack/update-gencode.sh b/hack/update-gencode.sh new file mode 100644 index 0000000000..0aaad3a1b3 --- /dev/null +++ b/hack/update-gencode.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Copyright 2019 The Volcano Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd) +#cd $ROOT +#SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. +CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} + +# generate the code with: +# --output-base because this script should also be able to run inside the vendor dir of +# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir +# instead of the $GOPATH directly. For normal projects this can be dropped. +${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ + volcano.sh/volcano/pkg/client volcano.sh/volcano/pkg/apis \ + "batch:v1alpha1 bus:v1alpha1" \ + --go-header-file ${SCRIPT_ROOT}/hack/boilerplate/boilerplate.go.txt + +# To use your own boilerplate text use: +# --go-header-file ${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt + diff --git a/hack/verify-fmt.sh b/hack/verify-fmt.sh new file mode 100644 index 0000000000..1c83594c81 --- /dev/null +++ b/hack/verify-fmt.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. +source "${KUBE_ROOT}/hack/lib/init.sh" + +kube::golang::verify_go_version + +cd "${KUBE_ROOT}" + +find_files() { + find . -not \( \ + \( \ + -wholename './output' \ + -o -wholename './_output' \ + -o -wholename './_gopath' \ + -o -wholename './release' \ + -o -wholename './target' \ + -o -wholename '*/third_party/*' \ + -o -wholename '*/vendor/*' \ + -o -wholename '*/contrib/*' \ + -o -wholename './staging/src/k8s.io/client-go/*vendor/*' \ + \) -prune \ + \) -name '*.go' +} +# gofmt exits with non-zero exit code if it finds a problem unrelated to +# formatting (e.g., a file does not parse correctly). Without "|| true" this +# would have led to no useful error message from gofmt, because the script would +# have failed before getting to the "echo" in the block below. +GOFMT="gofmt -d -s" +diff=$(find_files | xargs ${GOFMT} 2>&1) || true +if [[ -n "${diff}" ]]; then + echo "${diff}" + exit 1 +fi \ No newline at end of file diff --git a/hack/verify-gencode.sh b/hack/verify-gencode.sh new file mode 100644 index 0000000000..5434dcfe1e --- /dev/null +++ b/hack/verify-gencode.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# Copyright 2019 The Volcano Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. + +DIFFROOT="${SCRIPT_ROOT}/pkg" +TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg" +_tmp="${SCRIPT_ROOT}/_tmp" + +cleanup() { + rm -rf "${_tmp}" +} +trap "cleanup" EXIT SIGINT + +cleanup + +mkdir -p "${TMP_DIFFROOT}" +cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" + +"${SCRIPT_ROOT}/hack/update-gencode.sh" +echo "diffing ${DIFFROOT} against freshly generated codegen" +ret=0 +diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? +cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" +if [[ $ret -eq 0 ]] +then + echo "${DIFFROOT} up to date." +else + echo "${DIFFROOT} is out of date. Please run hack/update-gencode.sh" + exit 1 +fi diff --git a/hack/verify-golint.sh b/hack/verify-golint.sh new file mode 100644 index 0000000000..5faf8a2dbd --- /dev/null +++ b/hack/verify-golint.sh @@ -0,0 +1,113 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. +source "${KUBE_ROOT}/hack/lib/init.sh" + +kube::golang::verify_go_version + +cd "${KUBE_ROOT}" + +array_contains () { + local seeking=$1; shift # shift will iterate through the array + local in=1 # in holds the exit status for the function + for element; do + if [[ "$element" == "$seeking" ]]; then + in=0 # set in to 0 since we found it + break + fi + done + return $in +} + +# Check that the file is in alphabetical order +failure_file="${KUBE_ROOT}/hack/.golint_failures" +if ! diff -u "${failure_file}" <(LC_ALL=C sort "${failure_file}"); then + { + echo + echo "hack/.golint_failures is not in alphabetical order. Please sort it:" + echo + echo " LC_ALL=C sort -o hack/.golint_failures hack/.golint_failures" + echo + } >&2 + false +fi + +export IFS=$'\n' +# NOTE: when "go list -e ./..." is run within GOPATH, it turns the k8s.io/kubernetes +# as the prefix, however if we run it outside it returns the full path of the file +# with a leading underscore. We'll need to support both scenarios for all_packages. +all_packages=( + $(go list -e ./... | egrep -v "/(third_party|vendor|staging/src/k8s.io/client-go/pkg|generated|clientset_generated)" ) +) +failing_packages=( + $(cat $failure_file) +) +unset IFS +errors=() +not_failing=() +for p in "${all_packages[@]}"; do + # Run golint on package/*.go file explicitly to validate all go files + # and not just the ones for the current platform. + # Packages with a corresponding foo_test package will make golint fail + # with a useless error. Just ignore that, see golang/lint#68. + failedLint=$(golint "$p" 2>/dev/null) + array_contains "$p" "${failing_packages[@]}" && in_failing=$? || in_failing=$? + if [[ -n "${failedLint}" ]] && [[ "${in_failing}" -ne "0" ]]; then + errors+=( "${failedLint}" ) + fi + if [[ -z "${failedLint}" ]] && [[ "${in_failing}" -eq "0" ]]; then + not_failing+=( $p ) + fi +done + +# Check that all failing_packages actually still exist +gone=() +for p in "${failing_packages[@]}"; do + array_contains "$p" "${all_packages[@]}" || gone+=( "$p" ) +done + +# Check to be sure all the packages that should pass lint are. +if [ ${#errors[@]} -eq 0 ]; then + echo 'Congratulations! All Go source files have been linted.' +else + { + echo "Errors from golint:" + for err in "${errors[@]}"; do + echo "$err" + done + echo + echo 'Please review the above warnings. You can test via "golint" and commit the result.' + echo 'If the above warnings do not make sense, you can exempt this package from golint' + echo 'checking by adding it to hack/.golint_failures (if your reviewer is okay with it).' + echo + } >&2 + false +fi + +if [[ ${#not_failing[@]} -gt 0 ]]; then + { + echo "Some packages in hack/.golint_failures are passing golint. Please remove them." + echo + for p in "${not_failing[@]}"; do + echo " $p" + done + echo + } >&2 + false +fi + +if [[ ${#gone[@]} -gt 0 ]]; then + { + echo "Some packages in hack/.golint_failures do not exist anymore. Please remove them." + echo + for p in "${gone[@]}"; do + echo " $p" + done + echo + } >&2 + false +fi diff --git a/pkg/client/clientset/versioned/typed/batch/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/batch/v1alpha1/generated_expansion.go index 7c0c20c7a2..6db1798231 100644 --- a/pkg/client/clientset/versioned/typed/batch/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/batch/v1alpha1/generated_expansion.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/clientset/versioned/typed/batch/v1alpha1/job.go b/pkg/client/clientset/versioned/typed/batch/v1alpha1/job.go index 259dd4d082..bb47bd1015 100644 --- a/pkg/client/clientset/versioned/typed/batch/v1alpha1/job.go +++ b/pkg/client/clientset/versioned/typed/batch/v1alpha1/job.go @@ -21,12 +21,13 @@ package v1alpha1 import ( "time" - v1alpha1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" - scheme "volcano.sh/volcano/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + + v1alpha1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" + scheme "volcano.sh/volcano/pkg/client/clientset/versioned/scheme" ) // JobsGetter has a method to return a JobInterface. diff --git a/pkg/client/clientset/versioned/typed/bus/v1alpha1/command.go b/pkg/client/clientset/versioned/typed/bus/v1alpha1/command.go index 6a0b1392bf..3613296c0e 100644 --- a/pkg/client/clientset/versioned/typed/bus/v1alpha1/command.go +++ b/pkg/client/clientset/versioned/typed/bus/v1alpha1/command.go @@ -21,12 +21,13 @@ package v1alpha1 import ( "time" - v1alpha1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" - scheme "volcano.sh/volcano/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + + v1alpha1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" + scheme "volcano.sh/volcano/pkg/client/clientset/versioned/scheme" ) // CommandsGetter has a method to return a CommandInterface. diff --git a/pkg/client/clientset/versioned/typed/bus/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/bus/v1alpha1/generated_expansion.go index 55e8cd3bf5..ded6d68ded 100644 --- a/pkg/client/clientset/versioned/typed/bus/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/bus/v1alpha1/generated_expansion.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/informers/externalversions/bus/v1alpha1/command.go b/pkg/client/informers/externalversions/bus/v1alpha1/command.go index 3350ce62ec..050c06bbf7 100644 --- a/pkg/client/informers/externalversions/bus/v1alpha1/command.go +++ b/pkg/client/informers/externalversions/bus/v1alpha1/command.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index e3fc754615..2b25eaa57a 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go index 1e7b8e4a03..dd28ecd9dd 100644 --- a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/listers/batch/v1alpha1/expansion_generated.go b/pkg/client/listers/batch/v1alpha1/expansion_generated.go index f10fb62fa5..c7b9108f0f 100644 --- a/pkg/client/listers/batch/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/batch/v1alpha1/expansion_generated.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/client/listers/batch/v1alpha1/job.go b/pkg/client/listers/batch/v1alpha1/job.go index c56e9ea0b5..71401c5c2b 100644 --- a/pkg/client/listers/batch/v1alpha1/job.go +++ b/pkg/client/listers/batch/v1alpha1/job.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,10 +19,10 @@ limitations under the License. package v1alpha1 import ( - v1alpha1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" + v1alpha1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" ) // JobLister helps list Jobs. diff --git a/pkg/client/listers/bus/v1alpha1/command.go b/pkg/client/listers/bus/v1alpha1/command.go index 7742aa09d1..d8680a12c9 100644 --- a/pkg/client/listers/bus/v1alpha1/command.go +++ b/pkg/client/listers/bus/v1alpha1/command.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,10 +19,11 @@ limitations under the License. package v1alpha1 import ( - v1alpha1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" + + v1alpha1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" ) // CommandLister helps list Commands. diff --git a/pkg/client/listers/bus/v1alpha1/expansion_generated.go b/pkg/client/listers/bus/v1alpha1/expansion_generated.go index f0a2fa2164..a2482e527b 100644 --- a/pkg/client/listers/bus/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/bus/v1alpha1/expansion_generated.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +Copyright 2019 The Volcano Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/controllers/job/apis/types.go b/pkg/controllers/job/apis/types.go index af7aef6f2b..631a050c83 100644 --- a/pkg/controllers/job/apis/types.go +++ b/pkg/controllers/job/apis/types.go @@ -17,21 +17,129 @@ limitations under the License. package apis import ( + "fmt" + "k8s.io/api/core/v1" - vkbatchv1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" + "volcano.sh/volcano/pkg/apis/batch/v1alpha1" ) type JobInfo struct { - Job *vkbatchv1.Job + Namespace string + Name string + + Job *v1alpha1.Job Pods map[string]map[string]*v1.Pod } +func (ji *JobInfo) Clone() *JobInfo { + job := &JobInfo{ + Namespace: ji.Namespace, + Name: ji.Name, + Job: ji.Job, + + Pods: make(map[string]map[string]*v1.Pod), + } + + for key, pods := range ji.Pods { + job.Pods[key] = make(map[string]*v1.Pod) + for pn, pod := range pods { + job.Pods[key][pn] = pod + } + } + + return job +} + +func (ji *JobInfo) SetJob(job *v1alpha1.Job) { + ji.Name = job.Name + ji.Namespace = job.Namespace + ji.Job = job +} + +func (ji *JobInfo) AddPod(pod *v1.Pod) error { + taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] + if !found { + return fmt.Errorf("failed to taskName of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + + _, found = pod.Annotations[v1alpha1.JobVersion] + if !found { + return fmt.Errorf("failed to find jobVersion of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + + if _, found := ji.Pods[taskName]; !found { + ji.Pods[taskName] = make(map[string]*v1.Pod) + } + if _, found := ji.Pods[taskName][pod.Name]; found { + return fmt.Errorf("duplicated pod") + } + ji.Pods[taskName][pod.Name] = pod + + return nil +} + +func (ji *JobInfo) UpdatePod(pod *v1.Pod) error { + taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] + if !found { + return fmt.Errorf("failed to find taskName of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + _, found = pod.Annotations[v1alpha1.JobVersion] + if !found { + return fmt.Errorf("failed to find jobVersion of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + + if _, found := ji.Pods[taskName]; !found { + return fmt.Errorf("can not find task %s in cache", taskName) + } + if _, found := ji.Pods[taskName][pod.Name]; !found { + return fmt.Errorf("can not find pod <%s/%s> in cache", + pod.Namespace, pod.Name) + } + ji.Pods[taskName][pod.Name] = pod + + return nil +} + +func (ji *JobInfo) DeletePod(pod *v1.Pod) error { + taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] + if !found { + return fmt.Errorf("failed to find taskName of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + _, found = pod.Annotations[v1alpha1.JobVersion] + if !found { + return fmt.Errorf("failed to find jobVersion of Pod <%s/%s>", + pod.Namespace, pod.Name) + } + + if pods, found := ji.Pods[taskName]; found { + delete(pods, pod.Name) + if len(pods) == 0 { + delete(ji.Pods, taskName) + } + } + + return nil +} + type Request struct { Namespace string JobName string TaskName string - Event vkbatchv1.Event - Action vkbatchv1.Action + Event v1alpha1.Event + Action v1alpha1.Action + JobVersion int32 +} + +func (r Request) String() string { + return fmt.Sprintf( + "Job: %s/%s, Task:%s, Event:%s, Action:%s, JobVersion: %d", + r.Namespace, r.JobName, r.TaskName, r.Event, r.Action, r.JobVersion) + } diff --git a/pkg/controllers/job/cache/cache.go b/pkg/controllers/job/cache/cache.go index 62fa87e134..d9866c2588 100644 --- a/pkg/controllers/job/cache/cache.go +++ b/pkg/controllers/job/cache/cache.go @@ -19,62 +19,44 @@ package cache import ( "fmt" "sync" - "time" "github.com/golang/glog" "k8s.io/api/core/v1" - "k8s.io/client-go/tools/cache" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/workqueue" "volcano.sh/volcano/pkg/apis/batch/v1alpha1" "volcano.sh/volcano/pkg/controllers/job/apis" ) -type Cache interface { - Run(stopCh <-chan struct{}) - - Get(key string) (*apis.JobInfo, error) - GetStatus(key string) (*v1alpha1.JobStatus, error) - Add(obj *v1alpha1.Job) error - Update(obj *v1alpha1.Job) error - Delete(obj *v1alpha1.Job) error - - AddPod(pod *v1.Pod) error - UpdatePod(pod *v1.Pod) error - DeletePod(pod *v1.Pod) error -} - type jobCache struct { sync.Mutex jobs map[string]*apis.JobInfo - deletedJobs *cache.FIFO + deletedJobs workqueue.RateLimitingInterface } func keyFn(ns, name string) string { return fmt.Sprintf("%s/%s", ns, name) } +func JobKeyByName(namespace string, name string) string { + return keyFn(namespace, name) +} + func JobKeyByReq(req *apis.Request) string { return keyFn(req.Namespace, req.JobName) } -func JobKey(req *v1alpha1.Job) string { - return keyFn(req.Namespace, req.Name) +func JobKey(job *v1alpha1.Job) string { + return keyFn(job.Namespace, job.Name) } func jobTerminated(job *apis.JobInfo) bool { return job.Job == nil && len(job.Pods) == 0 } -func jobKey(obj interface{}) (string, error) { - job, ok := obj.(*v1alpha1.Job) - if !ok { - return "", fmt.Errorf("failed to convert <%v> to *v1alpha1.Job", obj) - } - return keyFn(job.Namespace, job.Name), nil -} - func jobKeyOfPod(pod *v1.Pod) (string, error) { jobName, found := pod.Annotations[v1alpha1.JobNameKey] if !found { @@ -88,7 +70,7 @@ func jobKeyOfPod(pod *v1.Pod) (string, error) { func New() Cache { return &jobCache{ jobs: map[string]*apis.JobInfo{}, - deletedJobs: cache.NewFIFO(jobKey), + deletedJobs: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), } } @@ -105,20 +87,7 @@ func (jc *jobCache) Get(key string) (*apis.JobInfo, error) { return nil, fmt.Errorf("job <%s> is not ready", key) } - jobInfo := &apis.JobInfo{ - Job: job.Job, - Pods: make(map[string]map[string]*v1.Pod), - } - - // Copy Pods. - for key, pods := range job.Pods { - jobInfo.Pods[key] = make(map[string]*v1.Pod) - for pn, pod := range pods { - jobInfo.Pods[key][pn] = pod - } - } - - return jobInfo, nil + return job.Clone(), nil } func (jc *jobCache) GetStatus(key string) (*v1alpha1.JobStatus, error) { @@ -135,24 +104,25 @@ func (jc *jobCache) GetStatus(key string) (*v1alpha1.JobStatus, error) { return &status, nil } -func (jc *jobCache) Add(obj *v1alpha1.Job) error { +func (jc *jobCache) Add(job *v1alpha1.Job) error { jc.Lock() defer jc.Unlock() - key := JobKey(obj) - if job, found := jc.jobs[key]; found { - if job.Job == nil { - job.Job = obj + key := JobKey(job) + if jobInfo, found := jc.jobs[key]; found { + if jobInfo.Job == nil { + jobInfo.SetJob(job) + return nil } - - glog.Errorf("Found duplicated jobs by <%v>", key) - - return fmt.Errorf("duplicated job <%v>", key) + return fmt.Errorf("duplicated jobInfo <%v>", key) } jc.jobs[key] = &apis.JobInfo{ - Job: obj, + Name: job.Name, + Namespace: job.Namespace, + + Job: job, Pods: make(map[string]map[string]*v1.Pod), } @@ -181,6 +151,7 @@ func (jc *jobCache) Delete(obj *v1alpha1.Job) error { if jobInfo, found := jc.jobs[key]; !found { return fmt.Errorf("failed to find job <%v>", key) } else { + jobInfo.Job = nil jc.deleteJob(jobInfo) } @@ -204,21 +175,7 @@ func (jc *jobCache) AddPod(pod *v1.Pod) error { jc.jobs[key] = job } - taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] - if !found { - return fmt.Errorf("failed to taskName of Pod <%s/%s>", - pod.Namespace, pod.Name) - } - - if _, found := job.Pods[taskName]; !found { - job.Pods[taskName] = make(map[string]*v1.Pod) - } - if _, found := job.Pods[taskName][pod.Name]; found { - return fmt.Errorf("duplicated pod") - } - job.Pods[taskName][pod.Name] = pod - - return nil + return job.AddPod(pod) } func (jc *jobCache) UpdatePod(pod *v1.Pod) error { @@ -238,18 +195,7 @@ func (jc *jobCache) UpdatePod(pod *v1.Pod) error { jc.jobs[key] = job } - taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] - if !found { - return fmt.Errorf("failed to taskName of Pod <%s/%s>", - pod.Namespace, pod.Name) - } - - if _, found := job.Pods[taskName]; !found { - job.Pods[taskName] = make(map[string]*v1.Pod) - } - job.Pods[taskName][pod.Name] = pod - - return nil + return job.UpdatePod(pod) } func (jc *jobCache) DeletePod(pod *v1.Pod) error { @@ -269,66 +215,51 @@ func (jc *jobCache) DeletePod(pod *v1.Pod) error { jc.jobs[key] = job } - taskName, found := pod.Annotations[v1alpha1.TaskSpecKey] - if !found { - return fmt.Errorf("failed to taskName of Pod <%s/%s>", - pod.Namespace, pod.Name) + if err := job.DeletePod(pod); err != nil { + return err } - if pods, found := job.Pods[taskName]; found { - delete(pods, pod.Name) + if jc.jobs[key].Job == nil { + jc.deleteJob(job) } - jc.deleteJob(job) - return nil } func (jc *jobCache) Run(stopCh <-chan struct{}) { - go jc.cleanupJobs() + wait.Until(jc.processCleanupJob, 0, stopCh) } -func (jc *jobCache) cleanupJobs() { - for { - err := jc.processCleanupJob() - if err != nil { - glog.Errorf("Failed to process job clean up: %v", err) - } +func (jc *jobCache) processCleanupJob() { + obj, shutdown := jc.deletedJobs.Get() + if shutdown { + return } -} - -func (jc *jobCache) processCleanupJob() error { - _, err := jc.deletedJobs.Pop(func(obj interface{}) error { - job, ok := obj.(*apis.JobInfo) - if !ok { - return fmt.Errorf("failed to convert %v to *v1.Pod", obj) - } - - func() { - jc.Mutex.Lock() - defer jc.Mutex.Unlock() + defer jc.deletedJobs.Done(obj) - if jobTerminated(job) { - key, _ := jobKey(job) - delete(jc.jobs, key) - glog.V(3).Infof("Job <%s> was deleted.", key) - } else { - // Retry - jc.deleteJob(job) - } - }() + job, ok := obj.(*apis.JobInfo) + if !ok { + glog.Errorf("failed to convert %v to *apis.JobInfo", obj) + return + } - return nil - }) + jc.Mutex.Lock() + defer jc.Mutex.Unlock() - return err + if jobTerminated(job) { + jc.deletedJobs.Forget(obj) + key := keyFn(job.Namespace, job.Name) + delete(jc.jobs, key) + glog.V(3).Infof("Job <%s> was deleted.", key) + } else { + // Retry + jc.deleteJob(job) + } } func (jc *jobCache) deleteJob(job *apis.JobInfo) { glog.V(3).Infof("Try to delete Job <%v/%v>", - job.Job.Namespace, job.Job.Name) + job.Namespace, job.Name) - time.AfterFunc(1*time.Second, func() { - jc.deletedJobs.AddIfNotPresent(job) - }) + jc.deletedJobs.AddRateLimited(job) } diff --git a/pkg/controllers/job/cache/interface.go b/pkg/controllers/job/cache/interface.go new file mode 100644 index 0000000000..e9a4506289 --- /dev/null +++ b/pkg/controllers/job/cache/interface.go @@ -0,0 +1,38 @@ +/* +Copyright 2019 The Volcano Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "k8s.io/api/core/v1" + + "volcano.sh/volcano/pkg/apis/batch/v1alpha1" + "volcano.sh/volcano/pkg/controllers/job/apis" +) + +type Cache interface { + Run(stopCh <-chan struct{}) + + Get(key string) (*apis.JobInfo, error) + GetStatus(key string) (*v1alpha1.JobStatus, error) + Add(obj *v1alpha1.Job) error + Update(obj *v1alpha1.Job) error + Delete(obj *v1alpha1.Job) error + + AddPod(pod *v1.Pod) error + UpdatePod(pod *v1.Pod) error + DeletePod(pod *v1.Pod) error +} diff --git a/pkg/controllers/job/job_controller.go b/pkg/controllers/job/job_controller.go index 0dffd34edf..f425d2a076 100644 --- a/pkg/controllers/job/job_controller.go +++ b/pkg/controllers/job/job_controller.go @@ -27,9 +27,11 @@ import ( "k8s.io/client-go/informers" coreinformers "k8s.io/client-go/informers/core/v1" "k8s.io/client-go/kubernetes" + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" corelisters "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" kbver "github.com/kubernetes-sigs/kube-batch/pkg/client/clientset/versioned" @@ -40,6 +42,7 @@ import ( v1corev1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" "volcano.sh/volcano/pkg/apis/helpers" vkver "volcano.sh/volcano/pkg/client/clientset/versioned" + vkscheme "volcano.sh/volcano/pkg/client/clientset/versioned/scheme" vkinfoext "volcano.sh/volcano/pkg/client/informers/externalversions" vkbatchinfo "volcano.sh/volcano/pkg/client/informers/externalversions/batch/v1alpha1" vkcoreinfo "volcano.sh/volcano/pkg/client/informers/externalversions/bus/v1alpha1" @@ -87,19 +90,33 @@ type Controller struct { cmdSynced func() bool // queue that need to sync up - queue workqueue.RateLimitingInterface - cache jobcache.Cache + queue workqueue.RateLimitingInterface + commandQueue workqueue.RateLimitingInterface + cache jobcache.Cache + //Job Event recorder + recorder record.EventRecorder } // NewJobController create new Job Controller func NewJobController(config *rest.Config) *Controller { + + kubeClients := kubernetes.NewForConfigOrDie(config) + + //Initialize event client + eventBroadcaster := record.NewBroadcaster() + eventBroadcaster.StartLogging(glog.Infof) + eventBroadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: kubeClients.CoreV1().Events("")}) + recorder := eventBroadcaster.NewRecorder(vkscheme.Scheme, v1.EventSource{Component: "vk-controller"}) + cc := &Controller{ - config: config, - kubeClients: kubernetes.NewForConfigOrDie(config), - vkClients: vkver.NewForConfigOrDie(config), - kbClients: kbver.NewForConfigOrDie(config), - queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), - cache: jobcache.New(), + config: config, + kubeClients: kubeClients, + vkClients: vkver.NewForConfigOrDie(config), + kbClients: kbver.NewForConfigOrDie(config), + queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), + commandQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), + cache: jobcache.New(), + recorder: recorder, } cc.jobInformer = vkinfoext.NewSharedInformerFactory(cc.vkClients, 0).Batch().V1alpha1().Jobs() @@ -121,7 +138,7 @@ func NewJobController(config *rest.Config) *Controller { if cmd, ok := t.Obj.(*v1corev1.Command); ok { return helpers.ControlledBy(cmd, helpers.JobKind) } - runtime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Pod", obj)) + runtime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Command", obj)) return false default: runtime.HandleError(fmt.Errorf("unable to handle object %T", obj)) @@ -172,6 +189,9 @@ func NewJobController(config *rest.Config) *Controller { cc.svcSynced = cc.svcInformer.Informer().HasSynced cc.pgInformer = kbinfoext.NewSharedInformerFactory(cc.kbClients, 0).Scheduling().V1alpha1().PodGroups() + cc.pgInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + UpdateFunc: cc.updatePodGroup, + }) cc.pgLister = cc.pgInformer.Lister() cc.pgSynced = cc.pgInformer.Informer().HasSynced @@ -194,6 +214,7 @@ func (cc *Controller) Run(stopCh <-chan struct{}) { cache.WaitForCacheSync(stopCh, cc.jobSynced, cc.podSynced, cc.pgSynced, cc.svcSynced, cc.cmdSynced, cc.pvcSynced) + go wait.Until(cc.handleCommands, 0, stopCh) go wait.Until(cc.worker, 0, stopCh) go cc.cache.Run(stopCh) @@ -215,6 +236,7 @@ func (cc *Controller) worker() { jobInfo, err := cc.cache.Get(jobcache.JobKeyByReq(&req)) if err != nil { + // TODO(k82cn): ignore not-ready error. glog.Errorf("Failed to get job by <%v> from cache: %v", req, err) return } @@ -235,5 +257,10 @@ func (cc *Controller) worker() { jobInfo.Job.Namespace, jobInfo.Job.Name, err) // If any error, requeue it. cc.queue.AddRateLimited(req) + return } + + // If no error, forget it. + cc.queue.Forget(req) } + diff --git a/pkg/controllers/job/job_controller_actions.go b/pkg/controllers/job/job_controller_actions.go index c8b878e391..429c66c2d2 100644 --- a/pkg/controllers/job/job_controller_actions.go +++ b/pkg/controllers/job/job_controller_actions.go @@ -27,6 +27,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + admissioncontroller "volcano.sh/volcano/pkg/admission" vkv1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" "volcano.sh/volcano/pkg/apis/helpers" "volcano.sh/volcano/pkg/controllers/job/apis" @@ -38,6 +39,9 @@ func (cc *Controller) killJob(jobInfo *apis.JobInfo, nextState state.NextStateFn defer glog.V(3).Infof("Finished Job <%s/%s> killing", jobInfo.Job.Namespace, jobInfo.Job.Name) job := jobInfo.Job + //Job version is bumped only when job is killed + job.Status.Version = job.Status.Version + 1 + glog.Infof("Current Version is: %d of job: %s/%s", job.Status.Version, job.Namespace, job.Name) if job.DeletionTimestamp != nil { glog.Infof("Job <%s/%s> is terminating, skip management process.", job.Namespace, job.Name) @@ -53,6 +57,12 @@ func (cc *Controller) killJob(jobInfo *apis.JobInfo, nextState state.NextStateFn for _, pod := range pods { total++ + if pod.DeletionTimestamp != nil { + glog.Infof("Pod <%s/%s> is terminating", pod.Namespace, pod.Name) + terminating++ + continue + } + switch pod.Status.Phase { case v1.PodRunning: err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil) @@ -73,7 +83,13 @@ func (cc *Controller) killJob(jobInfo *apis.JobInfo, nextState state.NextStateFn case v1.PodSucceeded: succeeded++ case v1.PodFailed: - failed++ + err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil) + if err != nil { + failed++ + errs = append(errs, err) + continue + } + terminating++ } } } @@ -90,6 +106,7 @@ func (cc *Controller) killJob(jobInfo *apis.JobInfo, nextState state.NextStateFn Succeeded: succeeded, Failed: failed, Terminating: terminating, + Version: job.Status.Version, MinAvailable: int32(job.Spec.MinAvailable), } @@ -98,7 +115,7 @@ func (cc *Controller) killJob(jobInfo *apis.JobInfo, nextState state.NextStateFn } // Update Job status - if job, err := cc.vkClients.BatchV1alpha1().Jobs(job.Namespace).Update(job); err != nil { + if job, err := cc.vkClients.BatchV1alpha1().Jobs(job.Namespace).UpdateStatus(job); err != nil { glog.Errorf("Failed to update status of Job %v/%v: %v", job.Namespace, job.Name, err) return err @@ -136,6 +153,7 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn defer glog.V(3).Infof("Finished Job <%s/%s> sync up", jobInfo.Job.Namespace, jobInfo.Job.Name) job := jobInfo.Job + glog.Infof("Current Version is: %d of job: %s/%s", job.Status.Version, job.Namespace, job.Name) if job.DeletionTimestamp != nil { glog.Infof("Job <%s/%s> is terminating, skip management process.", @@ -143,11 +161,6 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn return nil } - // TODO(k82cn): add WebHook to validate job. - if err := validate(job); err != nil { - glog.Errorf("Failed to validate Job <%s/%s>: %v", job.Namespace, job.Name, err) - } - if err := cc.createPodGroupIfNotExist(job); err != nil { return err } @@ -160,19 +173,17 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn return err } + var running, pending, terminating, succeeded, failed int32 + var podToCreate []*v1.Pod var podToDelete []*v1.Pod - - var running, pending, terminating, succeeded, failed int32 + var creationErrs []error + var deletionErrs []error for _, ts := range job.Spec.Tasks { + ts.Template.Name = ts.Name tc := ts.Template.DeepCopy() name := ts.Template.Name - // TODO(k82cn): the template name should be set in default func. - if len(name) == 0 { - name = vkv1.DefaultTaskSpec - tc.Name = vkv1.DefaultTaskSpec - } pods, found := jobInfo.Pods[name] if !found { @@ -185,6 +196,13 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn newPod := createJobPod(job, tc, i) podToCreate = append(podToCreate, newPod) } else { + if pod.DeletionTimestamp != nil { + glog.Infof("Pod <%s/%s> is terminating", pod.Namespace, pod.Name) + terminating++ + delete(pods, podName) + continue + } + switch pod.Status.Phase { case v1.PodPending: if pod.DeletionTimestamp != nil { @@ -210,61 +228,59 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn for _, pod := range pods { podToDelete = append(podToDelete, pod) } + } - var creationErrs []error - waitCreationGroup := sync.WaitGroup{} - waitCreationGroup.Add(len(podToCreate)) - for _, pod := range podToCreate { - go func(pod *v1.Pod) { - defer waitCreationGroup.Done() - _, err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Create(pod) - if err != nil { - // Failed to create Pod, waitCreationGroup a moment and then create it again - // This is to ensure all podsMap under the same Job created - // So gang-scheduling could schedule the Job successfully - glog.Errorf("Failed to create pod %s for Job %s, err %#v", - pod.Name, job.Name, err) - creationErrs = append(creationErrs, err) - } else { - pending++ - glog.V(3).Infof("Created Task <%s> of Job <%s/%s>", - pod.Name, job.Namespace, job.Name) - } - }(pod) - } - waitCreationGroup.Wait() + waitCreationGroup := sync.WaitGroup{} + waitCreationGroup.Add(len(podToCreate)) + for _, pod := range podToCreate { + go func(pod *v1.Pod) { + defer waitCreationGroup.Done() + _, err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Create(pod) + if err != nil { + // Failed to create Pod, waitCreationGroup a moment and then create it again + // This is to ensure all podsMap under the same Job created + // So gang-scheduling could schedule the Job successfully + glog.Errorf("Failed to create pod %s for Job %s, err %#v", + pod.Name, job.Name, err) + creationErrs = append(creationErrs, err) + } else { + pending++ + glog.V(3).Infof("Created Task <%s> of Job <%s/%s>", + pod.Name, job.Namespace, job.Name) + } + }(pod) + } + waitCreationGroup.Wait() - if len(creationErrs) != 0 { - return fmt.Errorf("failed to create %d pods of %d", len(creationErrs), len(podToCreate)) - } + if len(creationErrs) != 0 { + return fmt.Errorf("failed to create %d pods of %d", len(creationErrs), len(podToCreate)) + } - // Delete unnecessary pods. - var deletionErrs []error - waitDeletionGroup := sync.WaitGroup{} - waitDeletionGroup.Add(len(podToDelete)) - for _, pod := range podToDelete { - go func(pod *v1.Pod) { - defer waitDeletionGroup.Done() - err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil) - if err != nil { - // Failed to create Pod, waitCreationGroup a moment and then create it again - // This is to ensure all podsMap under the same Job created - // So gang-scheduling could schedule the Job successfully - glog.Errorf("Failed to delete pod %s for Job %s, err %#v", - pod.Name, job.Name, err) - deletionErrs = append(deletionErrs, err) - } else { - glog.V(3).Infof("Deleted Task <%s> of Job <%s/%s>", - pod.Name, job.Namespace, job.Name) - terminating++ - } - }(pod) - } - waitDeletionGroup.Wait() + // Delete unnecessary pods. + waitDeletionGroup := sync.WaitGroup{} + waitDeletionGroup.Add(len(podToDelete)) + for _, pod := range podToDelete { + go func(pod *v1.Pod) { + defer waitDeletionGroup.Done() + err := cc.kubeClients.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil) + if err != nil { + // Failed to create Pod, waitCreationGroup a moment and then create it again + // This is to ensure all podsMap under the same Job created + // So gang-scheduling could schedule the Job successfully + glog.Errorf("Failed to delete pod %s for Job %s, err %#v", + pod.Name, job.Name, err) + deletionErrs = append(deletionErrs, err) + } else { + glog.V(3).Infof("Deleted Task <%s> of Job <%s/%s>", + pod.Name, job.Namespace, job.Name) + terminating++ + } + }(pod) + } + waitDeletionGroup.Wait() - if len(deletionErrs) != 0 { - return fmt.Errorf("failed to delete %d pods of %d", len(deletionErrs), len(podToDelete)) - } + if len(deletionErrs) != 0 { + return fmt.Errorf("failed to delete %d pods of %d", len(deletionErrs), len(podToDelete)) } job.Status = vkv1.JobStatus{ @@ -275,6 +291,7 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn Succeeded: succeeded, Failed: failed, Terminating: terminating, + Version: job.Status.Version, MinAvailable: int32(job.Spec.MinAvailable), } @@ -282,7 +299,7 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn job.Status.State = nextState(job.Status) } - if job, err := cc.vkClients.BatchV1alpha1().Jobs(job.Namespace).Update(job); err != nil { + if job, err := cc.vkClients.BatchV1alpha1().Jobs(job.Namespace).UpdateStatus(job); err != nil { glog.Errorf("Failed to update status of Job %v/%v: %v", job.Namespace, job.Name, err) return err @@ -295,6 +312,16 @@ func (cc *Controller) syncJob(jobInfo *apis.JobInfo, nextState state.NextStateFn return nil } +func (cc *Controller) calculateVersion(current int32, bumpVersion bool) int32 { + if current == 0 { + current += 1 + } + if bumpVersion { + current += 1 + } + return current +} + func (cc *Controller) createServiceIfNotExist(job *vkv1.Job) error { // If Service does not exist, create one for Job. if _, err := cc.svcLister.Services(job.Namespace).Get(job.Name); err != nil { @@ -334,8 +361,8 @@ func (cc *Controller) createServiceIfNotExist(job *vkv1.Job) error { func (cc *Controller) createJobIOIfNotExist(job *vkv1.Job) error { // If input/output PVC does not exist, create them for Job. - inputPVC := fmt.Sprintf("%s-input", job.Name) - outputPVC := fmt.Sprintf("%s-output", job.Name) + inputPVC := job.Annotations[admissioncontroller.PVCInputName] + outputPVC := job.Annotations[admissioncontroller.PVCOutputName] if job.Spec.Input != nil { if job.Spec.Input.VolumeClaim != nil { if _, err := cc.pvcLister.PersistentVolumeClaims(job.Namespace).Get(inputPVC); err != nil { diff --git a/pkg/controllers/job/job_controller_handler.go b/pkg/controllers/job/job_controller_handler.go index 778f3f4ade..4672262b9f 100644 --- a/pkg/controllers/job/job_controller_handler.go +++ b/pkg/controllers/job/job_controller_handler.go @@ -17,14 +17,20 @@ limitations under the License. package job import ( + "fmt" + "reflect" + "strconv" + "github.com/golang/glog" "k8s.io/api/core/v1" "k8s.io/client-go/tools/cache" + kbtype "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" vkbatchv1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" vkbusv1 "volcano.sh/volcano/pkg/apis/bus/v1alpha1" "volcano.sh/volcano/pkg/controllers/job/apis" + vkcache "volcano.sh/volcano/pkg/controllers/job/cache" ) func (cc *Controller) addCommand(obj interface{}) { @@ -34,26 +40,7 @@ func (cc *Controller) addCommand(obj interface{}) { return } - req := apis.Request{ - Namespace: cmd.Namespace, - JobName: cmd.TargetObject.Name, - - Event: vkbatchv1.CommandIssuedEvent, - Action: vkbatchv1.Action(cmd.Action), - } - - glog.V(3).Infof("Try to execute command <%v> on Job <%s/%s>", - cmd.Action, req.Namespace, req.JobName) - - cc.queue.Add(req) - - go func() { - // TODO(k82cn): record event for this Command - if err := cc.vkClients.BusV1alpha1().Commands(cmd.Namespace).Delete(cmd.Name, nil); err != nil { - glog.Errorf("Failed to delete Command <%s/%s> which maybe executed again.", - cmd.Namespace, cmd.Name) - } - }() + cc.commandQueue.Add(cmd) } func (cc *Controller) addJob(obj interface{}) { @@ -72,7 +59,7 @@ func (cc *Controller) addJob(obj interface{}) { // TODO(k82cn): if failed to add job, the cache should be refresh if err := cc.cache.Add(job); err != nil { - glog.Errorf("Failed to add job <%s/%s>: %v", + glog.Errorf("Failed to add job <%s/%s>: %v in cache", job.Namespace, job.Name, err) } cc.queue.Add(req) @@ -85,18 +72,31 @@ func (cc *Controller) updateJob(oldObj, newObj interface{}) { return } - req := apis.Request{ - Namespace: newJob.Namespace, - JobName: newJob.Name, + oldJob, ok := oldObj.(*vkbatchv1.Job) + if !ok { + glog.Errorf("oldJob is not Job") + return + } - Event: vkbatchv1.OutOfSyncEvent, + //NOTE: Since we only reconcile job based on Spec, we will ignore other attributes + // For Job status, it's used internally and always been updated via our controller. + if reflect.DeepEqual(newJob.Spec, oldJob.Spec) { + glog.Infof("Job update event is ignored since no update in 'Spec'.") + return } if err := cc.cache.Update(newJob); err != nil { - glog.Errorf("Failed to update job <%s/%s>: %v", + glog.Errorf("Failed to update job <%s/%s>: %v in cache", newJob.Namespace, newJob.Name, err) } + req := apis.Request{ + Namespace: newJob.Namespace, + JobName: newJob.Name, + + Event: vkbatchv1.OutOfSyncEvent, + } + cc.queue.Add(req) } @@ -108,7 +108,7 @@ func (cc *Controller) deleteJob(obj interface{}) { } if err := cc.cache.Delete(job); err != nil { - glog.Errorf("Failed to delete job <%s/%s>: %v", + glog.Errorf("Failed to delete job <%s/%s>: %v in cache", job.Namespace, job.Name, err) } } @@ -122,7 +122,21 @@ func (cc *Controller) addPod(obj interface{}) { jobName, found := pod.Annotations[vkbatchv1.JobNameKey] if !found { - glog.Errorf("Failed to find jobName of Pod <%s/%s>", + glog.Infof("Failed to find jobName of Pod <%s/%s>, skipping", + pod.Namespace, pod.Name) + return + } + + version, found := pod.Annotations[vkbatchv1.JobVersion] + if !found { + glog.Infof("Failed to find jobVersion of Pod <%s/%s>, skipping", + pod.Namespace, pod.Name) + return + } + + dVersion, err := strconv.Atoi(version) + if err != nil { + glog.Infof("Failed to convert jobVersion of Pod <%s/%s> into number, skipping", pod.Namespace, pod.Name) return } @@ -131,11 +145,12 @@ func (cc *Controller) addPod(obj interface{}) { Namespace: pod.Namespace, JobName: jobName, - Event: vkbatchv1.OutOfSyncEvent, + Event: vkbatchv1.OutOfSyncEvent, + JobVersion: int32(dVersion), } if err := cc.cache.AddPod(pod); err != nil { - glog.Errorf("Failed to add Pod <%s/%s>: %v", + glog.Errorf("Failed to add Pod <%s/%s>: %v to cache", pod.Namespace, pod.Name, err) } cc.queue.Add(req) @@ -156,14 +171,28 @@ func (cc *Controller) updatePod(oldObj, newObj interface{}) { taskName, found := newPod.Annotations[vkbatchv1.TaskSpecKey] if !found { - glog.Errorf("Failed to find taskName of Pod <%s/%s>", + glog.Infof("Failed to find taskName of Pod <%s/%s>, skipping", newPod.Namespace, newPod.Name) return } jobName, found := newPod.Annotations[vkbatchv1.JobNameKey] if !found { - glog.Errorf("Failed to find jobName of Pod <%s/%s>", + glog.Infof("Failed to find jobName of Pod <%s/%s>, skipping", + newPod.Namespace, newPod.Name) + return + } + + version, found := newPod.Annotations[vkbatchv1.JobVersion] + if !found { + glog.Infof("Failed to find jobVersion of Pod <%s/%s>, skipping", + newPod.Namespace, newPod.Name) + return + } + + dVersion, err := strconv.Atoi(version) + if err != nil { + glog.Infof("Failed to convert jobVersion of Pod into number <%s/%s>, skipping", newPod.Namespace, newPod.Name) return } @@ -179,11 +208,12 @@ func (cc *Controller) updatePod(oldObj, newObj interface{}) { JobName: jobName, TaskName: taskName, - Event: event, + Event: event, + JobVersion: int32(dVersion), } if err := cc.cache.UpdatePod(newPod); err != nil { - glog.Errorf("Failed to update Pod <%s/%s>: %v", + glog.Errorf("Failed to update Pod <%s/%s>: %v in cache", newPod.Namespace, newPod.Name, err) } @@ -209,14 +239,28 @@ func (cc *Controller) deletePod(obj interface{}) { taskName, found := pod.Annotations[vkbatchv1.TaskSpecKey] if !found { - glog.Errorf("Failed to find taskName of Pod <%s/%s>", + glog.Infof("Failed to find taskName of Pod <%s/%s>, skipping", pod.Namespace, pod.Name) return } jobName, found := pod.Annotations[vkbatchv1.JobNameKey] if !found { - glog.Errorf("Failed to find jobName of Pod <%s/%s>", + glog.Infof("Failed to find jobName of Pod <%s/%s>, skipping", + pod.Namespace, pod.Name) + return + } + + version, found := pod.Annotations[vkbatchv1.JobVersion] + if !found { + glog.Infof("Failed to find jobVersion of Pod <%s/%s>, skipping", + pod.Namespace, pod.Name) + return + } + + dVersion, err := strconv.Atoi(version) + if err != nil { + glog.Infof("Failed to convert jobVersion of Pod <%s/%s> into number, skipping", pod.Namespace, pod.Name) return } @@ -226,15 +270,84 @@ func (cc *Controller) deletePod(obj interface{}) { JobName: jobName, TaskName: taskName, - Event: vkbatchv1.PodEvictedEvent, + Event: vkbatchv1.PodEvictedEvent, + JobVersion: int32(dVersion), } if err := cc.cache.DeletePod(pod); err != nil { - glog.Errorf("Failed to update Pod <%s/%s>: %v", + glog.Errorf("Failed to update Pod <%s/%s>: %v in cache", pod.Namespace, pod.Name, err) } cc.queue.Add(req) } +func (cc *Controller) recordJobEvent(namespace, name string, event vkbatchv1.JobEvent, message string) { + job, err := cc.cache.Get(vkcache.JobKeyByName(namespace, name)) + if err != nil { + glog.Warningf("Failed to find job in cache when reporting job event <%s/%s>: %v", + namespace, name, err) + return + } + cc.recorder.Event(job.Job, v1.EventTypeNormal, string(event), message) + +} + +func (cc *Controller) handleCommands() { + obj, shutdown := cc.commandQueue.Get() + if shutdown { + return + } + cmd := obj.(*vkbusv1.Command) + defer cc.commandQueue.Done(cmd) + + if err := cc.vkClients.BusV1alpha1().Commands(cmd.Namespace).Delete(cmd.Name, nil); err != nil { + glog.Errorf("Failed to delete Command <%s/%s>.", cmd.Namespace, cmd.Name) + cc.commandQueue.AddRateLimited(cmd) + return + } + cc.recordJobEvent(cmd.Namespace, cmd.TargetObject.Name, + vkbatchv1.CommandIssued, + fmt.Sprintf( + "Start to execute command %s, and clean it up to make sure executed not more than once.", cmd.Action)) + req := apis.Request{ + Namespace: cmd.Namespace, + JobName: cmd.TargetObject.Name, + Event: vkbatchv1.CommandIssuedEvent, + Action: vkbatchv1.Action(cmd.Action), + } + + cc.queue.Add(req) + +} + +func (cc *Controller) updatePodGroup(oldObj, newObj interface{}) { + oldPG, ok := oldObj.(*kbtype.PodGroup) + if !ok { + glog.Errorf("Failed to convert %v to PodGroup", newObj) + return + } + + newPG, ok := newObj.(*kbtype.PodGroup) + if !ok { + glog.Errorf("Failed to convert %v to PodGroup", newObj) + return + } + + _, err := cc.cache.Get(vkcache.JobKeyByName(newPG.Namespace, newPG.Name)) + if err != nil { + glog.Warningf( + "Failed to find job in cache by PodGroup, this may not be a PodGroup for volcano job.") + } + + if newPG.Status.Phase == kbtype.PodGroupUnknown && newPG.Status.Phase != oldPG.Status.Phase { + req := apis.Request{ + Namespace: newPG.Namespace, + JobName: newPG.Name, + Event: vkbatchv1.JobUnknownEvent, + } + cc.queue.Add(req) + } +} + // TODO(k82cn): add handler for PodGroup unschedulable event. diff --git a/pkg/controllers/job/job_controller_util.go b/pkg/controllers/job/job_controller_util.go index f24d3d7457..04155606ed 100644 --- a/pkg/controllers/job/job_controller_util.go +++ b/pkg/controllers/job/job_controller_util.go @@ -18,31 +18,19 @@ package job import ( "fmt" + "github.com/golang/glog" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kbapi "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" + admissioncontroller "volcano.sh/volcano/pkg/admission" vkv1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" "volcano.sh/volcano/pkg/apis/helpers" "volcano.sh/volcano/pkg/controllers/job/apis" ) -func validate(job *vkv1.Job) error { - tsNames := map[string]string{} - - for _, ts := range job.Spec.Tasks { - if _, found := tsNames[ts.Template.Name]; found { - return fmt.Errorf("duplicated TaskSpec") - } - - tsNames[ts.Template.Name] = ts.Template.Name - } - - return nil -} - func eventKey(obj interface{}) interface{} { req, ok := obj.(apis.Request) if !ok { @@ -55,12 +43,16 @@ func eventKey(obj interface{}) interface{} { } } +func MakePodName(jobName string, taskName string, index int) string { + return fmt.Sprintf(TaskNameFmt, jobName, taskName, index) +} + func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { templateCopy := template.DeepCopy() pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(TaskNameFmt, job.Name, template.Name, ix), + Name: MakePodName(job.Name, template.Name, ix), Namespace: job.Namespace, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(job, helpers.JobKind), @@ -76,19 +68,21 @@ func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { pod.Spec.SchedulerName = job.Spec.SchedulerName } + inputPVC := job.Annotations[admissioncontroller.PVCInputName] + outputPVC := job.Annotations[admissioncontroller.PVCOutputName] if job.Spec.Output != nil { if job.Spec.Output.VolumeClaim == nil { volume := v1.Volume{ - Name: fmt.Sprintf("%s-output", job.Name), + Name: outputPVC, } volume.EmptyDir = &v1.EmptyDirVolumeSource{} pod.Spec.Volumes = append(pod.Spec.Volumes, volume) } else { volume := v1.Volume{ - Name: fmt.Sprintf("%s-output", job.Name), + Name: outputPVC, } volume.PersistentVolumeClaim = &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: fmt.Sprintf("%s-output", job.Name), + ClaimName: outputPVC, } pod.Spec.Volumes = append(pod.Spec.Volumes, volume) @@ -97,7 +91,7 @@ func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { for i, c := range pod.Spec.Containers { vm := v1.VolumeMount{ MountPath: job.Spec.Output.MountPath, - Name: fmt.Sprintf("%s-output", job.Name), + Name: outputPVC, } pod.Spec.Containers[i].VolumeMounts = append(c.VolumeMounts, vm) } @@ -106,16 +100,16 @@ func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { if job.Spec.Input != nil { if job.Spec.Input.VolumeClaim == nil { volume := v1.Volume{ - Name: fmt.Sprintf("%s-input", job.Name), + Name: inputPVC, } volume.EmptyDir = &v1.EmptyDirVolumeSource{} pod.Spec.Volumes = append(pod.Spec.Volumes, volume) } else { volume := v1.Volume{ - Name: fmt.Sprintf("%s-input", job.Name), + Name: inputPVC, } volume.PersistentVolumeClaim = &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: fmt.Sprintf("%s-input", job.Name), + ClaimName: inputPVC, } pod.Spec.Volumes = append(pod.Spec.Volumes, volume) @@ -124,7 +118,7 @@ func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { for i, c := range pod.Spec.Containers { vm := v1.VolumeMount{ MountPath: job.Spec.Input.MountPath, - Name: fmt.Sprintf("%s-input", job.Name), + Name: inputPVC, } pod.Spec.Containers[i].VolumeMounts = append(c.VolumeMounts, vm) @@ -140,14 +134,15 @@ func createJobPod(job *vkv1.Job, template *v1.PodTemplateSpec, ix int) *v1.Pod { if len(tsKey) == 0 { tsKey = vkv1.DefaultTaskSpec } - pod.Annotations[vkv1.TaskSpecKey] = tsKey if len(pod.Annotations) == 0 { pod.Annotations = make(map[string]string) } + pod.Annotations[vkv1.TaskSpecKey] = tsKey pod.Annotations[kbapi.GroupNameAnnotationKey] = job.Name pod.Annotations[vkv1.JobNameKey] = job.Name + pod.Annotations[vkv1.JobVersion] = fmt.Sprintf("%d", job.Status.Version) if len(pod.Labels) == 0 { pod.Labels = make(map[string]string) @@ -170,6 +165,16 @@ func applyPolicies(job *vkv1.Job, req *apis.Request) vkv1.Action { return req.Action } + //For all the requests triggered from discarded job resources will perform sync action instead + if req.JobVersion > 0 && req.JobVersion < job.Status.Version { + glog.Infof("Request %s is outdated, will perform sync instead.", req) + return vkv1.SyncJobAction + } + + if req.Event == vkv1.OutOfSyncEvent { + return vkv1.SyncJobAction + } + // Overwrite Job level policies if len(req.TaskName) != 0 { // Parse task level policies diff --git a/pkg/controllers/job/state/pending.go b/pkg/controllers/job/state/pending.go index 270069e421..dea311b381 100644 --- a/pkg/controllers/job/state/pending.go +++ b/pkg/controllers/job/state/pending.go @@ -52,10 +52,9 @@ func (ps *pendingState) Execute(action vkv1.Action) error { }) default: return SyncJob(ps.job, func(status vkv1.JobStatus) vkv1.JobState { - total := totalTasks(ps.job.Job) phase := vkv1.Pending - if total == status.Running { + if ps.job.Job.Spec.MinAvailable <= status.Running { phase = vkv1.Running } return vkv1.JobState{ diff --git a/pkg/controllers/job/state/restarting.go b/pkg/controllers/job/state/restarting.go index 681aa01da5..353c009be0 100644 --- a/pkg/controllers/job/state/restarting.go +++ b/pkg/controllers/job/state/restarting.go @@ -29,7 +29,7 @@ func (ps *restartingState) Execute(action vkv1.Action) error { return SyncJob(ps.job, func(status vkv1.JobStatus) vkv1.JobState { phase := vkv1.Restarting if status.Terminating == 0 { - if status.Pending == 0 && status.Running != 0 { + if status.Running >= ps.job.Job.Spec.MinAvailable { phase = vkv1.Running } else { phase = vkv1.Pending diff --git a/pkg/controllers/job/state/running.go b/pkg/controllers/job/state/running.go index 9671e86b35..2cf128a6ba 100644 --- a/pkg/controllers/job/state/running.go +++ b/pkg/controllers/job/state/running.go @@ -63,7 +63,7 @@ func (ps *runningState) Execute(action vkv1.Action) error { default: return SyncJob(ps.job, func(status vkv1.JobStatus) vkv1.JobState { phase := vkv1.Running - if status.Succeeded+status.Failed == totalTasks(ps.job.Job) { + if status.Succeeded+status.Failed == TotalTasks(ps.job.Job) { phase = vkv1.Completed } diff --git a/pkg/controllers/job/state/util.go b/pkg/controllers/job/state/util.go index 45277ef640..7f287cad55 100644 --- a/pkg/controllers/job/state/util.go +++ b/pkg/controllers/job/state/util.go @@ -20,7 +20,7 @@ import ( vkv1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1" ) -func totalTasks(job *vkv1.Job) int32 { +func TotalTasks(job *vkv1.Job) int32 { var rep int32 for _, task := range job.Spec.Tasks { diff --git a/pkg/scheduler/algorithm/factory.go b/pkg/scheduler/algorithm/factory.go index 110aea4f25..4f224966db 100644 --- a/pkg/scheduler/algorithm/factory.go +++ b/pkg/scheduler/algorithm/factory.go @@ -17,11 +17,15 @@ limitations under the License. package algorithm import ( - "volcano.sh/volcano/pkg/scheduler/algorithm/fairshare" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + // Import default actions/plugins. + _ "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions" + _ "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins" + + "volcano.sh/volcano/pkg/scheduler/algorithm/fairshare" ) func init() { framework.RegisterPluginBuilder("fairshare", fairshare.New) -} +} \ No newline at end of file diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options/options.go b/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options/options.go index 7bcb4bfbec..6fc4d636c2 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options/options.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options/options.go @@ -30,22 +30,11 @@ type ServerOption struct { SchedulerName string SchedulerConf string SchedulePeriod string - NamespaceAsQueue bool EnableLeaderElection bool LockObjectNamespace string DefaultQueue string PrintVersion bool -} - -var ( - opts *ServerOption -) - -func Options() *ServerOption { - if opts == nil { - opts = &ServerOption{} - } - return opts + ListenAddress string } // NewServerOption creates a new CMServer with a default config. @@ -62,14 +51,13 @@ func (s *ServerOption) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.SchedulerName, "scheduler-name", "kube-batch", "kube-batch will handle pods with the scheduler-name") fs.StringVar(&s.SchedulerConf, "scheduler-conf", "", "The absolute path of scheduler configuration file") fs.StringVar(&s.SchedulePeriod, "schedule-period", "1s", "The period between each scheduling cycle") - fs.StringVar(&s.DefaultQueue, "default-queue", "", "The name of the queue to fall-back to instead of namespace name") + fs.StringVar(&s.DefaultQueue, "default-queue", "default", "The default queue name of the job") fs.BoolVar(&s.EnableLeaderElection, "leader-elect", s.EnableLeaderElection, "Start a leader election client and gain leadership before "+ "executing the main loop. Enable this when running replicated kube-batch for high availability") - fs.BoolVar(&s.NamespaceAsQueue, "enable-namespace-as-queue", true, "Make Namespace as Queue with weight one, "+ - "but kube-batch will not handle Queue CRD anymore") fs.BoolVar(&s.PrintVersion, "version", false, "Show version and quit") fs.StringVar(&s.LockObjectNamespace, "lock-object-namespace", s.LockObjectNamespace, "Define the namespace of the lock object") + fs.StringVar(&s.ListenAddress, "listen-address", ":8080", "The address to listen on for HTTP requests.") } func (s *ServerOption) CheckOptionOrDie() error { diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/server.go b/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/server.go index 4df9309f2c..50f41ddb4d 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/server.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/server.go @@ -19,6 +19,7 @@ package app import ( "context" "fmt" + "net/http" "os" "time" @@ -26,6 +27,7 @@ import ( "github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler" "github.com/kubernetes-sigs/kube-batch/pkg/version" + "github.com/prometheus/client_golang/prometheus/promhttp" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/uuid" @@ -66,12 +68,20 @@ func Run(opt *options.ServerOption) error { } // Start policy controller to allocate resources. - sched, err := scheduler.NewScheduler(config, opt.SchedulerName, - opt.SchedulerConf, opt.SchedulePeriod, opt.NamespaceAsQueue) + sched, err := scheduler.NewScheduler(config, + opt.SchedulerName, + opt.SchedulerConf, + opt.SchedulePeriod, + opt.DefaultQueue) if err != nil { panic(err) } + go func() { + http.Handle("/metrics", promhttp.Handler()) + glog.Fatalf("Prometheus Http Server failed %s", http.ListenAndServe(opt.ListenAddress, nil)) + }() + run := func(ctx context.Context) { sched.Run(ctx.Done()) <-ctx.Done() diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1/types.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1/types.go index 8ddf642591..c8ff2c7db7 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1/types.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1/types.go @@ -114,6 +114,15 @@ type PodGroupSpec struct { // Queue defines the queue to allocate resource for PodGroup; if queue does not exist, // the PodGroup will not be scheduled. Queue string `json:"queue,omitempty" protobuf:"bytes,2,opt,name=queue"` + + // If specified, indicates the PodGroup's priority. "system-node-critical" and + // "system-cluster-critical" are two special keywords which indicate the + // highest priorities with the former being the highest priority. Any other + // name must be defined by creating a PriorityClass object with that name. + // If not specified, the PodGroup priority will be default or zero if there is no + // default. + // +optional + PriorityClassName string `json:"priorityClassName,omitempty" protobuf:"bytes,3,opt,name=priorityClassName"` } // PodGroupStatus represents the current state of a pod group. diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate/allocate.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate/allocate.go index e8509bdc13..753ad8bbb2 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate/allocate.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate/allocate.go @@ -50,7 +50,7 @@ func (alloc *allocateAction) Execute(ssn *framework.Session) { jobsMap[job.Queue] = util.NewPriorityQueue(ssn.JobOrderFn) } - if queue, found := ssn.QueueIndex[job.Queue]; found { + if queue, found := ssn.Queues[job.Queue]; found { queues.Push(queue) } @@ -103,6 +103,9 @@ func (alloc *allocateAction) Execute(ssn *framework.Session) { tasks.Len(), job.Namespace, job.Name) for !tasks.Empty() { + predicateNodes := []*api.NodeInfo{} + nodeScores := map[int][]*api.NodeInfo{} + task := tasks.Pop().(*api.TaskInfo) assigned := false @@ -125,8 +128,20 @@ func (alloc *allocateAction) Execute(ssn *framework.Session) { glog.V(3).Infof("Predicates failed for task <%s/%s> on node <%s>: %v", task.Namespace, task.Name, node.Name, err) continue + } else { + predicateNodes = append(predicateNodes, node) } - + } + for _, node := range predicateNodes { + score, err := ssn.NodeOrderFn(task, node) + if err != nil { + glog.V(3).Infof("Error in Calculating Priority for the node:%v", err) + } else { + nodeScores[score] = append(nodeScores[score], node) + } + } + selectedNodes := util.SelectBestNode(nodeScores) + for _, node := range selectedNodes { // Allocate idle resource to the task. if task.Resreq.LessEqual(node.Idle) { glog.V(3).Infof("Binding Task <%v/%v> to node <%v>", @@ -161,13 +176,14 @@ func (alloc *allocateAction) Execute(ssn *framework.Session) { } } - if assigned { - jobs.Push(job) - // Handle one assigned task in each loop. + if !assigned { break } - // If current task is not assgined, try to fit all rest tasks. + if ssn.JobReady(job) { + jobs.Push(job) + break + } } // Added Queue back until no job in Queue. diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/factory.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/factory.go new file mode 100644 index 0000000000..827533b226 --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/factory.go @@ -0,0 +1,33 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/backfill" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim" +) + +func init() { + framework.RegisterAction(reclaim.New()) + framework.RegisterAction(allocate.New()) + framework.RegisterAction(backfill.New()) + framework.RegisterAction(preempt.New()) +} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt/preempt.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt/preempt.go index c339e2b474..9b21325490 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt/preempt.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt/preempt.go @@ -23,6 +23,7 @@ import ( "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util" ) @@ -48,14 +49,15 @@ func (alloc *preemptAction) Execute(ssn *framework.Session) { preemptorTasks := map[api.JobID]*util.PriorityQueue{} var underRequest []*api.JobInfo - var queues []*api.QueueInfo + queues := map[api.QueueID]*api.QueueInfo{} + for _, job := range ssn.Jobs { - if queue, found := ssn.QueueIndex[job.Queue]; !found { + if queue, found := ssn.Queues[job.Queue]; !found { continue - } else { + } else if _, existed := queues[queue.UID]; !existed { glog.V(3).Infof("Added Queue <%s> for Job <%s/%s>", queue.Name, job.Namespace, job.Name) - queues = append(queues, queue) + queues[queue.UID] = queue } if len(job.TaskStatusIndex[api.Pending]) != 0 { @@ -102,7 +104,7 @@ func (alloc *preemptAction) Execute(ssn *framework.Session) { return false } - job, found := ssn.JobIndex[task.Job] + job, found := ssn.Jobs[task.Job] if !found { return false } @@ -170,23 +172,39 @@ func preempt( ssn *framework.Session, stmt *framework.Statement, preemptor *api.TaskInfo, - nodes []*api.NodeInfo, + nodes map[string]*api.NodeInfo, filter func(*api.TaskInfo) bool, ) (bool, error) { - resreq := preemptor.Resreq.Clone() - preempted := api.EmptyResource() - + predicateNodes := []*api.NodeInfo{} + nodeScores := map[int][]*api.NodeInfo{} assigned := false for _, node := range nodes { if err := ssn.PredicateFn(preemptor, node); err != nil { + glog.V(3).Infof("Predicates failed for task <%s/%s> on node <%s>: %v", + preemptor.Namespace, preemptor.Name, node.Name, err) continue + } else { + predicateNodes = append(predicateNodes, node) } - + } + for _, node := range predicateNodes { + score, err := ssn.NodeOrderFn(preemptor, node) + if err != nil { + glog.V(3).Infof("Error in Calculating Priority for the node:%v", err) + } else { + nodeScores[score] = append(nodeScores[score], node) + } + } + selectedNodes := util.SelectBestNode(nodeScores) + for _, node := range selectedNodes { glog.V(3).Infof("Considering Task <%s/%s> on Node <%s>.", preemptor.Namespace, preemptor.Name, node.Name) var preemptees []*api.TaskInfo + preempted := api.EmptyResource() + resreq := preemptor.Resreq.Clone() + for _, task := range node.Tasks { if filter == nil { preemptees = append(preemptees, task.Clone()) @@ -195,6 +213,7 @@ func preempt( } } victims := ssn.Preemptable(preemptor, preemptees) + metrics.UpdatePreemptionVictimsCount(len(victims)) if err := validateVictims(victims, resreq); err != nil { glog.V(3).Infof("No validated victims on Node <%s>: %v", node.Name, err) @@ -218,18 +237,21 @@ func preempt( resreq.Sub(preemptee.Resreq) } + metrics.RegisterPreemptionAttempts() glog.V(3).Infof("Preempted <%v> for task <%s/%s> requested <%v>.", preempted, preemptor.Namespace, preemptor.Name, preemptor.Resreq) - if err := stmt.Pipeline(preemptor, node.Name); err != nil { - glog.Errorf("Failed to pipline Task <%s/%s> on Node <%s>", - preemptor.Namespace, preemptor.Name, node.Name) - } + if preemptor.Resreq.LessEqual(preempted) { + if err := stmt.Pipeline(preemptor, node.Name); err != nil { + glog.Errorf("Failed to pipline Task <%s/%s> on Node <%s>", + preemptor.Namespace, preemptor.Name, node.Name) + } - // Ignore pipeline error, will be corrected in next scheduling loop. - assigned = true + // Ignore pipeline error, will be corrected in next scheduling loop. + assigned = true - break + break + } } return assigned, nil diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim/reclaim.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim/reclaim.go index 9a44fdff3b..e113a65a99 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim/reclaim.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim/reclaim.go @@ -43,6 +43,7 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { defer glog.V(3).Infof("Leaving Reclaim ...") queues := util.NewPriorityQueue(ssn.QueueOrderFn) + queueMap := map[api.QueueID]*api.QueueInfo{} preemptorsMap := map[api.QueueID]*util.PriorityQueue{} preemptorTasks := map[api.JobID]*util.PriorityQueue{} @@ -52,14 +53,18 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { var underRequest []*api.JobInfo for _, job := range ssn.Jobs { - if queue, found := ssn.QueueIndex[job.Queue]; !found { + if queue, found := ssn.Queues[job.Queue]; !found { glog.Errorf("Failed to find Queue <%s> for Job <%s/%s>", job.Queue, job.Namespace, job.Name) continue } else { - glog.V(4).Infof("Added Queue <%s> for Job <%s/%s>", - queue.Name, job.Namespace, job.Name) - queues.Push(queue) + if _, existed := queueMap[queue.UID]; !existed { + glog.V(4).Infof("Added Queue <%s> for Job <%s/%s>", + queue.Name, job.Namespace, job.Name) + + queueMap[queue.UID] = queue + queues.Push(queue) + } } if len(job.TaskStatusIndex[api.Pending]) != 0 { @@ -104,9 +109,6 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { task = tasks.Pop().(*api.TaskInfo) } - resreq := task.Resreq.Clone() - reclaimed := api.EmptyResource() - assigned := false for _, n := range ssn.Nodes { @@ -115,6 +117,9 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { continue } + resreq := task.Resreq.Clone() + reclaimed := api.EmptyResource() + glog.V(3).Infof("Considering Task <%s/%s> on Node <%s>.", task.Namespace, task.Name, n.Name) @@ -125,7 +130,7 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { continue } - if j, found := ssn.JobIndex[task.Job]; !found { + if j, found := ssn.Jobs[task.Job]; !found { continue } else if j.Queue != job.Queue { // Clone task to avoid modify Task's status on node. @@ -169,15 +174,17 @@ func (alloc *reclaimAction) Execute(ssn *framework.Session) { glog.V(3).Infof("Reclaimed <%v> for task <%s/%s> requested <%v>.", reclaimed, task.Namespace, task.Name, task.Resreq) - if err := ssn.Pipeline(task, n.Name); err != nil { - glog.Errorf("Failed to pipline Task <%s/%s> on Node <%s>", - task.Namespace, task.Name, n.Name) - } + if task.Resreq.LessEqual(reclaimed) { + if err := ssn.Pipeline(task, n.Name); err != nil { + glog.Errorf("Failed to pipline Task <%s/%s> on Node <%s>", + task.Namespace, task.Name, n.Name) + } - // Ignore error of pipeline, will be corrected in next scheduling loop. - assigned = true + // Ignore error of pipeline, will be corrected in next scheduling loop. + assigned = true - break + break + } } if assigned { diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/cluster_info.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/cluster_info.go index 8a3355e0c2..8264f7a7cc 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/cluster_info.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/cluster_info.go @@ -19,13 +19,9 @@ import "fmt" // ClusterInfo is a snapshot of cluster by cache. type ClusterInfo struct { - Jobs []*JobInfo - - Nodes []*NodeInfo - - Queues []*QueueInfo - - Others []*TaskInfo + Jobs map[JobID]*JobInfo + Nodes map[string]*NodeInfo + Queues map[QueueID]*QueueInfo } func (ci ClusterInfo) String() string { diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/job_info.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/job_info.go index 11dc17db81..297bf9df40 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/job_info.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/job_info.go @@ -26,9 +26,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "github.com/kubernetes-sigs/kube-batch/cmd/kube-batch/app/options" - arbcorev1 "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" - "github.com/kubernetes-sigs/kube-batch/pkg/apis/utils" + "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" ) type TaskID types.UID @@ -52,13 +50,14 @@ type TaskInfo struct { func getJobID(pod *v1.Pod) JobID { if len(pod.Annotations) != 0 { - if gn, found := pod.Annotations[arbcorev1.GroupNameAnnotationKey]; found && len(gn) != 0 { + if gn, found := pod.Annotations[v1alpha1.GroupNameAnnotationKey]; found && len(gn) != 0 { // Make sure Pod and PodGroup belong to the same namespace. jobID := fmt.Sprintf("%s/%s", pod.Namespace, gn) return JobID(jobID) } } - return JobID(utils.GetController(pod)) + + return "" } func NewTaskInfo(pod *v1.Pod) *TaskInfo { @@ -69,9 +68,11 @@ func NewTaskInfo(pod *v1.Pod) *TaskInfo { req.Add(NewResource(c.Resources.Requests)) } + jobID := getJobID(pod) + ti := &TaskInfo{ UID: TaskID(pod.UID), - Job: getJobID(pod), + Job: jobID, Name: pod.Name, Namespace: pod.Namespace, NodeName: pod.Spec.NodeName, @@ -123,7 +124,7 @@ type JobInfo struct { Queue QueueID - Priority int + Priority int32 NodeSelector map[string]string MinAvailable int32 @@ -138,14 +139,14 @@ type JobInfo struct { TotalRequest *Resource CreationTimestamp metav1.Time - PodGroup *arbcorev1.PodGroup + PodGroup *v1alpha1.PodGroup // TODO(k82cn): keep backward compatbility, removed it when v1alpha1 finalized. PDB *policyv1.PodDisruptionBudget } -func NewJobInfo(uid JobID) *JobInfo { - return &JobInfo{ +func NewJobInfo(uid JobID, tasks ...*TaskInfo) *JobInfo { + job := &JobInfo{ UID: uid, MinAvailable: 0, @@ -157,31 +158,25 @@ func NewJobInfo(uid JobID) *JobInfo { TaskStatusIndex: map[TaskStatus]tasksMap{}, Tasks: tasksMap{}, } + + for _, task := range tasks { + job.AddTaskInfo(task) + } + + return job } func (ji *JobInfo) UnsetPodGroup() { ji.PodGroup = nil } -func (ji *JobInfo) SetPodGroup(pg *arbcorev1.PodGroup) { +func (ji *JobInfo) SetPodGroup(pg *v1alpha1.PodGroup) { ji.Name = pg.Name ji.Namespace = pg.Namespace ji.MinAvailable = pg.Spec.MinMember - - //set queue name based on the available information - //in the following priority order: - // 1. queue name from PodGroup spec (if available) - // 2. queue name from default-queue command line option (if specified) - // 3. namespace name - if len(pg.Spec.Queue) > 0 { - ji.Queue = QueueID(pg.Spec.Queue) - } else if len(options.Options().DefaultQueue) > 0 { - ji.Queue = QueueID(options.Options().DefaultQueue) - } else { - ji.Queue = QueueID(pg.Namespace) - } - + ji.Queue = QueueID(pg.Spec.Queue) ji.CreationTimestamp = pg.GetCreationTimestamp() + ji.PodGroup = pg } @@ -189,11 +184,6 @@ func (ji *JobInfo) SetPDB(pdb *policyv1.PodDisruptionBudget) { ji.Name = pdb.Name ji.MinAvailable = pdb.Spec.MinAvailable.IntVal ji.Namespace = pdb.Namespace - if len(options.Options().DefaultQueue) == 0 { - ji.Queue = QueueID(pdb.Namespace) - } else { - ji.Queue = QueueID(options.Options().DefaultQueue) - } ji.CreationTimestamp = pdb.GetCreationTimestamp() ji.PDB = pdb @@ -285,11 +275,12 @@ func (ji *JobInfo) Clone() *JobInfo { Name: ji.Name, Namespace: ji.Namespace, Queue: ji.Queue, + Priority: ji.Priority, MinAvailable: ji.MinAvailable, NodeSelector: map[string]string{}, - Allocated: ji.Allocated.Clone(), - TotalRequest: ji.TotalRequest.Clone(), + Allocated: EmptyResource(), + TotalRequest: EmptyResource(), NodesFitDelta: make(NodeResourceMap), PDB: ji.PDB, @@ -321,7 +312,8 @@ func (ji JobInfo) String() string { i++ } - return fmt.Sprintf("Job (%v): name %v, minAvailable %d", ji.UID, ji.Name, ji.MinAvailable) + res + return fmt.Sprintf("Job (%v): namespace %v (%v), name %v, minAvailable %d, podGroup %+v", + ji.UID, ji.Namespace, ji.Queue, ji.Name, ji.MinAvailable, ji.PodGroup) + res } // Error returns detailed information on why a job's task failed to fit on diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/types.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/types.go index 07d22066d7..9fbd58c6c0 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/types.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api/types.go @@ -102,3 +102,6 @@ type PredicateFn func(*TaskInfo, *NodeInfo) error // EvictableFn is the func declaration used to evict tasks. type EvictableFn func(*TaskInfo, []*TaskInfo) []*TaskInfo + +// NodeOrderFn is the func declaration used to get priority score for a node for a particular task. +type NodeOrderFn func(*TaskInfo, *NodeInfo) (int, error) diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/cache.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/cache.go index 38afb29153..df0b533bfe 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/cache.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/cache.go @@ -25,31 +25,46 @@ import ( "github.com/golang/glog" "k8s.io/api/core/v1" + "k8s.io/api/scheduling/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/informers" infov1 "k8s.io/client-go/informers/core/v1" policyv1 "k8s.io/client-go/informers/policy/v1beta1" + schedv1 "k8s.io/client-go/informers/scheduling/v1beta1" storagev1 "k8s.io/client-go/informers/storage/v1" "k8s.io/client-go/kubernetes" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/workqueue" podutil "k8s.io/kubernetes/pkg/api/v1/pod" "k8s.io/kubernetes/pkg/scheduler/volumebinder" "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" kbver "github.com/kubernetes-sigs/kube-batch/pkg/client/clientset/versioned" "github.com/kubernetes-sigs/kube-batch/pkg/client/clientset/versioned/scheme" + kbschema "github.com/kubernetes-sigs/kube-batch/pkg/client/clientset/versioned/scheme" kbinfo "github.com/kubernetes-sigs/kube-batch/pkg/client/informers/externalversions" kbinfov1 "github.com/kubernetes-sigs/kube-batch/pkg/client/informers/externalversions/scheduling/v1alpha1" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" kbapi "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" ) +func init() { + schemeBuilder := runtime.SchemeBuilder{ + v1.AddToScheme, + } + + utilruntime.Must(schemeBuilder.AddToScheme(kbschema.Scheme)) +} + // New returns a Cache implementation. -func New(config *rest.Config, schedulerName string, nsAsQueue bool) Cache { - return newSchedulerCache(config, schedulerName, nsAsQueue) +func New(config *rest.Config, schedulerName string, defaultQueue string) Cache { + return newSchedulerCache(config, schedulerName, defaultQueue) } type SchedulerCache struct { @@ -58,6 +73,8 @@ type SchedulerCache struct { kubeclient *kubernetes.Clientset kbclient *kbver.Clientset + defaultQueue string + podInformer infov1.PodInformer nodeInformer infov1.NodeInformer pdbInformer policyv1.PodDisruptionBudgetInformer @@ -67,6 +84,7 @@ type SchedulerCache struct { pvInformer infov1.PersistentVolumeInformer pvcInformer infov1.PersistentVolumeClaimInformer scInformer storagev1.StorageClassInformer + pcInformer schedv1.PriorityClassInformer Binder Binder Evictor Evictor @@ -75,14 +93,15 @@ type SchedulerCache struct { Recorder record.EventRecorder - Jobs map[kbapi.JobID]*kbapi.JobInfo - Nodes map[string]*kbapi.NodeInfo - Queues map[kbapi.QueueID]*kbapi.QueueInfo - - errTasks *cache.FIFO - deletedJobs *cache.FIFO + Jobs map[kbapi.JobID]*kbapi.JobInfo + Nodes map[string]*kbapi.NodeInfo + Queues map[kbapi.QueueID]*kbapi.QueueInfo + PriorityClasses map[string]*v1beta1.PriorityClass + defaultPriorityClass *v1beta1.PriorityClass + defaultPriority int32 - namespaceAsQueue bool + errTasks workqueue.RateLimitingInterface + deletedJobs workqueue.RateLimitingInterface } type defaultBinder struct { @@ -129,12 +148,12 @@ type defaultStatusUpdater struct { } // Update pod with podCondition -func (su *defaultStatusUpdater) UpdatePod(pod *v1.Pod, condition *v1.PodCondition) (*v1.Pod, error) { +func (su *defaultStatusUpdater) UpdatePodCondition(pod *v1.Pod, condition *v1.PodCondition) (*v1.Pod, error) { glog.V(3).Infof("Updating pod condition for %s/%s to (%s==%s)", pod.Namespace, pod.Name, condition.Type, condition.Status) if podutil.UpdatePodCondition(&pod.Status, condition) { return su.kubeclient.CoreV1().Pods(pod.Namespace).UpdateStatus(pod) } - return nil, fmt.Errorf("failed to update pod condition") + return pod, nil } // Update pod with podCondition @@ -164,44 +183,17 @@ func (dvb *defaultVolumeBinder) BindVolumes(task *api.TaskInfo) error { return dvb.volumeBinder.Binder.BindPodVolumes(task.Pod) } -func taskKey(obj interface{}) (string, error) { - if obj == nil { - return "", fmt.Errorf("the object is nil") - } - - task, ok := obj.(*kbapi.TaskInfo) - - if !ok { - return "", fmt.Errorf("failed to convert %v to TaskInfo", obj) - } - - return string(task.UID), nil -} - -func jobKey(obj interface{}) (string, error) { - if obj == nil { - return "", fmt.Errorf("the object is nil") - } - - job, ok := obj.(*kbapi.JobInfo) - - if !ok { - return "", fmt.Errorf("failed to convert %v to TaskInfo", obj) - } - - return string(job.UID), nil -} - -func newSchedulerCache(config *rest.Config, schedulerName string, nsAsQueue bool) *SchedulerCache { +func newSchedulerCache(config *rest.Config, schedulerName string, defaultQueue string) *SchedulerCache { sc := &SchedulerCache{ - Jobs: make(map[kbapi.JobID]*kbapi.JobInfo), - Nodes: make(map[string]*kbapi.NodeInfo), - Queues: make(map[kbapi.QueueID]*kbapi.QueueInfo), - errTasks: cache.NewFIFO(taskKey), - deletedJobs: cache.NewFIFO(jobKey), - kubeclient: kubernetes.NewForConfigOrDie(config), - kbclient: kbver.NewForConfigOrDie(config), - namespaceAsQueue: nsAsQueue, + Jobs: make(map[kbapi.JobID]*kbapi.JobInfo), + Nodes: make(map[string]*kbapi.NodeInfo), + Queues: make(map[kbapi.QueueID]*kbapi.QueueInfo), + PriorityClasses: make(map[string]*v1beta1.PriorityClass), + errTasks: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), + deletedJobs: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), + kubeclient: kubernetes.NewForConfigOrDie(config), + kbclient: kbver.NewForConfigOrDie(config), + defaultQueue: defaultQueue, } // Prepare event clients. @@ -278,6 +270,13 @@ func newSchedulerCache(config *rest.Config, schedulerName string, nsAsQueue bool DeleteFunc: sc.DeletePDB, }) + sc.pcInformer = informerFactory.Scheduling().V1beta1().PriorityClasses() + sc.pcInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: sc.AddPriorityClass, + UpdateFunc: sc.UpdatePriorityClass, + DeleteFunc: sc.DeletePriorityClass, + }) + kbinformer := kbinfo.NewSharedInformerFactory(sc.kbclient, 0) // create informer for PodGroup information sc.podGroupInformer = kbinformer.Scheduling().V1alpha1().PodGroups() @@ -287,23 +286,13 @@ func newSchedulerCache(config *rest.Config, schedulerName string, nsAsQueue bool DeleteFunc: sc.DeletePodGroup, }) - if sc.namespaceAsQueue { - // create informer for Namespace information - sc.nsInformer = informerFactory.Core().V1().Namespaces() - sc.nsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: sc.AddNamespace, - UpdateFunc: sc.UpdateNamespace, - DeleteFunc: sc.DeleteNamespace, - }) - } else { - // create informer for Queue information - sc.queueInformer = kbinformer.Scheduling().V1alpha1().Queues() - sc.queueInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: sc.AddQueue, - UpdateFunc: sc.UpdateQueue, - DeleteFunc: sc.DeleteQueue, - }) - } + // create informer for Queue information + sc.queueInformer = kbinformer.Scheduling().V1alpha1().Queues() + sc.queueInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: sc.AddQueue, + UpdateFunc: sc.UpdateQueue, + DeleteFunc: sc.DeleteQueue, + }) return sc } @@ -316,27 +305,17 @@ func (sc *SchedulerCache) Run(stopCh <-chan struct{}) { go sc.pvInformer.Informer().Run(stopCh) go sc.pvcInformer.Informer().Run(stopCh) go sc.scInformer.Informer().Run(stopCh) - - if sc.namespaceAsQueue { - go sc.nsInformer.Informer().Run(stopCh) - } else { - go sc.queueInformer.Informer().Run(stopCh) - } + go sc.queueInformer.Informer().Run(stopCh) + go sc.pcInformer.Informer().Run(stopCh) // Re-sync error tasks. - go sc.resync() + go wait.Until(sc.processResyncTask, 0, stopCh) // Cleanup jobs. - go sc.cleanupJobs() + go wait.Until(sc.processCleanupJob, 0, stopCh) } func (sc *SchedulerCache) WaitForCacheSync(stopCh <-chan struct{}) bool { - var queueSync func() bool - if sc.namespaceAsQueue { - queueSync = sc.nsInformer.Informer().HasSynced - } else { - queueSync = sc.queueInformer.Informer().HasSynced - } return cache.WaitForCacheSync(stopCh, sc.pdbInformer.Informer().HasSynced, @@ -346,7 +325,8 @@ func (sc *SchedulerCache) WaitForCacheSync(stopCh <-chan struct{}) bool { sc.pvInformer.Informer().HasSynced, sc.pvcInformer.Informer().HasSynced, sc.scInformer.Informer().HasSynced, - queueSync, + sc.queueInformer.Informer().HasSynced, + sc.pcInformer.Informer().HasSynced, ) } @@ -388,7 +368,9 @@ func (sc *SchedulerCache) Evict(taskInfo *kbapi.TaskInfo, reason string) error { } // Add new task to node. - node.UpdateTask(task) + if err := node.UpdateTask(task); err != nil { + return err + } p := task.Pod @@ -399,7 +381,9 @@ func (sc *SchedulerCache) Evict(taskInfo *kbapi.TaskInfo, reason string) error { } }() - sc.Recorder.Eventf(job.PodGroup, v1.EventTypeNormal, "Evict", reason) + if !shadowPodGroup(job.PodGroup) { + sc.Recorder.Eventf(job.PodGroup, v1.EventTypeNormal, "Evict", reason) + } return nil } @@ -430,7 +414,9 @@ func (sc *SchedulerCache) Bind(taskInfo *kbapi.TaskInfo, hostname string) error task.NodeName = hostname // Add task to the node. - node.AddTask(task) + if err := node.AddTask(task); err != nil { + return err + } p := task.Pod @@ -461,7 +447,7 @@ func (sc *SchedulerCache) taskUnschedulable(task *api.TaskInfo, message string) pod := task.Pod.DeepCopy() sc.Recorder.Eventf(pod, v1.EventTypeWarning, string(v1.PodReasonUnschedulable), message) - if _, err := sc.StatusUpdater.UpdatePod(pod, &v1.PodCondition{ + if _, err := sc.StatusUpdater.UpdatePodCondition(pod, &v1.PodCondition{ Type: v1.PodScheduled, Status: v1.ConditionFalse, Reason: v1.PodReasonUnschedulable, @@ -476,74 +462,52 @@ func (sc *SchedulerCache) taskUnschedulable(task *api.TaskInfo, message string) func (sc *SchedulerCache) deleteJob(job *kbapi.JobInfo) { glog.V(3).Infof("Try to delete Job <%v:%v/%v>", job.UID, job.Namespace, job.Name) - time.AfterFunc(5*time.Second, func() { - sc.deletedJobs.AddIfNotPresent(job) - }) + sc.deletedJobs.AddRateLimited(job) } -func (sc *SchedulerCache) processCleanupJob() error { - _, err := sc.deletedJobs.Pop(func(obj interface{}) error { - job, ok := obj.(*kbapi.JobInfo) - if !ok { - return fmt.Errorf("failed to convert %v to *v1.Pod", obj) - } - - func() { - sc.Mutex.Lock() - defer sc.Mutex.Unlock() - - if kbapi.JobTerminated(job) { - delete(sc.Jobs, job.UID) - glog.V(3).Infof("Job <%v:%v/%v> was deleted.", job.UID, job.Namespace, job.Name) - } else { - // Retry - sc.deleteJob(job) - } - }() +func (sc *SchedulerCache) processCleanupJob() { + obj, shutdown := sc.deletedJobs.Get() + if shutdown { + return + } - return nil - }) + job, found := obj.(*kbapi.JobInfo) + if !found { + glog.Errorf("Failed to convert <%v> to *JobInfo", obj) + return + } - return err -} + sc.Mutex.Lock() + defer sc.Mutex.Unlock() -func (sc *SchedulerCache) cleanupJobs() { - for { - err := sc.processCleanupJob() - if err != nil { - glog.Errorf("Failed to process job clean up: %v", err) - } + if kbapi.JobTerminated(job) { + delete(sc.Jobs, job.UID) + glog.V(3).Infof("Job <%v:%v/%v> was deleted.", job.UID, job.Namespace, job.Name) + } else { + // Retry + sc.deleteJob(job) } } func (sc *SchedulerCache) resyncTask(task *kbapi.TaskInfo) { - sc.errTasks.AddIfNotPresent(task) + sc.errTasks.AddRateLimited(task) } -func (sc *SchedulerCache) resync() { - for { - err := sc.processResyncTask() - if err != nil { - glog.Errorf("Failed to process resync: %v", err) - } +func (sc *SchedulerCache) processResyncTask() { + obj, shutdown := sc.errTasks.Get() + if shutdown { + return + } + task, ok := obj.(*kbapi.TaskInfo) + if !ok { + glog.Errorf("failed to convert %v to *v1.Pod", obj) + return } -} - -func (sc *SchedulerCache) processResyncTask() error { - _, err := sc.errTasks.Pop(func(obj interface{}) error { - task, ok := obj.(*kbapi.TaskInfo) - if !ok { - return fmt.Errorf("failed to convert %v to *v1.Pod", obj) - } - - if err := sc.syncTask(task); err != nil { - glog.Errorf("Failed to sync pod <%v/%v>", task.Namespace, task.Name) - return err - } - return nil - }) - return err + if err := sc.syncTask(task); err != nil { + glog.Errorf("Failed to sync pod <%v/%v>, retry it.", task.Namespace, task.Name) + sc.resyncTask(task) + } } func (sc *SchedulerCache) Snapshot() *kbapi.ClusterInfo { @@ -551,20 +515,17 @@ func (sc *SchedulerCache) Snapshot() *kbapi.ClusterInfo { defer sc.Mutex.Unlock() snapshot := &kbapi.ClusterInfo{ - Nodes: make([]*kbapi.NodeInfo, 0, len(sc.Nodes)), - Jobs: make([]*kbapi.JobInfo, 0, len(sc.Jobs)), - Queues: make([]*kbapi.QueueInfo, 0, len(sc.Queues)), - Others: make([]*kbapi.TaskInfo, 0, 10), + Nodes: make(map[string]*kbapi.NodeInfo), + Jobs: make(map[kbapi.JobID]*kbapi.JobInfo), + Queues: make(map[kbapi.QueueID]*kbapi.QueueInfo), } for _, value := range sc.Nodes { - snapshot.Nodes = append(snapshot.Nodes, value.Clone()) + snapshot.Nodes[value.Name] = value.Clone() } - queues := map[kbapi.QueueID]struct{}{} for _, value := range sc.Queues { - snapshot.Queues = append(snapshot.Queues, value.Clone()) - queues[value.UID] = struct{}{} + snapshot.Queues[value.UID] = value.Clone() } for _, value := range sc.Jobs { @@ -573,25 +534,32 @@ func (sc *SchedulerCache) Snapshot() *kbapi.ClusterInfo { glog.V(4).Infof("The scheduling spec of Job <%v:%s/%s> is nil, ignore it.", value.UID, value.Namespace, value.Name) - // Also tracing the running task assigned by other scheduler. - for _, task := range value.TaskStatusIndex[kbapi.Running] { - snapshot.Others = append(snapshot.Others, task.Clone()) - } - continue } - if _, found := queues[value.Queue]; !found { - glog.V(3).Infof("The Queue <%v> of Job <%v> does not exist, ignore it.", - value.Queue, value.UID) + if _, found := snapshot.Queues[value.Queue]; !found { + glog.V(3).Infof("The Queue <%v> of Job <%v/%v> does not exist, ignore it.", + value.Queue, value.Namespace, value.Name) continue } - snapshot.Jobs = append(snapshot.Jobs, value.Clone()) + if value.PodGroup != nil { + value.Priority = sc.defaultPriority + + priName := value.PodGroup.Spec.PriorityClassName + if priorityClass, found := sc.PriorityClasses[priName]; found { + value.Priority = priorityClass.Value + } + + glog.V(4).Infof("The priority of job <%s/%s> is <%s/%d>", + value.Namespace, value.Name, priName, value.Priority) + } + + snapshot.Jobs[value.UID] = value.Clone() } - glog.V(3).Infof("There are <%d> Jobs and <%d> Queues in total for scheduling.", - len(snapshot.Jobs), len(snapshot.Queues)) + glog.V(3).Infof("There are <%d> Jobs, <%d> Queues and <%d> Nodes in total for scheduling.", + len(snapshot.Jobs), len(snapshot.Queues), len(snapshot.Nodes)) return snapshot } @@ -619,14 +587,7 @@ func (sc *SchedulerCache) String() string { if len(sc.Jobs) != 0 { str = str + "Jobs:\n" for _, job := range sc.Jobs { - str = str + fmt.Sprintf("\t Job(%s) name(%s) minAvailable(%v)\n", - job.UID, job.Name, job.MinAvailable) - - i := 0 - for _, task := range job.Tasks { - str = str + fmt.Sprintf("\t\t %d: %v\n", i, task) - i++ - } + str = str + fmt.Sprintf("\t %s\n", job) } } @@ -637,17 +598,19 @@ func (sc *SchedulerCache) String() string { func (sc *SchedulerCache) RecordJobStatusEvent(job *kbapi.JobInfo) { jobErrMsg := job.FitError() - pgUnschedulable := job.PodGroup != nil && - (job.PodGroup.Status.Phase == v1alpha1.PodGroupUnknown || - job.PodGroup.Status.Phase == v1alpha1.PodGroupPending) - pdbUnschedulabe := job.PDB != nil && len(job.TaskStatusIndex[api.Pending]) != 0 - - // If pending or unschedulable, record unschedulable event. - if pgUnschedulable || pdbUnschedulabe { - msg := fmt.Sprintf("%v/%v tasks in gang unschedulable: %v", - len(job.TaskStatusIndex[api.Pending]), len(job.Tasks), job.FitError()) - sc.Recorder.Eventf(job.PodGroup, v1.EventTypeWarning, - string(v1alpha1.PodGroupUnschedulableType), msg) + if !shadowPodGroup(job.PodGroup) { + pgUnschedulable := job.PodGroup != nil && + (job.PodGroup.Status.Phase == v1alpha1.PodGroupUnknown || + job.PodGroup.Status.Phase == v1alpha1.PodGroupPending) + pdbUnschedulabe := job.PDB != nil && len(job.TaskStatusIndex[api.Pending]) != 0 + + // If pending or unschedulable, record unschedulable event. + if pgUnschedulable || pdbUnschedulabe { + msg := fmt.Sprintf("%v/%v tasks in gang unschedulable: %v", + len(job.TaskStatusIndex[api.Pending]), len(job.Tasks), job.FitError()) + sc.Recorder.Eventf(job.PodGroup, v1.EventTypeWarning, + string(v1alpha1.PodGroupUnschedulableType), msg) + } } // Update podCondition for tasks Allocated and Pending before job discarded @@ -663,11 +626,13 @@ func (sc *SchedulerCache) RecordJobStatusEvent(job *kbapi.JobInfo) { // UpdateJobStatus update the status of job and its tasks. func (sc *SchedulerCache) UpdateJobStatus(job *kbapi.JobInfo) (*kbapi.JobInfo, error) { - pg, err := sc.StatusUpdater.UpdatePodGroup(job.PodGroup) - if err != nil { - return nil, err + if !shadowPodGroup(job.PodGroup) { + pg, err := sc.StatusUpdater.UpdatePodGroup(job.PodGroup) + if err != nil { + return nil, err + } + job.PodGroup = pg } - job.PodGroup = pg sc.RecordJobStatusEvent(job) diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/event_handlers.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/event_handlers.go index 8867c1e112..72055f3b28 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/event_handlers.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/event_handlers.go @@ -24,6 +24,7 @@ import ( "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1beta1" + "k8s.io/api/scheduling/v1beta1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" @@ -37,15 +38,32 @@ func isTerminated(status kbapi.TaskStatus) bool { return status == kbapi.Succeeded || status == kbapi.Failed } -func (sc *SchedulerCache) addTask(pi *kbapi.TaskInfo) error { - if len(pi.Job) != 0 { +func (sc *SchedulerCache) getOrCreateJob(pi *kbapi.TaskInfo) *kbapi.JobInfo { + if len(pi.Job) == 0 { + pb := createShadowPodGroup(pi.Pod) + pi.Job = kbapi.JobID(pb.Name) + + if _, found := sc.Jobs[pi.Job]; !found { + job := kbapi.NewJobInfo(pi.Job) + job.SetPodGroup(pb) + // Set default queue for shadow podgroup. + job.Queue = kbapi.QueueID(sc.defaultQueue) + + sc.Jobs[pi.Job] = job + } + } else { if _, found := sc.Jobs[pi.Job]; !found { sc.Jobs[pi.Job] = kbapi.NewJobInfo(pi.Job) } - - sc.Jobs[pi.Job].AddTaskInfo(pi) } + return sc.Jobs[pi.Job] +} + +func (sc *SchedulerCache) addTask(pi *kbapi.TaskInfo) error { + job := sc.getOrCreateJob(pi) + job.AddTaskInfo(pi) + if len(pi.NodeName) != 0 { if _, found := sc.Nodes[pi.NodeName]; !found { sc.Nodes[pi.NodeName] = kbapi.NewNodeInfo(nil) @@ -354,6 +372,11 @@ func (sc *SchedulerCache) setPodGroup(ss *kbv1.PodGroup) error { sc.Jobs[job].SetPodGroup(ss) + // TODO(k82cn): set default queue in admission. + if len(ss.Spec.Queue) == 0 { + sc.Jobs[job].Queue = kbapi.QueueID(sc.defaultQueue) + } + return nil } @@ -389,11 +412,6 @@ func (sc *SchedulerCache) AddPodGroup(obj interface{}) { sc.Mutex.Lock() defer sc.Mutex.Unlock() - // If namespace as queue, the `.spec.Queue` of PodGroup is ignored. - if sc.namespaceAsQueue { - ss.Spec.Queue = "" - } - glog.V(4).Infof("Add PodGroup(%s) into cache, spec(%#v)", ss.Name, ss.Spec) err := sc.setPodGroup(ss) if err != nil { @@ -467,6 +485,8 @@ func (sc *SchedulerCache) setPDB(pdb *policyv1.PodDisruptionBudget) error { } sc.Jobs[job].SetPDB(pdb) + // Set it to default queue, as PDB did not support queue right now. + sc.Jobs[job].Queue = kbapi.QueueID(sc.defaultQueue) return nil } @@ -653,103 +673,96 @@ func (sc *SchedulerCache) deleteQueue(queue *kbv1.Queue) error { return nil } -func (sc *SchedulerCache) AddNamespace(obj interface{}) { - ss, ok := obj.(*v1.Namespace) - if !ok { - glog.Errorf("Cannot convert to *v1.Namespace: %v", obj) +func (sc *SchedulerCache) DeletePriorityClass(obj interface{}) { + var ss *v1beta1.PriorityClass + switch t := obj.(type) { + case *v1beta1.PriorityClass: + ss = t + case cache.DeletedFinalStateUnknown: + var ok bool + ss, ok = t.Obj.(*v1beta1.PriorityClass) + if !ok { + glog.Errorf("Cannot convert to *v1beta1.PriorityClass: %v", t.Obj) + return + } + default: + glog.Errorf("Cannot convert to *v1beta1.PriorityClass: %v", t) return } sc.Mutex.Lock() defer sc.Mutex.Unlock() - glog.V(4).Infof("Add Queue(%s) into cache, spec(%#v)", ss.Name, ss.Spec) - err := sc.addNamespace(ss) - if err != nil { - glog.Errorf("Failed to add Queue %s into cache: %v", ss.Name, err) - return - } - return + sc.deletePriorityClass(ss) } -func (sc *SchedulerCache) UpdateNamespace(oldObj, newObj interface{}) { - oldSS, ok := oldObj.(*v1.Namespace) +func (sc *SchedulerCache) UpdatePriorityClass(oldObj, newObj interface{}) { + oldSS, ok := oldObj.(*v1beta1.PriorityClass) if !ok { - glog.Errorf("Cannot convert oldObj to *v1.Namespace: %v", oldObj) + glog.Errorf("Cannot convert oldObj to *v1beta1.PriorityClass: %v", oldObj) + return + } - newSS, ok := newObj.(*v1.Namespace) + + newSS, ok := newObj.(*v1beta1.PriorityClass) if !ok { - glog.Errorf("Cannot convert newObj to *v1.Namespace: %v", newObj) + glog.Errorf("Cannot convert newObj to *v1beta1.PriorityClass: %v", newObj) + return + } sc.Mutex.Lock() defer sc.Mutex.Unlock() - err := sc.updateNamespace(oldSS, newSS) - if err != nil { - glog.Errorf("Failed to update Queue (NS) %s into cache: %v", oldSS.Name, err) - return - } - return + sc.deletePriorityClass(oldSS) + sc.addPriorityClass(newSS) } -func (sc *SchedulerCache) DeleteNamespace(obj interface{}) { - var ss *v1.Namespace +func (sc *SchedulerCache) AddPriorityClass(obj interface{}) { + var ss *v1beta1.PriorityClass switch t := obj.(type) { - case *v1.Namespace: + case *v1beta1.PriorityClass: ss = t case cache.DeletedFinalStateUnknown: var ok bool - ss, ok = t.Obj.(*v1.Namespace) + ss, ok = t.Obj.(*v1beta1.PriorityClass) if !ok { - glog.Errorf("Cannot convert to *v1.Namespace: %v", t.Obj) + glog.Errorf("Cannot convert to *v1beta1.PriorityClass: %v", t.Obj) return } default: - glog.Errorf("Cannot convert to *v1.Namespace: %v", t) + glog.Errorf("Cannot convert to *v1beta1.PriorityClass: %v", t) return } sc.Mutex.Lock() defer sc.Mutex.Unlock() - err := sc.deleteNamespace(ss) - if err != nil { - glog.Errorf("Failed to delete Queue (NS) %s from cache: %v", ss.Name, err) - return - } - return + sc.addPriorityClass(ss) } -func (sc *SchedulerCache) addNamespace(ns *v1.Namespace) error { - qi := &kbapi.QueueInfo{ - UID: kbapi.QueueID(ns.Name), - Name: ns.Name, +func (sc *SchedulerCache) deletePriorityClass(pc *v1beta1.PriorityClass) { + if pc.GlobalDefault { + sc.defaultPriorityClass = nil + sc.defaultPriority = 0 - Weight: 1, } - sc.Queues[qi.UID] = qi - return nil + delete(sc.PriorityClasses, pc.Name) } -func (sc *SchedulerCache) updateNamespace(oldObj, newObj *v1.Namespace) error { - sc.deleteNamespace(oldObj) - sc.addNamespace(newObj) +func (sc *SchedulerCache) addPriorityClass(pc *v1beta1.PriorityClass) { + if pc.GlobalDefault { + if sc.defaultPriorityClass != nil { + glog.Errorf("Updated default priority class from <%s> to <%s> forcefully.", + sc.defaultPriorityClass.Name, pc.Name) - return nil -} - -func (sc *SchedulerCache) deleteNamespace(ns *v1.Namespace) error { - qi := &kbapi.QueueInfo{ - UID: kbapi.QueueID(ns.Name), - Name: ns.Name, - - Weight: 1, + } + sc.defaultPriorityClass = pc + sc.defaultPriority = pc.Value } - delete(sc.Queues, qi.UID) - return nil + sc.PriorityClasses[pc.Name] = pc } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/interface.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/interface.go index 8876939953..38b991974a 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/interface.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/interface.go @@ -71,6 +71,6 @@ type Evictor interface { // StatusUpdater updates pod with given PodCondition type StatusUpdater interface { - UpdatePod(pod *v1.Pod, podCondition *v1.PodCondition) (*v1.Pod, error) + UpdatePodCondition(pod *v1.Pod, podCondition *v1.PodCondition) (*v1.Pod, error) UpdatePodGroup(pg *v1alpha1.PodGroup) (*v1alpha1.PodGroup, error) } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/util.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/util.go new file mode 100644 index 0000000000..411b47552d --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache/util.go @@ -0,0 +1,60 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" + "github.com/kubernetes-sigs/kube-batch/pkg/apis/utils" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" +) + +const ( + shadowPodGroupKey = "kube-batch/shadow-pod-group" +) + +func shadowPodGroup(pg *v1alpha1.PodGroup) bool { + if pg == nil { + return true + } + + _, found := pg.Annotations[shadowPodGroupKey] + + return found +} + +func createShadowPodGroup(pod *v1.Pod) *v1alpha1.PodGroup { + jobID := api.JobID(utils.GetController(pod)) + if len(jobID) == 0 { + jobID = api.JobID(pod.UID) + } + + return &v1alpha1.PodGroup{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: pod.Namespace, + Name: string(jobID), + Annotations: map[string]string{ + shadowPodGroupKey: string(jobID), + }, + }, + Spec: v1alpha1.PodGroupSpec{ + MinMember: 1, + }, + } +} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf/scheduler_conf.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf/scheduler_conf.go index 838c071776..fdcbdff902 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf/scheduler_conf.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf/scheduler_conf.go @@ -47,4 +47,6 @@ type PluginOption struct { QueueOrderDisabled bool `yaml:"disableQueueOrder"` // PredicateDisabled defines whether predicateFn is disabled PredicateDisabled bool `yaml:"disablePredicate"` + // NodeOrderDisabled defines whether NodeOrderFn is disabled + NodeOrderDisabled bool `yaml:"disableNodeOrder"` } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/framework.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/framework.go index 2362ff7526..a25f1c6e0d 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/framework.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/framework.go @@ -17,10 +17,13 @@ limitations under the License. package framework import ( + "time" + "github.com/golang/glog" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics" ) func OpenSession(cache cache.Cache, tiers []conf.Tier) *Session { @@ -39,7 +42,9 @@ func OpenSession(cache cache.Cache, tiers []conf.Tier) *Session { } for _, plugin := range ssn.plugins { + onSessionOpenStart := time.Now() plugin.OnSessionOpen(ssn) + metrics.UpdatePluginDuration(plugin.Name(), metrics.OnSessionOpen, metrics.Duration(onSessionOpenStart)) } return ssn @@ -47,7 +52,9 @@ func OpenSession(cache cache.Cache, tiers []conf.Tier) *Session { func CloseSession(ssn *Session) { for _, plugin := range ssn.plugins { + onSessionCloseStart := time.Now() plugin.OnSessionClose(ssn) + metrics.UpdatePluginDuration(plugin.Name(), metrics.OnSessionClose, metrics.Duration(onSessionCloseStart)) } closeSession(ssn) diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session.go index 076006c5a8..c8dbd6e495 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session.go @@ -21,7 +21,7 @@ import ( "github.com/golang/glog" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/uuid" @@ -30,6 +30,7 @@ import ( "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/conf" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics" ) type Session struct { @@ -37,15 +38,11 @@ type Session struct { cache cache.Cache - Jobs []*api.JobInfo - JobIndex map[api.JobID]*api.JobInfo - Nodes []*api.NodeInfo - NodeIndex map[string]*api.NodeInfo - Queues []*api.QueueInfo - QueueIndex map[api.QueueID]*api.QueueInfo - Others []*api.TaskInfo - Backlog []*api.JobInfo - Tiers []conf.Tier + Jobs map[api.JobID]*api.JobInfo + Nodes map[string]*api.NodeInfo + Queues map[api.QueueID]*api.QueueInfo + Backlog []*api.JobInfo + Tiers []conf.Tier plugins map[string]Plugin eventHandlers []*EventHandler @@ -53,6 +50,7 @@ type Session struct { queueOrderFns map[string]api.CompareFn taskOrderFns map[string]api.CompareFn predicateFns map[string]api.PredicateFn + nodeOrderFns map[string]api.NodeOrderFn preemptableFns map[string]api.EvictableFn reclaimableFns map[string]api.EvictableFn overusedFns map[string]api.ValidateFn @@ -62,17 +60,19 @@ type Session struct { func openSession(cache cache.Cache) *Session { ssn := &Session{ - UID: uuid.NewUUID(), - cache: cache, - JobIndex: map[api.JobID]*api.JobInfo{}, - NodeIndex: map[string]*api.NodeInfo{}, - QueueIndex: map[api.QueueID]*api.QueueInfo{}, + UID: uuid.NewUUID(), + cache: cache, + + Jobs: map[api.JobID]*api.JobInfo{}, + Nodes: map[string]*api.NodeInfo{}, + Queues: map[api.QueueID]*api.QueueInfo{}, plugins: map[string]Plugin{}, jobOrderFns: map[string]api.CompareFn{}, queueOrderFns: map[string]api.CompareFn{}, taskOrderFns: map[string]api.CompareFn{}, predicateFns: map[string]api.PredicateFn{}, + nodeOrderFns: map[string]api.NodeOrderFn{}, preemptableFns: map[string]api.EvictableFn{}, reclaimableFns: map[string]api.EvictableFn{}, overusedFns: map[string]api.ValidateFn{}, @@ -82,7 +82,8 @@ func openSession(cache cache.Cache) *Session { snapshot := cache.Snapshot() - for _, job := range snapshot.Jobs { + ssn.Jobs = snapshot.Jobs + for _, job := range ssn.Jobs { if vjr := ssn.JobValid(job); vjr != nil { if !vjr.Pass { jc := &v1alpha1.PodGroupCondition{ @@ -99,27 +100,12 @@ func openSession(cache cache.Cache) *Session { } } - continue + delete(ssn.Jobs, job.UID) } - - ssn.Jobs = append(ssn.Jobs, job) - } - - for _, job := range ssn.Jobs { - ssn.JobIndex[job.UID] = job } ssn.Nodes = snapshot.Nodes - for _, node := range ssn.Nodes { - ssn.NodeIndex[node.Name] = node - } - ssn.Queues = snapshot.Queues - for _, queue := range ssn.Queues { - ssn.QueueIndex[queue.UID] = queue - } - - ssn.Others = snapshot.Others glog.V(3).Infof("Open Session %v with <%d> Job and <%d> Queues", ssn.UID, len(ssn.Jobs), len(ssn.Queues)) @@ -144,9 +130,7 @@ func closeSession(ssn *Session) { } ssn.Jobs = nil - ssn.JobIndex = nil ssn.Nodes = nil - ssn.NodeIndex = nil ssn.Backlog = nil ssn.plugins = nil ssn.eventHandlers = nil @@ -204,7 +188,7 @@ func (ssn *Session) Statement() *Statement { func (ssn *Session) Pipeline(task *api.TaskInfo, hostname string) error { // Only update status in session - job, found := ssn.JobIndex[task.Job] + job, found := ssn.Jobs[task.Job] if found { if err := job.UpdateTaskStatus(task, api.Pipelined); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -217,7 +201,7 @@ func (ssn *Session) Pipeline(task *api.TaskInfo, hostname string) error { task.NodeName = hostname - if node, found := ssn.NodeIndex[hostname]; found { + if node, found := ssn.Nodes[hostname]; found { if err := node.AddTask(task); err != nil { glog.Errorf("Failed to add task <%v/%v> to node <%v> in Session <%v>: %v", task.Namespace, task.Name, hostname, ssn.UID, err) @@ -246,7 +230,7 @@ func (ssn *Session) Allocate(task *api.TaskInfo, hostname string) error { } // Only update status in session - job, found := ssn.JobIndex[task.Job] + job, found := ssn.Jobs[task.Job] if found { if err := job.UpdateTaskStatus(task, api.Allocated); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -259,7 +243,7 @@ func (ssn *Session) Allocate(task *api.TaskInfo, hostname string) error { task.NodeName = hostname - if node, found := ssn.NodeIndex[hostname]; found { + if node, found := ssn.Nodes[hostname]; found { if err := node.AddTask(task); err != nil { glog.Errorf("Failed to add task <%v/%v> to node <%v> in Session <%v>: %v", task.Namespace, task.Name, hostname, ssn.UID, err) @@ -302,7 +286,7 @@ func (ssn *Session) dispatch(task *api.TaskInfo) error { } // Update status in session - if job, found := ssn.JobIndex[task.Job]; found { + if job, found := ssn.Jobs[task.Job]; found { if err := job.UpdateTaskStatus(task, api.Binding); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", task.Namespace, task.Name, api.Binding, ssn.UID, err) @@ -312,6 +296,7 @@ func (ssn *Session) dispatch(task *api.TaskInfo) error { task.Job, ssn.UID) } + metrics.UpdateTaskScheduleDuration(metrics.Duration(task.Pod.CreationTimestamp.Time)) return nil } @@ -321,7 +306,7 @@ func (ssn *Session) Evict(reclaimee *api.TaskInfo, reason string) error { } // Update status in session - job, found := ssn.JobIndex[reclaimee.Job] + job, found := ssn.Jobs[reclaimee.Job] if found { if err := job.UpdateTaskStatus(reclaimee, api.Releasing); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -333,7 +318,7 @@ func (ssn *Session) Evict(reclaimee *api.TaskInfo, reason string) error { } // Update task in node. - if node, found := ssn.NodeIndex[reclaimee.NodeName]; found { + if node, found := ssn.Nodes[reclaimee.NodeName]; found { if err := node.UpdateTask(reclaimee); err != nil { glog.Errorf("Failed to update task <%v/%v> in Session <%v>: %v", reclaimee.Namespace, reclaimee.Name, ssn.UID, err) @@ -353,7 +338,7 @@ func (ssn *Session) Evict(reclaimee *api.TaskInfo, reason string) error { // UpdateJobStatus update job condition accordingly. func (ssn *Session) UpdateJobCondition(jobInfo *api.JobInfo, cond *v1alpha1.PodGroupCondition) error { - job, ok := ssn.JobIndex[jobInfo.UID] + job, ok := ssn.Jobs[jobInfo.UID] if !ok { return fmt.Errorf("failed to find job <%s/%s>", jobInfo.Namespace, jobInfo.Name) } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session_plugins.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session_plugins.go index cf3fc57b9b..dfbe655c65 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session_plugins.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/session_plugins.go @@ -48,6 +48,10 @@ func (ssn *Session) AddPredicateFn(name string, pf api.PredicateFn) { ssn.predicateFns[name] = pf } +func (ssn *Session) AddNodeOrderFn(name string, pf api.NodeOrderFn) { + ssn.nodeOrderFns[name] = pf +} + func (ssn *Session) AddOverusedFn(name string, fn api.ValidateFn) { ssn.overusedFns[name] = fn } @@ -293,3 +297,25 @@ func (ssn *Session) PredicateFn(task *api.TaskInfo, node *api.NodeInfo) error { } return nil } + +func (ssn *Session) NodeOrderFn(task *api.TaskInfo, node *api.NodeInfo) (int, error) { + priorityScore := 0 + for _, tier := range ssn.Tiers { + for _, plugin := range tier.Plugins { + if plugin.NodeOrderDisabled { + continue + } + pfn, found := ssn.nodeOrderFns[plugin.Name] + if !found { + continue + } + score, err := pfn(task, node) + if err != nil { + return 0, err + } else { + priorityScore = priorityScore + score + } + } + } + return priorityScore, nil +} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/statement.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/statement.go index 5435a2d423..9ed6ea1fdd 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/statement.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework/statement.go @@ -34,7 +34,7 @@ type operation struct { func (s *Statement) Evict(reclaimee *api.TaskInfo, reason string) error { // Update status in session - job, found := s.ssn.JobIndex[reclaimee.Job] + job, found := s.ssn.Jobs[reclaimee.Job] if found { if err := job.UpdateTaskStatus(reclaimee, api.Releasing); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -46,7 +46,7 @@ func (s *Statement) Evict(reclaimee *api.TaskInfo, reason string) error { } // Update task in node. - if node, found := s.ssn.NodeIndex[reclaimee.NodeName]; found { + if node, found := s.ssn.Nodes[reclaimee.NodeName]; found { node.UpdateTask(reclaimee) } @@ -80,7 +80,7 @@ func (s *Statement) evict(reclaimee *api.TaskInfo, reason string) error { func (s *Statement) unevict(reclaimee *api.TaskInfo, reason string) error { // Update status in session - job, found := s.ssn.JobIndex[reclaimee.Job] + job, found := s.ssn.Jobs[reclaimee.Job] if found { if err := job.UpdateTaskStatus(reclaimee, api.Running); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -92,7 +92,7 @@ func (s *Statement) unevict(reclaimee *api.TaskInfo, reason string) error { } // Update task in node. - if node, found := s.ssn.NodeIndex[reclaimee.NodeName]; found { + if node, found := s.ssn.Nodes[reclaimee.NodeName]; found { node.AddTask(reclaimee) } @@ -109,7 +109,7 @@ func (s *Statement) unevict(reclaimee *api.TaskInfo, reason string) error { func (s *Statement) Pipeline(task *api.TaskInfo, hostname string) error { // Only update status in session - job, found := s.ssn.JobIndex[task.Job] + job, found := s.ssn.Jobs[task.Job] if found { if err := job.UpdateTaskStatus(task, api.Pipelined); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -122,7 +122,7 @@ func (s *Statement) Pipeline(task *api.TaskInfo, hostname string) error { task.NodeName = hostname - if node, found := s.ssn.NodeIndex[hostname]; found { + if node, found := s.ssn.Nodes[hostname]; found { if err := node.AddTask(task); err != nil { glog.Errorf("Failed to pipeline task <%v/%v> to node <%v> in Session <%v>: %v", task.Namespace, task.Name, hostname, s.ssn.UID, err) @@ -155,7 +155,7 @@ func (s *Statement) pipeline(task *api.TaskInfo) { func (s *Statement) unpipeline(task *api.TaskInfo) error { // Only update status in session - job, found := s.ssn.JobIndex[task.Job] + job, found := s.ssn.Jobs[task.Job] if found { if err := job.UpdateTaskStatus(task, api.Pending); err != nil { glog.Errorf("Failed to update task <%v/%v> status to %v in Session <%v>: %v", @@ -168,7 +168,7 @@ func (s *Statement) unpipeline(task *api.TaskInfo) error { hostname := task.NodeName - if node, found := s.ssn.NodeIndex[hostname]; found { + if node, found := s.ssn.Nodes[hostname]; found { if err := node.RemoveTask(task); err != nil { glog.Errorf("Failed to pipeline task <%v/%v> to node <%v> in Session <%v>: %v", task.Namespace, task.Name, hostname, s.ssn.UID, err) diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics/metrics.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics/metrics.go new file mode 100644 index 0000000000..4e634c65f6 --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics/metrics.go @@ -0,0 +1,191 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" // auto-registry collectors in default registry +) + +const ( + // KubeBatchNamespace - namespace in prometheus used by kube-batch + KubeBatchNamespace = "kube_batch" + + // OnSessionOpen label + OnSessionOpen = "OnSessionOpen" + + // OnSessionClose label + OnSessionClose = "OnSessionClose" +) + +var ( + e2eSchedulingLatency = promauto.NewHistogram( + prometheus.HistogramOpts{ + Subsystem: KubeBatchNamespace, + Name: "e2e_scheduling_latency_milliseconds", + Help: "E2e scheduling latency in milliseconds (scheduling algorithm + binding)", + Buckets: prometheus.ExponentialBuckets(5, 2, 10), + }, + ) + + pluginSchedulingLatency = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Subsystem: KubeBatchNamespace, + Name: "plugin_scheduling_latency_microseconds", + Help: "Plugin scheduling latency in microseconds", + Buckets: prometheus.ExponentialBuckets(5, 2, 10), + }, []string{"plugin", "OnSession"}, + ) + + actionSchedulingLatency = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Subsystem: KubeBatchNamespace, + Name: "action_scheduling_latency_microseconds", + Help: "Action scheduling latency in microseconds", + Buckets: prometheus.ExponentialBuckets(5, 2, 10), + }, []string{"action"}, + ) + + taskSchedulingLatency = promauto.NewHistogram( + prometheus.HistogramOpts{ + Subsystem: KubeBatchNamespace, + Name: "task_scheduling_latency_microseconds", + Help: "Task scheduling latency in microseconds", + Buckets: prometheus.ExponentialBuckets(5, 2, 10), + }, + ) + + scheduleAttempts = promauto.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: KubeBatchNamespace, + Name: "schedule_attempts_total", + Help: "Number of attempts to schedule pods, by the result. 'unschedulable' means a pod could not be scheduled, while 'error' means an internal scheduler problem.", + }, []string{"result"}, + ) + + preemptionVictims = promauto.NewGauge( + prometheus.GaugeOpts{ + Subsystem: KubeBatchNamespace, + Name: "pod_preemption_victims", + Help: "Number of selected preemption victims", + }, + ) + + preemptionAttempts = promauto.NewCounter( + prometheus.CounterOpts{ + Subsystem: KubeBatchNamespace, + Name: "total_preemption_attempts", + Help: "Total preemption attempts in the cluster till now", + }, + ) + + unscheduleTaskCount = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Subsystem: KubeBatchNamespace, + Name: "unschedule_task_count", + Help: "Number of tasks could not be scheduled", + }, []string{"job_id"}, + ) + + unscheduleJobCount = promauto.NewGauge( + prometheus.GaugeOpts{ + Subsystem: KubeBatchNamespace, + Name: "unschedule_job_count", + Help: "Number of jobs could not be scheduled", + }, + ) + + jobRetryCount = promauto.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: KubeBatchNamespace, + Name: "job_retry_counts", + Help: "Number of retry counts for one job", + }, []string{"job_id"}, + ) +) + +// UpdatePluginDuration updates latency for every plugin +func UpdatePluginDuration(pluginName, OnSessionStatus string, duration time.Duration) { + pluginSchedulingLatency.WithLabelValues(pluginName, OnSessionStatus).Observe(DurationInMicroseconds(duration)) +} + +// UpdateActionDuration updates latency for every action +func UpdateActionDuration(actionName string, duration time.Duration) { + actionSchedulingLatency.WithLabelValues(actionName).Observe(DurationInMicroseconds(duration)) +} + +// UpdateE2eDuration updates entire end to end scheduling latency +func UpdateE2eDuration(duration time.Duration) { + e2eSchedulingLatency.Observe(DurationInMilliseconds(duration)) +} + +// UpdateTaskScheduleDuration updates single task scheduling latency +func UpdateTaskScheduleDuration(duration time.Duration) { + taskSchedulingLatency.Observe(DurationInMicroseconds(duration)) +} + +// UpdatePodScheduleStatus update pod schedule decision, could be Success, Failure, Error +func UpdatePodScheduleStatus(label string, count int) { + scheduleAttempts.WithLabelValues(label).Add(float64(count)) +} + +// UpdatePreemptionVictimsCount updates count of preemption victims +func UpdatePreemptionVictimsCount(victimsCount int) { + preemptionVictims.Set(float64(victimsCount)) +} + +// RegisterPreemptionAttempts records number of attempts for preemtion +func RegisterPreemptionAttempts() { + preemptionAttempts.Inc() +} + +// UpdateUnscheduleTaskCount records total number of unscheduleable tasks +func UpdateUnscheduleTaskCount(jobID string, taskCount int) { + unscheduleTaskCount.WithLabelValues(jobID).Set(float64(taskCount)) +} + +// UpdateUnscheduleJobCount records total number of unscheduleable jobs +func UpdateUnscheduleJobCount(jobCount int) { + unscheduleJobCount.Set(float64(jobCount)) +} + +// RegisterJobRetries total number of job retries. +func RegisterJobRetries(jobID string) { + jobRetryCount.WithLabelValues(jobID).Inc() +} + +// DurationInMicroseconds gets the time in microseconds. +func DurationInMicroseconds(duration time.Duration) float64 { + return float64(duration.Nanoseconds()) / float64(time.Microsecond.Nanoseconds()) +} + +// DurationInMilliseconds gets the time in milliseconds. +func DurationInMilliseconds(duration time.Duration) float64 { + return float64(duration.Nanoseconds()) / float64(time.Millisecond.Nanoseconds()) +} + +// DurationInSeconds gets the time in seconds. +func DurationInSeconds(duration time.Duration) float64 { + return duration.Seconds() +} + +// Duration get the time since specified start +func Duration(start time.Time) time.Duration { + return time.Since(start) +} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/conformance/conformance.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/conformance/conformance.go new file mode 100644 index 0000000000..779c3f79a9 --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/conformance/conformance.go @@ -0,0 +1,62 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conformance + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/apis/scheduling" + + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" +) + +type conformancePlugin struct { +} + +func New() framework.Plugin { + return &conformancePlugin{} +} + +func (pp *conformancePlugin) Name() string { + return "conformance" +} + +func (pp *conformancePlugin) OnSessionOpen(ssn *framework.Session) { + evictableFn := func(evictor *api.TaskInfo, evictees []*api.TaskInfo) []*api.TaskInfo { + var victims []*api.TaskInfo + + for _, evictee := range evictees { + className := evictee.Pod.Spec.PriorityClassName + // Skip critical pod. + if className == scheduling.SystemClusterCritical || + className == scheduling.SystemNodeCritical || + evictee.Namespace == v1.NamespaceSystem { + + continue + } + + victims = append(victims, evictee) + } + + return victims + } + + ssn.AddPreemptableFn(pp.Name(), evictableFn) + ssn.AddReclaimableFn(pp.Name(), evictableFn) +} + +func (pp *conformancePlugin) OnSessionClose(ssn *framework.Session) {} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/factory.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/factory.go similarity index 71% rename from vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/factory.go rename to vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/factory.go index 4f039736bc..331b9db09f 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/factory.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/factory.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2019 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,21 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package scheduler +package plugins import ( - "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/allocate" - "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/backfill" - "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/preempt" - "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/actions/reclaim" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/conformance" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/drf" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/gang" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/nodeorder" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/predicates" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/priority" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/proportion" - - "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" ) func init() { @@ -37,13 +34,9 @@ func init() { framework.RegisterPluginBuilder("gang", gang.New) framework.RegisterPluginBuilder("predicates", predicates.New) framework.RegisterPluginBuilder("priority", priority.New) + framework.RegisterPluginBuilder("nodeorder", nodeorder.New) + framework.RegisterPluginBuilder("conformance", conformance.New) // Plugins for Queues framework.RegisterPluginBuilder("proportion", proportion.New) - - // Actions - framework.RegisterAction(reclaim.New()) - framework.RegisterAction(allocate.New()) - framework.RegisterAction(backfill.New()) - framework.RegisterAction(preempt.New()) } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/gang/gang.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/gang/gang.go index 314114fc57..7c85f9aefa 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/gang/gang.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/gang/gang.go @@ -21,12 +21,13 @@ import ( "github.com/golang/glog" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics" ) type gangPlugin struct { @@ -105,9 +106,9 @@ func (gp *gangPlugin) OnSessionOpen(ssn *framework.Session) { var victims []*api.TaskInfo for _, preemptee := range preemptees { - job := ssn.JobIndex[preemptee.Job] + job := ssn.Jobs[preemptee.Job] occupid := readyTaskNum(job) - preemptable := job.MinAvailable <= occupid-1 + preemptable := job.MinAvailable <= occupid-1 || job.MinAvailable == 1 if !preemptable { glog.V(3).Infof("Can not preempt task <%v/%v> because of gang-scheduling", @@ -148,17 +149,6 @@ func (gp *gangPlugin) OnSessionOpen(ssn *framework.Session) { return -1 } - if !lReady && !rReady { - if lv.CreationTimestamp.Equal(&rv.CreationTimestamp) { - if lv.UID < rv.UID { - return -1 - } - } else if lv.CreationTimestamp.Before(&rv.CreationTimestamp) { - return -1 - } - return 1 - } - return 0 } @@ -167,11 +157,18 @@ func (gp *gangPlugin) OnSessionOpen(ssn *framework.Session) { } func (gp *gangPlugin) OnSessionClose(ssn *framework.Session) { + var unreadyTaskCount int32 + var unScheduleJobCount int for _, job := range ssn.Jobs { if !jobReady(job) { + unreadyTaskCount = job.MinAvailable - readyTaskNum(job) msg := fmt.Sprintf("%v/%v tasks in gang unschedulable: %v", job.MinAvailable-readyTaskNum(job), len(job.Tasks), job.FitError()) + unScheduleJobCount += 1 + metrics.UpdateUnscheduleTaskCount(job.Name, int(unreadyTaskCount)) + metrics.RegisterJobRetries(job.Name) + jc := &v1alpha1.PodGroupCondition{ Type: v1alpha1.PodGroupUnschedulableType, Status: v1.ConditionTrue, @@ -187,4 +184,6 @@ func (gp *gangPlugin) OnSessionClose(ssn *framework.Session) { } } } + + metrics.UpdateUnscheduleJobCount(unScheduleJobCount) } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/nodeorder/nodeorder.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/nodeorder/nodeorder.go new file mode 100644 index 0000000000..d2b40f6f1c --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/nodeorder/nodeorder.go @@ -0,0 +1,214 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package nodeorder + +import ( + "fmt" + + "github.com/golang/glog" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + "k8s.io/kubernetes/pkg/scheduler/cache" + + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" +) + +type nodeOrderPlugin struct { +} + +func getInterPodAffinityScore(name string, interPodAffinityScore schedulerapi.HostPriorityList) int { + for _, hostPriority := range interPodAffinityScore { + if hostPriority.Host == name { + return hostPriority.Score + } + } + return 0 +} + +func generateNodeMapAndSlice(nodes map[string]*api.NodeInfo) (map[string]*cache.NodeInfo, []*v1.Node) { + var nodeMap map[string]*cache.NodeInfo + var nodeSlice []*v1.Node + nodeMap = make(map[string]*cache.NodeInfo) + for _, node := range nodes { + nodeInfo := cache.NewNodeInfo(node.Pods()...) + nodeInfo.SetNode(node.Node) + nodeMap[node.Name] = nodeInfo + nodeSlice = append(nodeSlice, node.Node) + } + return nodeMap, nodeSlice +} + +type cachedNodeInfo struct { + session *framework.Session +} + +func (c *cachedNodeInfo) GetNodeInfo(name string) (*v1.Node, error) { + node, found := c.session.Nodes[name] + if !found { + for _, cacheNode := range c.session.Nodes { + pods := cacheNode.Pods() + for _, pod := range pods { + if pod.Spec.NodeName == "" { + return cacheNode.Node, nil + } + } + } + return nil, fmt.Errorf("failed to find node <%s>", name) + } + + return node.Node, nil +} + +type podLister struct { + session *framework.Session +} + +func (pl *podLister) List(selector labels.Selector) ([]*v1.Pod, error) { + var pods []*v1.Pod + for _, job := range pl.session.Jobs { + for status, tasks := range job.TaskStatusIndex { + if !api.AllocatedStatus(status) { + continue + } + + for _, task := range tasks { + if selector.Matches(labels.Set(task.Pod.Labels)) { + if task.NodeName != task.Pod.Spec.NodeName { + pod := task.Pod.DeepCopy() + pod.Spec.NodeName = task.NodeName + pods = append(pods, pod) + } else { + pods = append(pods, task.Pod) + } + } + } + } + } + + return pods, nil +} + +func (pl *podLister) FilteredList(podFilter algorithm.PodFilter, selector labels.Selector) ([]*v1.Pod, error) { + var pods []*v1.Pod + for _, job := range pl.session.Jobs { + for status, tasks := range job.TaskStatusIndex { + if !api.AllocatedStatus(status) { + continue + } + + for _, task := range tasks { + if podFilter(task.Pod) && selector.Matches(labels.Set(task.Pod.Labels)) { + if task.NodeName != task.Pod.Spec.NodeName { + pod := task.Pod.DeepCopy() + pod.Spec.NodeName = task.NodeName + pods = append(pods, pod) + } else { + pods = append(pods, task.Pod) + } + } + } + } + } + + return pods, nil +} + +type nodeLister struct { + session *framework.Session +} + +func (nl *nodeLister) List() ([]*v1.Node, error) { + var nodes []*v1.Node + for _, node := range nl.session.Nodes { + nodes = append(nodes, node.Node) + } + return nodes, nil +} + +//New function returns prioritizePlugin object +func New() framework.Plugin { + return &nodeOrderPlugin{} +} + +func (pp *nodeOrderPlugin) Name() string { + return "nodeorder" +} + +func (pp *nodeOrderPlugin) OnSessionOpen(ssn *framework.Session) { + nodeOrderFn := func(task *api.TaskInfo, node *api.NodeInfo) (int, error) { + + pl := &podLister{ + session: ssn, + } + + nl := &nodeLister{ + session: ssn, + } + + cn := &cachedNodeInfo{ + session: ssn, + } + + var nodeMap map[string]*cache.NodeInfo + var nodeSlice []*v1.Node + var interPodAffinityScore schedulerapi.HostPriorityList + + nodeMap, nodeSlice = generateNodeMapAndSlice(ssn.Nodes) + + nodeInfo := cache.NewNodeInfo(node.Pods()...) + nodeInfo.SetNode(node.Node) + var score = 0 + + //TODO: Add ImageLocalityPriority Function once priorityMetadata is published + //Issue: #74132 in kubernetes ( https://github.com/kubernetes/kubernetes/issues/74132 ) + + host, err := priorities.LeastRequestedPriorityMap(task.Pod, nil, nodeInfo) + if err != nil { + glog.Warningf("Least Requested Priority Failed because of Error: %v", err) + return 0, err + } + score = score + host.Score + + host, err = priorities.CalculateNodeAffinityPriorityMap(task.Pod, nil, nodeInfo) + if err != nil { + glog.Warningf("Calculate Node Affinity Priority Failed because of Error: %v", err) + return 0, err + } + score = score + host.Score + + mapFn := priorities.NewInterPodAffinityPriority(cn, nl, pl, v1.DefaultHardPodAffinitySymmetricWeight) + interPodAffinityScore, err = mapFn(task.Pod, nodeMap, nodeSlice) + if err != nil { + glog.Warningf("Calculate Inter Pod Affinity Priority Failed because of Error: %v", err) + return 0, err + } + hostScore := getInterPodAffinityScore(node.Name, interPodAffinityScore) + score = score + hostScore + + glog.V(4).Infof("Total Score for that node is: %d", score) + return score, nil + } + ssn.AddNodeOrderFn(pp.Name(), nodeOrderFn) +} + +func (pp *nodeOrderPlugin) OnSessionClose(ssn *framework.Session) { +} diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/predicates/predicates.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/predicates/predicates.go index 5da6eeb4e5..d190904234 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/predicates/predicates.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/predicates/predicates.go @@ -93,7 +93,7 @@ type cachedNodeInfo struct { } func (c *cachedNodeInfo) GetNodeInfo(name string) (*v1.Node, error) { - node, found := c.session.NodeIndex[name] + node, found := c.session.Nodes[name] if !found { return nil, fmt.Errorf("failed to find node <%s>", name) } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/proportion/proportion.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/proportion/proportion.go index 4a0c5a6c1b..582adf3f4e 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/proportion/proportion.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/plugins/proportion/proportion.go @@ -57,11 +57,6 @@ func (pp *proportionPlugin) OnSessionOpen(ssn *framework.Session) { pp.totalResource.Add(n.Allocatable) } - // Also remove the resource used by other scheduler. - for _, task := range ssn.Others { - pp.totalResource.Sub(task.Resreq) - } - glog.V(4).Infof("The total resource is <%v>", pp.totalResource) // Build attributes for Queues. @@ -69,7 +64,7 @@ func (pp *proportionPlugin) OnSessionOpen(ssn *framework.Session) { glog.V(4).Infof("Considering Job <%s/%s>.", job.Namespace, job.Name) if _, found := pp.queueOpts[job.Queue]; !found { - queue := ssn.QueueIndex[job.Queue] + queue := ssn.Queues[job.Queue] attr := &queueAttr{ queueID: queue.UID, name: queue.Name, @@ -163,7 +158,7 @@ func (pp *proportionPlugin) OnSessionOpen(ssn *framework.Session) { allocations := map[api.QueueID]*api.Resource{} for _, reclaimee := range reclaimees { - job := ssn.JobIndex[reclaimee.Job] + job := ssn.Jobs[reclaimee.Job] attr := pp.queueOpts[job.Queue] if _, found := allocations[job.Queue]; !found { @@ -189,13 +184,19 @@ func (pp *proportionPlugin) OnSessionOpen(ssn *framework.Session) { queue := obj.(*api.QueueInfo) attr := pp.queueOpts[queue.UID] - return attr.deserved.LessEqual(attr.allocated) + overused := attr.deserved.LessEqual(attr.allocated) + if overused { + glog.V(3).Infof("Queue <%v>: deserved <%v>, allocated <%v>, share <%v>", + queue.Name, attr.deserved, attr.allocated, attr.share) + } + + return overused }) // Register event handlers. ssn.AddEventHandler(&framework.EventHandler{ AllocateFunc: func(event *framework.Event) { - job := ssn.JobIndex[event.Task.Job] + job := ssn.Jobs[event.Task.Job] attr := pp.queueOpts[job.Queue] attr.allocated.Add(event.Task.Resreq) @@ -205,7 +206,7 @@ func (pp *proportionPlugin) OnSessionOpen(ssn *framework.Session) { event.Task.Namespace, event.Task.Name, event.Task.Resreq, attr.share) }, DeallocateFunc: func(event *framework.Event) { - job := ssn.JobIndex[event.Task.Job] + job := ssn.Jobs[event.Task.Job] attr := pp.queueOpts[job.Queue] attr.allocated.Sub(event.Task.Resreq) diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/scheduler.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/scheduler.go index bce3fd6646..d85c5c7f1a 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/scheduler.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/scheduler.go @@ -27,6 +27,7 @@ import ( schedcache "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/cache" "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/framework" + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/metrics" ) type Scheduler struct { @@ -43,13 +44,13 @@ func NewScheduler( schedulerName string, conf string, period string, - nsAsQueue bool, + defaultQueue string, ) (*Scheduler, error) { sp, _ := time.ParseDuration(period) scheduler := &Scheduler{ config: config, schedulerConf: conf, - cache: schedcache.New(config, schedulerName, nsAsQueue), + cache: schedcache.New(config, schedulerName, defaultQueue), schedulePeriod: sp, } @@ -69,6 +70,7 @@ func (pc *Scheduler) Run(stopCh <-chan struct{}) { if schedConf, err = readSchedulerConf(pc.schedulerConf); err != nil { glog.Errorf("Failed to read scheduler configuration '%s', using default configuration: %v", pc.schedulerConf, err) + schedConf = defaultSchedulerConf } } @@ -82,12 +84,16 @@ func (pc *Scheduler) Run(stopCh <-chan struct{}) { func (pc *Scheduler) runOnce() { glog.V(4).Infof("Start scheduling ...") + scheduleStartTime := time.Now() defer glog.V(4).Infof("End scheduling ...") + defer metrics.UpdateE2eDuration(metrics.Duration(scheduleStartTime)) ssn := framework.OpenSession(pc.cache, pc.plugins) defer framework.CloseSession(ssn) for _, action := range pc.actions { + actionStartTime := time.Now() action.Execute(ssn) + metrics.UpdateActionDuration(action.Name(), metrics.Duration(actionStartTime)) } } diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util.go index 9adf1251a3..4b55f9b9f6 100644 --- a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util.go +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util.go @@ -37,6 +37,7 @@ tiers: - name: drf - name: predicates - name: proportion + - name: nodeorder ` func loadSchedulerConf(confStr string) ([]framework.Action, []conf.Tier, error) { @@ -50,7 +51,6 @@ func loadSchedulerConf(confStr string) ([]framework.Action, []conf.Tier, error) if err := yaml.Unmarshal(buf, schedulerConf); err != nil { return nil, nil, err } - actionNames := strings.Split(schedulerConf.Actions, ",") for _, actionName := range actionNames { if action, found := framework.GetAction(strings.TrimSpace(actionName)); found { diff --git a/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util/sort.go b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util/sort.go new file mode 100644 index 0000000000..d4d808338c --- /dev/null +++ b/vendor/github.com/kubernetes-sigs/kube-batch/pkg/scheduler/util/sort.go @@ -0,0 +1,37 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "sort" + + "github.com/kubernetes-sigs/kube-batch/pkg/scheduler/api" +) + +func SelectBestNode(nodeScores map[int][]*api.NodeInfo) []*api.NodeInfo { + var nodesInorder []*api.NodeInfo + var keys []int + for key := range nodeScores { + keys = append(keys, key) + } + sort.Sort(sort.Reverse(sort.IntSlice(keys))) + for _, key := range keys { + nodes := nodeScores[key] + nodesInorder = append(nodesInorder, nodes...) + } + return nodesInorder +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go index 623d3d83fe..c0d70b2faf 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go @@ -29,27 +29,72 @@ type Collector interface { // collected by this Collector to the provided channel and returns once // the last descriptor has been sent. The sent descriptors fulfill the // consistency and uniqueness requirements described in the Desc - // documentation. (It is valid if one and the same Collector sends - // duplicate descriptors. Those duplicates are simply ignored. However, - // two different Collectors must not send duplicate descriptors.) This - // method idempotently sends the same descriptors throughout the - // lifetime of the Collector. If a Collector encounters an error while - // executing this method, it must send an invalid descriptor (created - // with NewInvalidDesc) to signal the error to the registry. + // documentation. + // + // It is valid if one and the same Collector sends duplicate + // descriptors. Those duplicates are simply ignored. However, two + // different Collectors must not send duplicate descriptors. + // + // Sending no descriptor at all marks the Collector as “unchecked”, + // i.e. no checks will be performed at registration time, and the + // Collector may yield any Metric it sees fit in its Collect method. + // + // This method idempotently sends the same descriptors throughout the + // lifetime of the Collector. It may be called concurrently and + // therefore must be implemented in a concurrency safe way. + // + // If a Collector encounters an error while executing this method, it + // must send an invalid descriptor (created with NewInvalidDesc) to + // signal the error to the registry. Describe(chan<- *Desc) // Collect is called by the Prometheus registry when collecting // metrics. The implementation sends each collected metric via the // provided channel and returns once the last metric has been sent. The - // descriptor of each sent metric is one of those returned by - // Describe. Returned metrics that share the same descriptor must differ - // in their variable label values. This method may be called - // concurrently and must therefore be implemented in a concurrency safe - // way. Blocking occurs at the expense of total performance of rendering - // all registered metrics. Ideally, Collector implementations support - // concurrent readers. + // descriptor of each sent metric is one of those returned by Describe + // (unless the Collector is unchecked, see above). Returned metrics that + // share the same descriptor must differ in their variable label + // values. + // + // This method may be called concurrently and must therefore be + // implemented in a concurrency safe way. Blocking occurs at the expense + // of total performance of rendering all registered metrics. Ideally, + // Collector implementations support concurrent readers. Collect(chan<- Metric) } +// DescribeByCollect is a helper to implement the Describe method of a custom +// Collector. It collects the metrics from the provided Collector and sends +// their descriptors to the provided channel. +// +// If a Collector collects the same metrics throughout its lifetime, its +// Describe method can simply be implemented as: +// +// func (c customCollector) Describe(ch chan<- *Desc) { +// DescribeByCollect(c, ch) +// } +// +// However, this will not work if the metrics collected change dynamically over +// the lifetime of the Collector in a way that their combined set of descriptors +// changes as well. The shortcut implementation will then violate the contract +// of the Describe method. If a Collector sometimes collects no metrics at all +// (for example vectors like CounterVec, GaugeVec, etc., which only collect +// metrics after a metric with a fully specified label set has been accessed), +// it might even get registered as an unchecked Collecter (cf. the Register +// method of the Registerer interface). Hence, only use this shortcut +// implementation of Describe if you are certain to fulfill the contract. +// +// The Collector example demonstrates a use of DescribeByCollect. +func DescribeByCollect(c Collector, descs chan<- *Desc) { + metrics := make(chan Metric) + go func() { + c.Collect(metrics) + close(metrics) + }() + for m := range metrics { + descs <- m.Desc() + } +} + // selfCollector implements Collector for a single Metric so that the Metric // collects itself. Add it as an anonymous field to a struct that implements // Metric, and call init with the Metric itself as an argument. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index 72d5256a50..d463e36d3e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -15,6 +15,10 @@ package prometheus import ( "errors" + "math" + "sync/atomic" + + dto "github.com/prometheus/client_model/go" ) // Counter is a Metric that represents a single numerical value that only ever @@ -42,6 +46,14 @@ type Counter interface { type CounterOpts Opts // NewCounter creates a new Counter based on the provided CounterOpts. +// +// The returned implementation tracks the counter value in two separate +// variables, a float64 and a uint64. The latter is used to track calls of the +// Inc method and calls of the Add method with a value that can be represented +// as a uint64. This allows atomic increments of the counter with optimal +// performance. (It is common to have an Inc call in very hot execution paths.) +// Both internal tracking values are added up in the Write method. This has to +// be taken into account when it comes to precision and overflow behavior. func NewCounter(opts CounterOpts) Counter { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), @@ -49,20 +61,58 @@ func NewCounter(opts CounterOpts) Counter { nil, opts.ConstLabels, ) - result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}} + result := &counter{desc: desc, labelPairs: desc.constLabelPairs} result.init(result) // Init self-collection. return result } type counter struct { - value + // valBits contains the bits of the represented float64 value, while + // valInt stores values that are exact integers. Both have to go first + // in the struct to guarantee alignment for atomic operations. + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + valBits uint64 + valInt uint64 + + selfCollector + desc *Desc + + labelPairs []*dto.LabelPair +} + +func (c *counter) Desc() *Desc { + return c.desc } func (c *counter) Add(v float64) { if v < 0 { panic(errors.New("counter cannot decrease in value")) } - c.value.Add(v) + ival := uint64(v) + if float64(ival) == v { + atomic.AddUint64(&c.valInt, ival) + return + } + + for { + oldBits := atomic.LoadUint64(&c.valBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + v) + if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) { + return + } + } +} + +func (c *counter) Inc() { + atomic.AddUint64(&c.valInt, 1) +} + +func (c *counter) Write(out *dto.Metric) error { + fval := math.Float64frombits(atomic.LoadUint64(&c.valBits)) + ival := atomic.LoadUint64(&c.valInt) + val := fval + float64(ival) + + return populateMetric(CounterValue, val, c.labelPairs, out) } // CounterVec is a Collector that bundles a set of Counters that all share the @@ -70,16 +120,12 @@ func (c *counter) Add(v float64) { // if you want to count the same thing partitioned by various dimensions // (e.g. number of HTTP requests, partitioned by response code and // method). Create instances with NewCounterVec. -// -// CounterVec embeds MetricVec. See there for a full list of methods with -// detailed documentation. type CounterVec struct { - *MetricVec + *metricVec } // NewCounterVec creates a new CounterVec based on the provided CounterOpts and -// partitioned by the given label names. At least one label name must be -// provided. +// partitioned by the given label names. func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), @@ -88,34 +134,62 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { opts.ConstLabels, ) return &CounterVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - result := &counter{value: value{ - desc: desc, - valType: CounterValue, - labelPairs: makeLabelPairs(desc, lvs), - }} + metricVec: newMetricVec(desc, func(lvs ...string) Metric { + if len(lvs) != len(desc.variableLabels) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) + } + result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. return result }), } } -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Counter and not a -// Metric so that no type conversion is required. -func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) +// GetMetricWithLabelValues returns the Counter for the given slice of label +// values (same order as the VariableLabels in Desc). If that combination of +// label values is accessed for the first time, a new Counter is created. +// +// It is possible to call this method without using the returned Counter to only +// create the new Counter but leave it at its starting value 0. See also the +// SummaryVec example. +// +// Keeping the Counter for later use is possible (and should be considered if +// performance is critical), but keep in mind that Reset, DeleteLabelValues and +// Delete can be used to delete the Counter from the CounterVec. In that case, +// the Counter will still exist, but it will not be exported anymore, even if a +// Counter with the same label values is created later. +// +// An error is returned if the number of label values is not the same as the +// number of VariableLabels in Desc (minus any curried labels). +// +// Note that for more than one label value, this method is prone to mistakes +// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as +// an alternative to avoid that type of mistake. For higher label numbers, the +// latter has a much more readable (albeit more verbose) syntax, but it comes +// with a performance overhead (for creating and processing the Labels map). +// See also the GaugeVec example. +func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) { + metric, err := v.metricVec.getMetricWithLabelValues(lvs...) if metric != nil { return metric.(Counter), err } return nil, err } -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Counter and not a Metric so that no -// type conversion is required. -func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) { - metric, err := m.MetricVec.GetMetricWith(labels) +// GetMetricWith returns the Counter for the given Labels map (the label names +// must match those of the VariableLabels in Desc). If that label map is +// accessed for the first time, a new Counter is created. Implications of +// creating a Counter without using it and keeping the Counter for later use are +// the same as for GetMetricWithLabelValues. +// +// An error is returned if the number and names of the Labels are inconsistent +// with those of the VariableLabels in Desc (minus any curried labels). +// +// This method is used for the same purpose as +// GetMetricWithLabelValues(...string). See there for pros and cons of the two +// methods. +func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) { + metric, err := v.metricVec.getMetricWith(labels) if metric != nil { return metric.(Counter), err } @@ -123,18 +197,57 @@ func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) { } // WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like +// GetMetricWithLabelValues would have returned an error. Not returning an +// error allows shortcuts like // myVec.WithLabelValues("404", "GET").Add(42) -func (m *CounterVec) WithLabelValues(lvs ...string) Counter { - return m.MetricVec.WithLabelValues(lvs...).(Counter) +func (v *CounterVec) WithLabelValues(lvs ...string) Counter { + c, err := v.GetMetricWithLabelValues(lvs...) + if err != nil { + panic(err) + } + return c } // With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *CounterVec) With(labels Labels) Counter { - return m.MetricVec.With(labels).(Counter) +// returned an error. Not returning an error allows shortcuts like +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42) +func (v *CounterVec) With(labels Labels) Counter { + c, err := v.GetMetricWith(labels) + if err != nil { + panic(err) + } + return c +} + +// CurryWith returns a vector curried with the provided labels, i.e. the +// returned vector has those labels pre-set for all labeled operations performed +// on it. The cardinality of the curried vector is reduced accordingly. The +// order of the remaining labels stays the same (just with the curried labels +// taken out of the sequence – which is relevant for the +// (GetMetric)WithLabelValues methods). It is possible to curry a curried +// vector, but only with labels not yet used for currying before. +// +// The metrics contained in the CounterVec are shared between the curried and +// uncurried vectors. They are just accessed differently. Curried and uncurried +// vectors behave identically in terms of collection. Only one must be +// registered with a given registry (usually the uncurried version). The Reset +// method deletes all metrics, even if called on a curried vector. +func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) { + vec, err := v.curryWith(labels) + if vec != nil { + return &CounterVec{vec}, err + } + return nil, err +} + +// MustCurryWith works as CurryWith but panics where CurryWith would have +// returned an error. +func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec { + vec, err := v.CurryWith(labels) + if err != nil { + panic(err) + } + return vec } // CounterFunc is a Counter whose value is determined at collect time by calling a diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 1835b16f65..1d034f871c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -25,19 +25,6 @@ import ( dto "github.com/prometheus/client_model/go" ) -// reservedLabelPrefix is a prefix which is not legal in user-supplied -// label names. -const reservedLabelPrefix = "__" - -// Labels represents a collection of label name -> value mappings. This type is -// commonly used with the With(Labels) and GetMetricWith(Labels) methods of -// metric vector Collectors, e.g.: -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -// -// The other use-case is the specification of constant label pairs in Opts or to -// create a Desc. -type Labels map[string]string - // Desc is the descriptor used by every Prometheus Metric. It is essentially // the immutable meta-data of a Metric. The normal Metric implementations // included in this package manage their Desc under the hood. Users only have to @@ -80,24 +67,19 @@ type Desc struct { // NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc // and will be reported on registration time. variableLabels and constLabels can -// be nil if no such labels should be set. fqName and help must not be empty. +// be nil if no such labels should be set. fqName must not be empty. // // variableLabels only contain the label names. Their label values are variable // and therefore not part of the Desc. (They are managed within the Metric.) // // For constLabels, the label values are constant. Therefore, they are fully -// specified in the Desc. See the Opts documentation for the implications of -// constant labels. +// specified in the Desc. See the Collector example for a usage pattern. func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { d := &Desc{ fqName: fqName, help: help, variableLabels: variableLabels, } - if help == "" { - d.err = errors.New("empty help string") - return d - } if !model.IsValidMetricName(model.LabelValue(fqName)) { d.err = fmt.Errorf("%q is not a valid metric name", fqName) return d @@ -111,7 +93,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // First add only the const label names and sort them... for labelName := range constLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, labelName) @@ -122,12 +104,18 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * for _, labelName := range labelNames { labelValues = append(labelValues, constLabels[labelName]) } + // Validate the const label values. They can't have a wrong cardinality, so + // use in len(labelValues) as expectedNumberOfValues. + if err := validateLabelValues(labelValues, len(labelValues)); err != nil { + d.err = err + return d + } // Now add the variable label names, but prefix them with something that // cannot be in a regular label name. That prevents matching the label // dimension with a different mix between preset and variable labels. for _, labelName := range variableLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, "$"+labelName) @@ -137,6 +125,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * d.err = errors.New("duplicate label names") return d } + vh := hashNew() for _, val := range labelValues { vh = hashAdd(vh, val) @@ -163,7 +152,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * Value: proto.String(v), }) } - sort.Sort(LabelPairSorter(d.constLabelPairs)) + sort.Sort(labelPairSorter(d.constLabelPairs)) return d } @@ -193,8 +182,3 @@ func (d *Desc) String() string { d.variableLabels, ) } - -func checkLabelName(l string) bool { - return model.LabelName(l).IsValid() && - !strings.HasPrefix(l, reservedLabelPrefix) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index 278969dc7c..5d9525defc 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -11,10 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package prometheus provides metrics primitives to instrument code for -// monitoring. It also offers a registry for metrics. Sub-packages allow to -// expose the registered metrics via HTTP (package promhttp) or push them to a -// Pushgateway (package push). +// Package prometheus is the core instrumentation package. It provides metrics +// primitives to instrument code for monitoring. It also offers a registry for +// metrics. Sub-packages allow to expose the registered metrics via HTTP +// (package promhttp) or push them to a Pushgateway (package push). There is +// also a sub-package promauto, which provides metrics constructors with +// automatic registration. // // All exported functions and methods are safe to be used concurrently unless // specified otherwise. @@ -60,7 +62,7 @@ // // The Handler function provides a default handler to expose metrics // // via an HTTP server. "/metrics" is the usual endpoint for that. // http.Handle("/metrics", promhttp.Handler()) -// log.Fatal(http.ListenAndServe(":8080", nil)) +// log.Fatal(http.ListenAndServe(":8080", nil)) // } // // @@ -72,7 +74,10 @@ // The number of exported identifiers in this package might appear a bit // overwhelming. However, in addition to the basic plumbing shown in the example // above, you only need to understand the different metric types and their -// vector versions for basic usage. +// vector versions for basic usage. Furthermore, if you are not concerned with +// fine-grained control of when and how to register metrics with the registry, +// have a look at the promauto package, which will effectively allow you to +// ignore registration altogether in simple cases. // // Above, you have already touched the Counter and the Gauge. There are two more // advanced metric types: the Summary and Histogram. A more thorough description @@ -116,7 +121,17 @@ // NewConstSummary (and their respective Must… versions). That will happen in // the Collect method. The Describe method has to return separate Desc // instances, representative of the “throw-away” metrics to be created later. -// NewDesc comes in handy to create those Desc instances. +// NewDesc comes in handy to create those Desc instances. Alternatively, you +// could return no Desc at all, which will marke the Collector “unchecked”. No +// checks are porformed at registration time, but metric consistency will still +// be ensured at scrape time, i.e. any inconsistencies will lead to scrape +// errors. Thus, with unchecked Collectors, the responsibility to not collect +// metrics that lead to inconsistencies in the total scrape result lies with the +// implementer of the Collector. While this is not a desirable state, it is +// sometimes necessary. The typical use case is a situatios where the exact +// metrics to be returned by a Collector cannot be predicted at registration +// time, but the implementer has sufficient knowledge of the whole system to +// guarantee metric consistency. // // The Collector example illustrates the use case. You can also look at the // source code of the processCollector (mirroring process metrics), the @@ -145,7 +160,7 @@ // registry. // // So far, everything we did operated on the so-called default registry, as it -// can be found in the global DefaultRegistry variable. With NewRegistry, you +// can be found in the global DefaultRegisterer variable. With NewRegistry, you // can create a custom registry, or you can even implement the Registerer or // Gatherer interfaces yourself. The methods Register and Unregister work in the // same way on a custom registry as the global functions Register and Unregister @@ -153,11 +168,11 @@ // // There are a number of uses for custom registries: You can use registries with // special properties, see NewPedanticRegistry. You can avoid global state, as -// it is imposed by the DefaultRegistry. You can use multiple registries at the -// same time to expose different metrics in different ways. You can use separate -// registries for testing purposes. +// it is imposed by the DefaultRegisterer. You can use multiple registries at +// the same time to expose different metrics in different ways. You can use +// separate registries for testing purposes. // -// Also note that the DefaultRegistry comes registered with a Collector for Go +// Also note that the DefaultRegisterer comes registered with a Collector for Go // runtime metrics (via NewGoCollector) and a Collector for process metrics (via // NewProcessCollector). With a custom registry, you are in control and decide // yourself about the Collectors to register. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/fnv.go b/vendor/github.com/prometheus/client_golang/prometheus/fnv.go index e3b67df8ac..3d383a735c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/fnv.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/fnv.go @@ -1,3 +1,16 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package prometheus // Inline and byte-free variant of hash/fnv's fnv64a. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index 9ab5a3d621..71d406bd92 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -13,6 +13,14 @@ package prometheus +import ( + "math" + "sync/atomic" + "time" + + dto "github.com/prometheus/client_model/go" +) + // Gauge is a Metric that represents a single numerical value that can // arbitrarily go up and down. // @@ -48,13 +56,74 @@ type Gauge interface { type GaugeOpts Opts // NewGauge creates a new Gauge based on the provided GaugeOpts. +// +// The returned implementation is optimized for a fast Set method. If you have a +// choice for managing the value of a Gauge via Set vs. Inc/Dec/Add/Sub, pick +// the former. For example, the Inc method of the returned Gauge is slower than +// the Inc method of a Counter returned by NewCounter. This matches the typical +// scenarios for Gauges and Counters, where the former tends to be Set-heavy and +// the latter Inc-heavy. func NewGauge(opts GaugeOpts) Gauge { - return newValue(NewDesc( + desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, nil, opts.ConstLabels, - ), GaugeValue, 0) + ) + result := &gauge{desc: desc, labelPairs: desc.constLabelPairs} + result.init(result) // Init self-collection. + return result +} + +type gauge struct { + // valBits contains the bits of the represented float64 value. It has + // to go first in the struct to guarantee alignment for atomic + // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG + valBits uint64 + + selfCollector + + desc *Desc + labelPairs []*dto.LabelPair +} + +func (g *gauge) Desc() *Desc { + return g.desc +} + +func (g *gauge) Set(val float64) { + atomic.StoreUint64(&g.valBits, math.Float64bits(val)) +} + +func (g *gauge) SetToCurrentTime() { + g.Set(float64(time.Now().UnixNano()) / 1e9) +} + +func (g *gauge) Inc() { + g.Add(1) +} + +func (g *gauge) Dec() { + g.Add(-1) +} + +func (g *gauge) Add(val float64) { + for { + oldBits := atomic.LoadUint64(&g.valBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + val) + if atomic.CompareAndSwapUint64(&g.valBits, oldBits, newBits) { + return + } + } +} + +func (g *gauge) Sub(val float64) { + g.Add(val * -1) +} + +func (g *gauge) Write(out *dto.Metric) error { + val := math.Float64frombits(atomic.LoadUint64(&g.valBits)) + return populateMetric(GaugeValue, val, g.labelPairs, out) } // GaugeVec is a Collector that bundles a set of Gauges that all share the same @@ -63,12 +132,11 @@ func NewGauge(opts GaugeOpts) Gauge { // (e.g. number of operations queued, partitioned by user and operation // type). Create instances with NewGaugeVec. type GaugeVec struct { - *MetricVec + *metricVec } // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and -// partitioned by the given label names. At least one label name must be -// provided. +// partitioned by the given label names. func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), @@ -77,28 +145,62 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { opts.ConstLabels, ) return &GaugeVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newValue(desc, GaugeValue, 0, lvs...) + metricVec: newMetricVec(desc, func(lvs ...string) Metric { + if len(lvs) != len(desc.variableLabels) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) + } + result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} + result.init(result) // Init self-collection. + return result }), } } -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Gauge and not a -// Metric so that no type conversion is required. -func (m *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) +// GetMetricWithLabelValues returns the Gauge for the given slice of label +// values (same order as the VariableLabels in Desc). If that combination of +// label values is accessed for the first time, a new Gauge is created. +// +// It is possible to call this method without using the returned Gauge to only +// create the new Gauge but leave it at its starting value 0. See also the +// SummaryVec example. +// +// Keeping the Gauge for later use is possible (and should be considered if +// performance is critical), but keep in mind that Reset, DeleteLabelValues and +// Delete can be used to delete the Gauge from the GaugeVec. In that case, the +// Gauge will still exist, but it will not be exported anymore, even if a +// Gauge with the same label values is created later. See also the CounterVec +// example. +// +// An error is returned if the number of label values is not the same as the +// number of VariableLabels in Desc (minus any curried labels). +// +// Note that for more than one label value, this method is prone to mistakes +// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as +// an alternative to avoid that type of mistake. For higher label numbers, the +// latter has a much more readable (albeit more verbose) syntax, but it comes +// with a performance overhead (for creating and processing the Labels map). +func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) { + metric, err := v.metricVec.getMetricWithLabelValues(lvs...) if metric != nil { return metric.(Gauge), err } return nil, err } -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Gauge and not a Metric so that no -// type conversion is required. -func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { - metric, err := m.MetricVec.GetMetricWith(labels) +// GetMetricWith returns the Gauge for the given Labels map (the label names +// must match those of the VariableLabels in Desc). If that label map is +// accessed for the first time, a new Gauge is created. Implications of +// creating a Gauge without using it and keeping the Gauge for later use are +// the same as for GetMetricWithLabelValues. +// +// An error is returned if the number and names of the Labels are inconsistent +// with those of the VariableLabels in Desc (minus any curried labels). +// +// This method is used for the same purpose as +// GetMetricWithLabelValues(...string). See there for pros and cons of the two +// methods. +func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { + metric, err := v.metricVec.getMetricWith(labels) if metric != nil { return metric.(Gauge), err } @@ -106,18 +208,57 @@ func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { } // WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like +// GetMetricWithLabelValues would have returned an error. Not returning an +// error allows shortcuts like // myVec.WithLabelValues("404", "GET").Add(42) -func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge { - return m.MetricVec.WithLabelValues(lvs...).(Gauge) +func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge { + g, err := v.GetMetricWithLabelValues(lvs...) + if err != nil { + panic(err) + } + return g } // With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *GaugeVec) With(labels Labels) Gauge { - return m.MetricVec.With(labels).(Gauge) +// returned an error. Not returning an error allows shortcuts like +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42) +func (v *GaugeVec) With(labels Labels) Gauge { + g, err := v.GetMetricWith(labels) + if err != nil { + panic(err) + } + return g +} + +// CurryWith returns a vector curried with the provided labels, i.e. the +// returned vector has those labels pre-set for all labeled operations performed +// on it. The cardinality of the curried vector is reduced accordingly. The +// order of the remaining labels stays the same (just with the curried labels +// taken out of the sequence – which is relevant for the +// (GetMetric)WithLabelValues methods). It is possible to curry a curried +// vector, but only with labels not yet used for currying before. +// +// The metrics contained in the GaugeVec are shared between the curried and +// uncurried vectors. They are just accessed differently. Curried and uncurried +// vectors behave identically in terms of collection. Only one must be +// registered with a given registry (usually the uncurried version). The Reset +// method deletes all metrics, even if called on a curried vector. +func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) { + vec, err := v.curryWith(labels) + if vec != nil { + return &GaugeVec{vec}, err + } + return nil, err +} + +// MustCurryWith works as CurryWith but panics where CurryWith would have +// returned an error. +func (v *GaugeVec) MustCurryWith(labels Labels) *GaugeVec { + vec, err := v.CurryWith(labels) + if err != nil { + panic(err) + } + return vec } // GaugeFunc is a Gauge whose value is determined at collect time by calling a diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go index f96764559b..ba3b9333ed 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go @@ -1,3 +1,16 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package prometheus import ( @@ -11,13 +24,18 @@ type goCollector struct { goroutinesDesc *Desc threadsDesc *Desc gcDesc *Desc + goInfoDesc *Desc // metrics to describe and collect metrics memStatsMetrics } -// NewGoCollector returns a collector which exports metrics about the current -// go process. +// NewGoCollector returns a collector which exports metrics about the current Go +// process. This includes memory stats. To collect those, runtime.ReadMemStats +// is called. This causes a stop-the-world, which is very short with Go1.9+ +// (~25µs). However, with older Go versions, the stop-the-world duration depends +// on the heap size and can be quite significant (~1.7 ms/GiB as per +// https://go-review.googlesource.com/c/go/+/34937). func NewGoCollector() Collector { return &goCollector{ goroutinesDesc: NewDesc( @@ -26,12 +44,16 @@ func NewGoCollector() Collector { nil, nil), threadsDesc: NewDesc( "go_threads", - "Number of OS threads created", + "Number of OS threads created.", nil, nil), gcDesc: NewDesc( "go_gc_duration_seconds", "A summary of the GC invocation durations.", nil, nil), + goInfoDesc: NewDesc( + "go_info", + "Information about the Go environment.", + nil, Labels{"version": runtime.Version()}), metrics: memStatsMetrics{ { desc: NewDesc( @@ -239,6 +261,7 @@ func (c *goCollector) Describe(ch chan<- *Desc) { ch <- c.goroutinesDesc ch <- c.threadsDesc ch <- c.gcDesc + ch <- c.goInfoDesc for _, i := range c.metrics { ch <- i.desc } @@ -259,7 +282,9 @@ func (c *goCollector) Collect(ch chan<- Metric) { quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds() } quantiles[0.0] = stats.PauseQuantiles[0].Seconds() - ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles) + ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles) + + ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) ms := &runtime.MemStats{} runtime.ReadMemStats(ms) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index f46eff6acf..f88da707bc 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -16,7 +16,9 @@ package prometheus import ( "fmt" "math" + "runtime" "sort" + "sync" "sync/atomic" "github.com/golang/protobuf/proto" @@ -108,8 +110,9 @@ func ExponentialBuckets(start, factor float64, count int) []float64 { } // HistogramOpts bundles the options for creating a Histogram metric. It is -// mandatory to set Name and Help to a non-empty string. All other fields are -// optional and can safely be left at their zero value. +// mandatory to set Name to a non-empty string. All other fields are optional +// and can safely be left at their zero value, although it is strongly +// encouraged to set a Help string. type HistogramOpts struct { // Namespace, Subsystem, and Name are components of the fully-qualified // name of the Histogram (created by joining these components with @@ -120,29 +123,22 @@ type HistogramOpts struct { Subsystem string Name string - // Help provides information about this Histogram. Mandatory! + // Help provides information about this Histogram. // // Metrics with the same fully-qualified name must have the same Help // string. Help string - // ConstLabels are used to attach fixed labels to this - // Histogram. Histograms with the same fully-qualified name must have the - // same label names in their ConstLabels. + // ConstLabels are used to attach fixed labels to this metric. Metrics + // with the same fully-qualified name must have the same label names in + // their ConstLabels. // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a - // HistogramVec. ConstLabels serve only special purposes. One is for the - // special case where the value of a label does not change during the - // lifetime of a process, e.g. if the revision of the running binary is - // put into a label. Another, more advanced purpose is if more than one - // Collector needs to collect Histograms with the same fully-qualified - // name. In that case, those Summaries must differ in the values of - // their ConstLabels. See the Collector examples. - // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). + // ConstLabels are only used rarely. In particular, do not use them to + // attach the same labels to all your metrics. Those use cases are + // better covered by target labels set by the scraping Prometheus + // server, or by one specific metric (e.g. a build_info or a + // machine_role metric). See also + // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels ConstLabels Labels // Buckets defines the buckets into which observations are counted. Each @@ -169,7 +165,7 @@ func NewHistogram(opts HistogramOpts) Histogram { func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -191,6 +187,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr desc: desc, upperBounds: opts.Buckets, labelPairs: makeLabelPairs(desc, labelValues), + counts: [2]*histogramCounts{&histogramCounts{}, &histogramCounts{}}, } for i, upperBound := range h.upperBounds { if i < len(h.upperBounds)-1 { @@ -207,28 +204,53 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } } } - // Finally we know the final length of h.upperBounds and can make counts. - h.counts = make([]uint64, len(h.upperBounds)) + // Finally we know the final length of h.upperBounds and can make counts + // for both states: + h.counts[0].buckets = make([]uint64, len(h.upperBounds)) + h.counts[1].buckets = make([]uint64, len(h.upperBounds)) h.init(h) // Init self-collection. return h } -type histogram struct { +type histogramCounts struct { // sumBits contains the bits of the float64 representing the sum of all // observations. sumBits and count have to go first in the struct to // guarantee alignment for atomic operations. // http://golang.org/pkg/sync/atomic/#pkg-note-BUG sumBits uint64 count uint64 + buckets []uint64 +} - selfCollector - // Note that there is no mutex required. +type histogram struct { + // countAndHotIdx is a complicated one. For lock-free yet atomic + // observations, we need to save the total count of observations again, + // combined with the index of the currently-hot counts struct, so that + // we can perform the operation on both values atomically. The least + // significant bit defines the hot counts struct. The remaining 63 bits + // represent the total count of observations. This happens under the + // assumption that the 63bit count will never overflow. Rationale: An + // observations takes about 30ns. Let's assume it could happen in + // 10ns. Overflowing the counter will then take at least (2^63)*10ns, + // which is about 3000 years. + // + // This has to be first in the struct for 64bit alignment. See + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + countAndHotIdx uint64 - desc *Desc + selfCollector + desc *Desc + writeMtx sync.Mutex // Only used in the Write method. upperBounds []float64 - counts []uint64 + + // Two counts, one is "hot" for lock-free observations, the other is + // "cold" for writing out a dto.Metric. It has to be an array of + // pointers to guarantee 64bit alignment of the histogramCounts, see + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG. + counts [2]*histogramCounts + hotIdx int // Index of currently-hot counts. Only used within Write. labelPairs []*dto.LabelPair } @@ -248,36 +270,113 @@ func (h *histogram) Observe(v float64) { // 100 buckets: 78.1 ns/op linear - binary 54.9 ns/op // 300 buckets: 154 ns/op linear - binary 61.6 ns/op i := sort.SearchFloat64s(h.upperBounds, v) - if i < len(h.counts) { - atomic.AddUint64(&h.counts[i], 1) + + // We increment h.countAndHotIdx by 2 so that the counter in the upper + // 63 bits gets incremented by 1. At the same time, we get the new value + // back, which we can use to find the currently-hot counts. + n := atomic.AddUint64(&h.countAndHotIdx, 2) + hotCounts := h.counts[n%2] + + if i < len(h.upperBounds) { + atomic.AddUint64(&hotCounts.buckets[i], 1) } - atomic.AddUint64(&h.count, 1) for { - oldBits := atomic.LoadUint64(&h.sumBits) + oldBits := atomic.LoadUint64(&hotCounts.sumBits) newBits := math.Float64bits(math.Float64frombits(oldBits) + v) - if atomic.CompareAndSwapUint64(&h.sumBits, oldBits, newBits) { + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { break } } + // Increment count last as we take it as a signal that the observation + // is complete. + atomic.AddUint64(&hotCounts.count, 1) } func (h *histogram) Write(out *dto.Metric) error { - his := &dto.Histogram{} - buckets := make([]*dto.Bucket, len(h.upperBounds)) + var ( + his = &dto.Histogram{} + buckets = make([]*dto.Bucket, len(h.upperBounds)) + hotCounts, coldCounts *histogramCounts + count uint64 + ) + + // For simplicity, we mutex the rest of this method. It is not in the + // hot path, i.e. Observe is called much more often than Write. The + // complication of making Write lock-free isn't worth it. + h.writeMtx.Lock() + defer h.writeMtx.Unlock() - his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&h.sumBits))) - his.SampleCount = proto.Uint64(atomic.LoadUint64(&h.count)) - var count uint64 + // This is a bit arcane, which is why the following spells out this if + // clause in English: + // + // If the currently-hot counts struct is #0, we atomically increment + // h.countAndHotIdx by 1 so that from now on Observe will use the counts + // struct #1. Furthermore, the atomic increment gives us the new value, + // which, in its most significant 63 bits, tells us the count of + // observations done so far up to and including currently ongoing + // observations still using the counts struct just changed from hot to + // cold. To have a normal uint64 for the count, we bitshift by 1 and + // save the result in count. We also set h.hotIdx to 1 for the next + // Write call, and we will refer to counts #1 as hotCounts and to counts + // #0 as coldCounts. + // + // If the currently-hot counts struct is #1, we do the corresponding + // things the other way round. We have to _decrement_ h.countAndHotIdx + // (which is a bit arcane in itself, as we have to express -1 with an + // unsigned int...). + if h.hotIdx == 0 { + count = atomic.AddUint64(&h.countAndHotIdx, 1) >> 1 + h.hotIdx = 1 + hotCounts = h.counts[1] + coldCounts = h.counts[0] + } else { + count = atomic.AddUint64(&h.countAndHotIdx, ^uint64(0)) >> 1 // Decrement. + h.hotIdx = 0 + hotCounts = h.counts[0] + coldCounts = h.counts[1] + } + + // Now we have to wait for the now-declared-cold counts to actually cool + // down, i.e. wait for all observations still using it to finish. That's + // the case once the count in the cold counts struct is the same as the + // one atomically retrieved from the upper 63bits of h.countAndHotIdx. + for { + if count == atomic.LoadUint64(&coldCounts.count) { + break + } + runtime.Gosched() // Let observations get work done. + } + + his.SampleCount = proto.Uint64(count) + his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))) + var cumCount uint64 for i, upperBound := range h.upperBounds { - count += atomic.LoadUint64(&h.counts[i]) + cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) buckets[i] = &dto.Bucket{ - CumulativeCount: proto.Uint64(count), + CumulativeCount: proto.Uint64(cumCount), UpperBound: proto.Float64(upperBound), } } + his.Bucket = buckets out.Histogram = his out.Label = h.labelPairs + + // Finally add all the cold counts to the new hot counts and reset the cold counts. + atomic.AddUint64(&hotCounts.count, count) + atomic.StoreUint64(&coldCounts.count, 0) + for { + oldBits := atomic.LoadUint64(&hotCounts.sumBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + his.GetSampleSum()) + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { + atomic.StoreUint64(&coldCounts.sumBits, 0) + break + } + } + for i := range h.upperBounds { + atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i])) + atomic.StoreUint64(&coldCounts.buckets[i], 0) + } return nil } @@ -287,12 +386,11 @@ func (h *histogram) Write(out *dto.Metric) error { // (e.g. HTTP request latencies, partitioned by status code and method). Create // instances with NewHistogramVec. type HistogramVec struct { - *MetricVec + *metricVec } // NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and -// partitioned by the given label names. At least one label name must be -// provided. +// partitioned by the given label names. func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), @@ -301,28 +399,58 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec { opts.ConstLabels, ) return &HistogramVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { + metricVec: newMetricVec(desc, func(lvs ...string) Metric { return newHistogram(desc, opts, lvs...) }), } } -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns an Observer and not a -// Metric so that no type conversion to an Observer is required. -func (m *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) +// GetMetricWithLabelValues returns the Histogram for the given slice of label +// values (same order as the VariableLabels in Desc). If that combination of +// label values is accessed for the first time, a new Histogram is created. +// +// It is possible to call this method without using the returned Histogram to only +// create the new Histogram but leave it at its starting value, a Histogram without +// any observations. +// +// Keeping the Histogram for later use is possible (and should be considered if +// performance is critical), but keep in mind that Reset, DeleteLabelValues and +// Delete can be used to delete the Histogram from the HistogramVec. In that case, the +// Histogram will still exist, but it will not be exported anymore, even if a +// Histogram with the same label values is created later. See also the CounterVec +// example. +// +// An error is returned if the number of label values is not the same as the +// number of VariableLabels in Desc (minus any curried labels). +// +// Note that for more than one label value, this method is prone to mistakes +// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as +// an alternative to avoid that type of mistake. For higher label numbers, the +// latter has a much more readable (albeit more verbose) syntax, but it comes +// with a performance overhead (for creating and processing the Labels map). +// See also the GaugeVec example. +func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { + metric, err := v.metricVec.getMetricWithLabelValues(lvs...) if metric != nil { return metric.(Observer), err } return nil, err } -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns an Observer and not a Metric so that no -// type conversion to an Observer is required. -func (m *HistogramVec) GetMetricWith(labels Labels) (Observer, error) { - metric, err := m.MetricVec.GetMetricWith(labels) +// GetMetricWith returns the Histogram for the given Labels map (the label names +// must match those of the VariableLabels in Desc). If that label map is +// accessed for the first time, a new Histogram is created. Implications of +// creating a Histogram without using it and keeping the Histogram for later use +// are the same as for GetMetricWithLabelValues. +// +// An error is returned if the number and names of the Labels are inconsistent +// with those of the VariableLabels in Desc (minus any curried labels). +// +// This method is used for the same purpose as +// GetMetricWithLabelValues(...string). See there for pros and cons of the two +// methods. +func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) { + metric, err := v.metricVec.getMetricWith(labels) if metric != nil { return metric.(Observer), err } @@ -330,18 +458,57 @@ func (m *HistogramVec) GetMetricWith(labels Labels) (Observer, error) { } // WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like +// GetMetricWithLabelValues would have returned an error. Not returning an +// error allows shortcuts like // myVec.WithLabelValues("404", "GET").Observe(42.21) -func (m *HistogramVec) WithLabelValues(lvs ...string) Observer { - return m.MetricVec.WithLabelValues(lvs...).(Observer) +func (v *HistogramVec) WithLabelValues(lvs ...string) Observer { + h, err := v.GetMetricWithLabelValues(lvs...) + if err != nil { + panic(err) + } + return h +} + +// With works as GetMetricWith but panics where GetMetricWithLabels would have +// returned an error. Not returning an error allows shortcuts like +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) +func (v *HistogramVec) With(labels Labels) Observer { + h, err := v.GetMetricWith(labels) + if err != nil { + panic(err) + } + return h +} + +// CurryWith returns a vector curried with the provided labels, i.e. the +// returned vector has those labels pre-set for all labeled operations performed +// on it. The cardinality of the curried vector is reduced accordingly. The +// order of the remaining labels stays the same (just with the curried labels +// taken out of the sequence – which is relevant for the +// (GetMetric)WithLabelValues methods). It is possible to curry a curried +// vector, but only with labels not yet used for currying before. +// +// The metrics contained in the HistogramVec are shared between the curried and +// uncurried vectors. They are just accessed differently. Curried and uncurried +// vectors behave identically in terms of collection. Only one must be +// registered with a given registry (usually the uncurried version). The Reset +// method deletes all metrics, even if called on a curried vector. +func (v *HistogramVec) CurryWith(labels Labels) (ObserverVec, error) { + vec, err := v.curryWith(labels) + if vec != nil { + return &HistogramVec{vec}, err + } + return nil, err } -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21) -func (m *HistogramVec) With(labels Labels) Observer { - return m.MetricVec.With(labels).(Observer) +// MustCurryWith works as CurryWith but panics where CurryWith would have +// returned an error. +func (v *HistogramVec) MustCurryWith(labels Labels) ObserverVec { + vec, err := v.CurryWith(labels) + if err != nil { + panic(err) + } + return vec } type constHistogram struct { @@ -393,7 +560,7 @@ func (h *constHistogram) Write(out *dto.Metric) error { // bucket. // // NewConstHistogram returns an error if the length of labelValues is not -// consistent with the variable labels in Desc. +// consistent with the variable labels in Desc or if Desc is invalid. func NewConstHistogram( desc *Desc, count uint64, @@ -401,8 +568,11 @@ func NewConstHistogram( buckets map[float64]uint64, labelValues ...string, ) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality + if desc.err != nil { + return nil, desc.err + } + if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + return nil, err } return &constHistogram{ desc: desc, diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http.go b/vendor/github.com/prometheus/client_golang/prometheus/http.go index d485ce0b8e..9f0875bfc8 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/http.go @@ -15,9 +15,7 @@ package prometheus import ( "bufio" - "bytes" "compress/gzip" - "fmt" "io" "net" "net/http" @@ -41,19 +39,10 @@ const ( acceptEncodingHeader = "Accept-Encoding" ) -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, } // Handler returns an HTTP handler for the DefaultGatherer. It is @@ -61,69 +50,50 @@ func giveBuf(buf *bytes.Buffer) { // name). // // Deprecated: Please note the issues described in the doc comment of -// InstrumentHandler. You might want to consider using promhttp.Handler instead -// (which is not instrumented, but can be instrumented with the tooling provided -// in package promhttp). +// InstrumentHandler. You might want to consider using promhttp.Handler instead. func Handler() http.Handler { return InstrumentHandler("prometheus", UninstrumentedHandler()) } // UninstrumentedHandler returns an HTTP handler for the DefaultGatherer. // -// Deprecated: Use promhttp.Handler instead. See there for further documentation. +// Deprecated: Use promhttp.HandlerFor(DefaultGatherer, promhttp.HandlerOpts{}) +// instead. See there for further documentation. func UninstrumentedHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + return http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { mfs, err := DefaultGatherer.Gather() if err != nil { - http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf) - enc := expfmt.NewEncoder(writer, contentType) - var lastErr error + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + for _, mf := range mfs { if err := enc.Encode(mf); err != nil { - lastErr = err - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - w.Write(buf.Bytes()) }) } -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) { - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") - for _, part := range parts { - part := strings.TrimSpace(part) - if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" - } - } - return writer, "" -} - var instLabels = []string{"method", "code"} type nower interface { @@ -140,16 +110,6 @@ var now nower = nowFunc(func() time.Time { return time.Now() }) -func nowSeries(t ...time.Time) nower { - return nowFunc(func() time.Time { - defer func() { - t = t[1:] - }() - - return t[0] - }) -} - // InstrumentHandler wraps the given HTTP handler for instrumentation. It // registers four metric collectors (if not already done) and reports HTTP // metrics to the (newly or already) registered collectors: http_requests_total @@ -160,21 +120,14 @@ func nowSeries(t ...time.Time) nower { // (label name "method") and HTTP status code (label name "code"). // // Deprecated: InstrumentHandler has several issues. Use the tooling provided in -// package promhttp instead. The issues are the following: -// -// - It uses Summaries rather than Histograms. Summaries are not useful if -// aggregation across multiple instances is required. -// -// - It uses microseconds as unit, which is deprecated and should be replaced by -// seconds. -// -// - The size of the request is calculated in a separate goroutine. Since this -// calculator requires access to the request header, it creates a race with -// any writes to the header performed during request handling. -// httputil.ReverseProxy is a prominent example for a handler -// performing such writes. -// -// - It has additional issues with HTTP/2, cf. +// package promhttp instead. The issues are the following: (1) It uses Summaries +// rather than Histograms. Summaries are not useful if aggregation across +// multiple instances is required. (2) It uses microseconds as unit, which is +// deprecated and should be replaced by seconds. (3) The size of the request is +// calculated in a separate goroutine. Since this calculator requires access to +// the request header, it creates a race with any writes to the header performed +// during request handling. httputil.ReverseProxy is a prominent example for a +// handler performing such writes. (4) It has additional issues with HTTP/2, cf. // https://github.com/prometheus/client_golang/issues/272. func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc { return InstrumentHandlerFunc(handlerName, handler.ServeHTTP) @@ -318,7 +271,7 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo } func computeApproximateRequestSize(r *http.Request) <-chan int { - // Get URL length in current go routine for avoiding a race condition. + // Get URL length in current goroutine for avoiding a race condition. // HandlerFunc that runs in parallel may modify the URL. s := 0 if r.URL != nil { @@ -353,10 +306,9 @@ func computeApproximateRequestSize(r *http.Request) <-chan int { type responseWriterDelegator struct { http.ResponseWriter - handler, method string - status int - written int64 - wroteHeader bool + status int + written int64 + wroteHeader bool } func (r *responseWriterDelegator) WriteHeader(code int) { @@ -522,3 +474,31 @@ func sanitizeCode(s int) string { return strconv.Itoa(s) } } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "gzip" || strings.HasPrefix(part, "gzip;") { + return true + } + } + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go new file mode 100644 index 0000000000..351c26e1ae --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go @@ -0,0 +1,85 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +import ( + "sort" + + dto "github.com/prometheus/client_model/go" +) + +// metricSorter is a sortable slice of *dto.Metric. +type metricSorter []*dto.Metric + +func (s metricSorter) Len() int { + return len(s) +} + +func (s metricSorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s metricSorter) Less(i, j int) bool { + if len(s[i].Label) != len(s[j].Label) { + // This should not happen. The metrics are + // inconsistent. However, we have to deal with the fact, as + // people might use custom collectors or metric family injection + // to create inconsistent metrics. So let's simply compare the + // number of labels in this case. That will still yield + // reproducible sorting. + return len(s[i].Label) < len(s[j].Label) + } + for n, lp := range s[i].Label { + vi := lp.GetValue() + vj := s[j].Label[n].GetValue() + if vi != vj { + return vi < vj + } + } + + // We should never arrive here. Multiple metrics with the same + // label set in the same scrape will lead to undefined ingestion + // behavior. However, as above, we have to provide stable sorting + // here, even for inconsistent metrics. So sort equal metrics + // by their timestamp, with missing timestamps (implying "now") + // coming last. + if s[i].TimestampMs == nil { + return false + } + if s[j].TimestampMs == nil { + return true + } + return s[i].GetTimestampMs() < s[j].GetTimestampMs() +} + +// NormalizeMetricFamilies returns a MetricFamily slice with empty +// MetricFamilies pruned and the remaining MetricFamilies sorted by name within +// the slice, with the contained Metrics sorted within each MetricFamily. +func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { + for _, mf := range metricFamiliesByName { + sort.Sort(metricSorter(mf.Metric)) + } + names := make([]string, 0, len(metricFamiliesByName)) + for name, mf := range metricFamiliesByName { + if len(mf.Metric) > 0 { + names = append(names, name) + } + } + sort.Strings(names) + result := make([]*dto.MetricFamily, 0, len(names)) + for _, name := range names { + result = append(result, metricFamiliesByName[name]) + } + return result +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go new file mode 100644 index 0000000000..2744443ac2 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go @@ -0,0 +1,87 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "errors" + "fmt" + "strings" + "unicode/utf8" + + "github.com/prometheus/common/model" +) + +// Labels represents a collection of label name -> value mappings. This type is +// commonly used with the With(Labels) and GetMetricWith(Labels) methods of +// metric vector Collectors, e.g.: +// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) +// +// The other use-case is the specification of constant label pairs in Opts or to +// create a Desc. +type Labels map[string]string + +// reservedLabelPrefix is a prefix which is not legal in user-supplied +// label names. +const reservedLabelPrefix = "__" + +var errInconsistentCardinality = errors.New("inconsistent label cardinality") + +func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { + return fmt.Errorf( + "%s: %q has %d variable labels named %q but %d values %q were provided", + errInconsistentCardinality, fqName, + len(labels), labels, + len(labelValues), labelValues, + ) +} + +func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { + if len(labels) != expectedNumberOfValues { + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(labels), labels, + ) + } + + for name, val := range labels { + if !utf8.ValidString(val) { + return fmt.Errorf("label %s: value %q is not valid UTF-8", name, val) + } + } + + return nil +} + +func validateLabelValues(vals []string, expectedNumberOfValues int) error { + if len(vals) != expectedNumberOfValues { + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(vals), vals, + ) + } + + for _, val := range vals { + if !utf8.ValidString(val) { + return fmt.Errorf("label value %q is not valid UTF-8", val) + } + } + + return nil +} + +func checkLabelName(l string) bool { + return model.LabelName(l).IsValid() && !strings.HasPrefix(l, reservedLabelPrefix) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go index d4063d98f4..55e6d86d59 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go @@ -15,6 +15,9 @@ package prometheus import ( "strings" + "time" + + "github.com/golang/protobuf/proto" dto "github.com/prometheus/client_model/go" ) @@ -43,9 +46,8 @@ type Metric interface { // While populating dto.Metric, it is the responsibility of the // implementation to ensure validity of the Metric protobuf (like valid // UTF-8 strings or syntactically valid metric and label names). It is - // recommended to sort labels lexicographically. (Implementers may find - // LabelPairSorter useful for that.) Callers of Write should still make - // sure of sorting if they depend on it. + // recommended to sort labels lexicographically. Callers of Write should + // still make sure of sorting if they depend on it. Write(*dto.Metric) error // TODO(beorn7): The original rationale of passing in a pre-allocated // dto.Metric protobuf to save allocations has disappeared. The @@ -57,8 +59,9 @@ type Metric interface { // implementation XXX has its own XXXOpts type, but in most cases, it is just be // an alias of this type (which might change when the requirement arises.) // -// It is mandatory to set Name and Help to a non-empty string. All other fields -// are optional and can safely be left at their zero value. +// It is mandatory to set Name to a non-empty string. All other fields are +// optional and can safely be left at their zero value, although it is strongly +// encouraged to set a Help string. type Opts struct { // Namespace, Subsystem, and Name are components of the fully-qualified // name of the Metric (created by joining these components with @@ -69,7 +72,7 @@ type Opts struct { Subsystem string Name string - // Help provides information about this metric. Mandatory! + // Help provides information about this metric. // // Metrics with the same fully-qualified name must have the same Help // string. @@ -79,20 +82,12 @@ type Opts struct { // with the same fully-qualified name must have the same label names in // their ConstLabels. // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a metric - // vector collector (like CounterVec, GaugeVec, UntypedVec). ConstLabels - // serve only special purposes. One is for the special case where the - // value of a label does not change during the lifetime of a process, - // e.g. if the revision of the running binary is put into a - // label. Another, more advanced purpose is if more than one Collector - // needs to collect Metrics with the same fully-qualified name. In that - // case, those Metrics must differ in the values of their - // ConstLabels. See the Collector examples. - // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). + // ConstLabels are only used rarely. In particular, do not use them to + // attach the same labels to all your metrics. Those use cases are + // better covered by target labels set by the scraping Prometheus + // server, or by one specific metric (e.g. a build_info or a + // machine_role metric). See also + // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels ConstLabels Labels } @@ -118,37 +113,22 @@ func BuildFQName(namespace, subsystem, name string) string { return name } -// LabelPairSorter implements sort.Interface. It is used to sort a slice of -// dto.LabelPair pointers. This is useful for implementing the Write method of -// custom metrics. -type LabelPairSorter []*dto.LabelPair +// labelPairSorter implements sort.Interface. It is used to sort a slice of +// dto.LabelPair pointers. +type labelPairSorter []*dto.LabelPair -func (s LabelPairSorter) Len() int { +func (s labelPairSorter) Len() int { return len(s) } -func (s LabelPairSorter) Swap(i, j int) { +func (s labelPairSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s LabelPairSorter) Less(i, j int) bool { +func (s labelPairSorter) Less(i, j int) bool { return s[i].GetName() < s[j].GetName() } -type hashSorter []uint64 - -func (s hashSorter) Len() int { - return len(s) -} - -func (s hashSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s hashSorter) Less(i, j int) bool { - return s[i] < s[j] -} - type invalidMetric struct { desc *Desc err error @@ -164,3 +144,31 @@ func NewInvalidMetric(desc *Desc, err error) Metric { func (m *invalidMetric) Desc() *Desc { return m.desc } func (m *invalidMetric) Write(*dto.Metric) error { return m.err } + +type timestampedMetric struct { + Metric + t time.Time +} + +func (m timestampedMetric) Write(pb *dto.Metric) error { + e := m.Metric.Write(pb) + pb.TimestampMs = proto.Int64(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000)) + return e +} + +// NewMetricWithTimestamp returns a new Metric wrapping the provided Metric in a +// way that it has an explicit timestamp set to the provided Time. This is only +// useful in rare cases as the timestamp of a Prometheus metric should usually +// be set by the Prometheus server during scraping. Exceptions include mirroring +// metrics with given timestamps from other metric +// sources. +// +// NewMetricWithTimestamp works best with MustNewConstMetric, +// MustNewConstHistogram, and MustNewConstSummary, see example. +// +// Currently, the exposition formats used by Prometheus are limited to +// millisecond resolution. Thus, the provided time will be rounded down to the +// next full millisecond value. +func NewMetricWithTimestamp(t time.Time, m Metric) Metric { + return timestampedMetric{Metric: m, t: t} +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/observer.go b/vendor/github.com/prometheus/client_golang/prometheus/observer.go index b0520e85e8..5806cd09e3 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/observer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/observer.go @@ -45,6 +45,8 @@ type ObserverVec interface { GetMetricWithLabelValues(lvs ...string) (Observer, error) With(Labels) Observer WithLabelValues(...string) Observer + CurryWith(Labels) (ObserverVec, error) + MustCurryWith(Labels) ObserverVec Collector } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go index 94b2553e14..55176d58ce 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go @@ -13,46 +13,74 @@ package prometheus -import "github.com/prometheus/procfs" +import ( + "errors" + "os" + + "github.com/prometheus/procfs" +) type processCollector struct { - pid int collectFn func(chan<- Metric) pidFn func() (int, error) + reportErrors bool cpuTotal *Desc openFDs, maxFDs *Desc - vsize, rss *Desc + vsize, maxVsize *Desc + rss *Desc startTime *Desc } -// NewProcessCollector returns a collector which exports the current state of -// process metrics including cpu, memory and file descriptor usage as well as -// the process start time for the given process id under the given namespace. -func NewProcessCollector(pid int, namespace string) Collector { - return NewProcessCollectorPIDFn( - func() (int, error) { return pid, nil }, - namespace, - ) +// ProcessCollectorOpts defines the behavior of a process metrics collector +// created with NewProcessCollector. +type ProcessCollectorOpts struct { + // PidFn returns the PID of the process the collector collects metrics + // for. It is called upon each collection. By default, the PID of the + // current process is used, as determined on construction time by + // calling os.Getpid(). + PidFn func() (int, error) + // If non-empty, each of the collected metrics is prefixed by the + // provided string and an underscore ("_"). + Namespace string + // If true, any error encountered during collection is reported as an + // invalid metric (see NewInvalidMetric). Otherwise, errors are ignored + // and the collected metrics will be incomplete. (Possibly, no metrics + // will be collected at all.) While that's usually not desired, it is + // appropriate for the common "mix-in" of process metrics, where process + // metrics are nice to have, but failing to collect them should not + // disrupt the collection of the remaining metrics. + ReportErrors bool } -// NewProcessCollectorPIDFn returns a collector which exports the current state -// of process metrics including cpu, memory and file descriptor usage as well -// as the process start time under the given namespace. The given pidFn is -// called on each collect and is used to determine the process to export -// metrics for. -func NewProcessCollectorPIDFn( - pidFn func() (int, error), - namespace string, -) Collector { +// NewProcessCollector returns a collector which exports the current state of +// process metrics including CPU, memory and file descriptor usage as well as +// the process start time. The detailed behavior is defined by the provided +// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a +// collector for the current process with an empty namespace string and no error +// reporting. +// +// Currently, the collector depends on a Linux-style proc filesystem and +// therefore only exports metrics for Linux. +// +// Note: An older version of this function had the following signature: +// +// NewProcessCollector(pid int, namespace string) Collector +// +// Most commonly, it was called as +// +// NewProcessCollector(os.Getpid(), "") +// +// The following call of the current version is equivalent to the above: +// +// NewProcessCollector(ProcessCollectorOpts{}) +func NewProcessCollector(opts ProcessCollectorOpts) Collector { ns := "" - if len(namespace) > 0 { - ns = namespace + "_" + if len(opts.Namespace) > 0 { + ns = opts.Namespace + "_" } - c := processCollector{ - pidFn: pidFn, - collectFn: func(chan<- Metric) {}, - + c := &processCollector{ + reportErrors: opts.ReportErrors, cpuTotal: NewDesc( ns+"process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", @@ -73,6 +101,11 @@ func NewProcessCollectorPIDFn( "Virtual memory size in bytes.", nil, nil, ), + maxVsize: NewDesc( + ns+"process_virtual_memory_max_bytes", + "Maximum amount of virtual memory available in bytes.", + nil, nil, + ), rss: NewDesc( ns+"process_resident_memory_bytes", "Resident memory size in bytes.", @@ -85,12 +118,23 @@ func NewProcessCollectorPIDFn( ), } + if opts.PidFn == nil { + pid := os.Getpid() + c.pidFn = func() (int, error) { return pid, nil } + } else { + c.pidFn = opts.PidFn + } + // Set up process metric collection if supported by the runtime. if _, err := procfs.NewStat(); err == nil { c.collectFn = c.processCollect + } else { + c.collectFn = func(ch chan<- Metric) { + c.reportError(ch, nil, errors.New("process metrics not supported on this platform")) + } } - return &c + return c } // Describe returns all descriptions of the collector. @@ -99,6 +143,7 @@ func (c *processCollector) Describe(ch chan<- *Desc) { ch <- c.openFDs ch <- c.maxFDs ch <- c.vsize + ch <- c.maxVsize ch <- c.rss ch <- c.startTime } @@ -108,16 +153,16 @@ func (c *processCollector) Collect(ch chan<- Metric) { c.collectFn(ch) } -// TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the -// client allows users to configure the error behavior. func (c *processCollector) processCollect(ch chan<- Metric) { pid, err := c.pidFn() if err != nil { + c.reportError(ch, nil, err) return } p, err := procfs.NewProc(pid) if err != nil { + c.reportError(ch, nil, err) return } @@ -127,14 +172,33 @@ func (c *processCollector) processCollect(ch chan<- Metric) { ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory())) if startTime, err := stat.StartTime(); err == nil { ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime) + } else { + c.reportError(ch, c.startTime, err) } + } else { + c.reportError(ch, nil, err) } if fds, err := p.FileDescriptorsLen(); err == nil { ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds)) + } else { + c.reportError(ch, c.openFDs, err) } if limits, err := p.NewLimits(); err == nil { ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles)) + ch <- MustNewConstMetric(c.maxVsize, GaugeValue, float64(limits.AddressSpace)) + } else { + c.reportError(ch, nil, err) + } +} + +func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) { + if !c.reportErrors { + return + } + if desc == nil { + desc = NewInvalidDesc(err) } + ch <- NewInvalidMetric(desc, err) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go new file mode 100644 index 0000000000..a00ba1eb83 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go @@ -0,0 +1,223 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package promauto provides constructors for the usual Prometheus metrics that +// return them already registered with the global registry +// (prometheus.DefaultRegisterer). This allows very compact code, avoiding any +// references to the registry altogether, but all the constructors in this +// package will panic if the registration fails. +// +// The following example is a complete program to create a histogram of normally +// distributed random numbers from the math/rand package: +// +// package main +// +// import ( +// "math/rand" +// "net/http" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promauto" +// "github.com/prometheus/client_golang/prometheus/promhttp" +// ) +// +// var histogram = promauto.NewHistogram(prometheus.HistogramOpts{ +// Name: "random_numbers", +// Help: "A histogram of normally distributed random numbers.", +// Buckets: prometheus.LinearBuckets(-3, .1, 61), +// }) +// +// func Random() { +// for { +// histogram.Observe(rand.NormFloat64()) +// } +// } +// +// func main() { +// go Random() +// http.Handle("/metrics", promhttp.Handler()) +// http.ListenAndServe(":1971", nil) +// } +// +// Prometheus's version of a minimal hello-world program: +// +// package main +// +// import ( +// "fmt" +// "net/http" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promauto" +// "github.com/prometheus/client_golang/prometheus/promhttp" +// ) +// +// func main() { +// http.Handle("/", promhttp.InstrumentHandlerCounter( +// promauto.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "hello_requests_total", +// Help: "Total number of hello-world requests by HTTP code.", +// }, +// []string{"code"}, +// ), +// http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// fmt.Fprint(w, "Hello, world!") +// }), +// )) +// http.Handle("/metrics", promhttp.Handler()) +// http.ListenAndServe(":1971", nil) +// } +// +// This appears very handy. So why are these constructors locked away in a +// separate package? There are two caveats: +// +// First, in more complex programs, global state is often quite problematic. +// That's the reason why the metrics constructors in the prometheus package do +// not interact with the global prometheus.DefaultRegisterer on their own. You +// are free to use the Register or MustRegister functions to register them with +// the global prometheus.DefaultRegisterer, but you could as well choose a local +// Registerer (usually created with prometheus.NewRegistry, but there are other +// scenarios, e.g. testing). +// +// The second issue is that registration may fail, e.g. if a metric inconsistent +// with the newly to be registered one is already registered. But how to signal +// and handle a panic in the automatic registration with the default registry? +// The only way is panicking. While panicking on invalid input provided by the +// programmer is certainly fine, things are a bit more subtle in this case: You +// might just add another package to the program, and that package (in its init +// function) happens to register a metric with the same name as your code. Now, +// all of a sudden, either your code or the code of the newly imported package +// panics, depending on initialization order, without any opportunity to handle +// the case gracefully. Even worse is a scenario where registration happens +// later during the runtime (e.g. upon loading some kind of plugin), where the +// panic could be triggered long after the code has been deployed to +// production. A possibility to panic should be explicitly called out by the +// Must… idiom, cf. prometheus.MustRegister. But adding a separate set of +// constructors in the prometheus package called MustRegisterNewCounterVec or +// similar would be quite unwieldy. Adding an extra MustRegister method to each +// metric, returning the registered metric, would result in nice code for those +// using the method, but would pollute every single metric interface for +// everybody avoiding the global registry. +// +// To address both issues, the problematic auto-registering and possibly +// panicking constructors are all in this package with a clear warning +// ahead. And whoever cares about avoiding global state and possibly panicking +// function calls can simply ignore the existence of the promauto package +// altogether. +// +// A final note: There is a similar case in the net/http package of the standard +// library. It has DefaultServeMux as a global instance of ServeMux, and the +// Handle function acts on it, panicking if a handler for the same pattern has +// already been registered. However, one might argue that the whole HTTP routing +// is usually set up closely together in the same package or file, while +// Prometheus metrics tend to be spread widely over the codebase, increasing the +// chance of surprising registration failures. Furthermore, the use of global +// state in net/http has been criticized widely, and some avoid it altogether. +package promauto + +import "github.com/prometheus/client_golang/prometheus" + +// NewCounter works like the function of the same name in the prometheus package +// but it automatically registers the Counter with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounter panics. +func NewCounter(opts prometheus.CounterOpts) prometheus.Counter { + c := prometheus.NewCounter(opts) + prometheus.MustRegister(c) + return c +} + +// NewCounterVec works like the function of the same name in the prometheus +// package but it automatically registers the CounterVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounterVec +// panics. +func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec { + c := prometheus.NewCounterVec(opts, labelNames) + prometheus.MustRegister(c) + return c +} + +// NewCounterFunc works like the function of the same name in the prometheus +// package but it automatically registers the CounterFunc with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounterFunc +// panics. +func NewCounterFunc(opts prometheus.CounterOpts, function func() float64) prometheus.CounterFunc { + g := prometheus.NewCounterFunc(opts, function) + prometheus.MustRegister(g) + return g +} + +// NewGauge works like the function of the same name in the prometheus package +// but it automatically registers the Gauge with the +// prometheus.DefaultRegisterer. If the registration fails, NewGauge panics. +func NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge { + g := prometheus.NewGauge(opts) + prometheus.MustRegister(g) + return g +} + +// NewGaugeVec works like the function of the same name in the prometheus +// package but it automatically registers the GaugeVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewGaugeVec panics. +func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec { + g := prometheus.NewGaugeVec(opts, labelNames) + prometheus.MustRegister(g) + return g +} + +// NewGaugeFunc works like the function of the same name in the prometheus +// package but it automatically registers the GaugeFunc with the +// prometheus.DefaultRegisterer. If the registration fails, NewGaugeFunc panics. +func NewGaugeFunc(opts prometheus.GaugeOpts, function func() float64) prometheus.GaugeFunc { + g := prometheus.NewGaugeFunc(opts, function) + prometheus.MustRegister(g) + return g +} + +// NewSummary works like the function of the same name in the prometheus package +// but it automatically registers the Summary with the +// prometheus.DefaultRegisterer. If the registration fails, NewSummary panics. +func NewSummary(opts prometheus.SummaryOpts) prometheus.Summary { + s := prometheus.NewSummary(opts) + prometheus.MustRegister(s) + return s +} + +// NewSummaryVec works like the function of the same name in the prometheus +// package but it automatically registers the SummaryVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewSummaryVec +// panics. +func NewSummaryVec(opts prometheus.SummaryOpts, labelNames []string) *prometheus.SummaryVec { + s := prometheus.NewSummaryVec(opts, labelNames) + prometheus.MustRegister(s) + return s +} + +// NewHistogram works like the function of the same name in the prometheus +// package but it automatically registers the Histogram with the +// prometheus.DefaultRegisterer. If the registration fails, NewHistogram panics. +func NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram { + h := prometheus.NewHistogram(opts) + prometheus.MustRegister(h) + return h +} + +// NewHistogramVec works like the function of the same name in the prometheus +// package but it automatically registers the HistogramVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewHistogramVec +// panics. +func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec { + h := prometheus.NewHistogramVec(opts, labelNames) + prometheus.MustRegister(h) + return h +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go new file mode 100644 index 0000000000..67b56d37cf --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go @@ -0,0 +1,199 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package promhttp + +import ( + "bufio" + "io" + "net" + "net/http" +) + +const ( + closeNotifier = 1 << iota + flusher + hijacker + readerFrom + pusher +) + +type delegator interface { + http.ResponseWriter + + Status() int + Written() int64 +} + +type responseWriterDelegator struct { + http.ResponseWriter + + handler, method string + status int + written int64 + wroteHeader bool + observeWriteHeader func(int) +} + +func (r *responseWriterDelegator) Status() int { + return r.status +} + +func (r *responseWriterDelegator) Written() int64 { + return r.written +} + +func (r *responseWriterDelegator) WriteHeader(code int) { + r.status = code + r.wroteHeader = true + r.ResponseWriter.WriteHeader(code) + if r.observeWriteHeader != nil { + r.observeWriteHeader(code) + } +} + +func (r *responseWriterDelegator) Write(b []byte) (int, error) { + if !r.wroteHeader { + r.WriteHeader(http.StatusOK) + } + n, err := r.ResponseWriter.Write(b) + r.written += int64(n) + return n, err +} + +type closeNotifierDelegator struct{ *responseWriterDelegator } +type flusherDelegator struct{ *responseWriterDelegator } +type hijackerDelegator struct{ *responseWriterDelegator } +type readerFromDelegator struct{ *responseWriterDelegator } + +func (d closeNotifierDelegator) CloseNotify() <-chan bool { + return d.ResponseWriter.(http.CloseNotifier).CloseNotify() +} +func (d flusherDelegator) Flush() { + d.ResponseWriter.(http.Flusher).Flush() +} +func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return d.ResponseWriter.(http.Hijacker).Hijack() +} +func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { + if !d.wroteHeader { + d.WriteHeader(http.StatusOK) + } + n, err := d.ResponseWriter.(io.ReaderFrom).ReadFrom(re) + d.written += n + return n, err +} + +var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32) + +func init() { + // TODO(beorn7): Code generation would help here. + pickDelegator[0] = func(d *responseWriterDelegator) delegator { // 0 + return d + } + pickDelegator[closeNotifier] = func(d *responseWriterDelegator) delegator { // 1 + return closeNotifierDelegator{d} + } + pickDelegator[flusher] = func(d *responseWriterDelegator) delegator { // 2 + return flusherDelegator{d} + } + pickDelegator[flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 3 + return struct { + *responseWriterDelegator + http.Flusher + http.CloseNotifier + }{d, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[hijacker] = func(d *responseWriterDelegator) delegator { // 4 + return hijackerDelegator{d} + } + pickDelegator[hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 5 + return struct { + *responseWriterDelegator + http.Hijacker + http.CloseNotifier + }{d, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 6 + return struct { + *responseWriterDelegator + http.Hijacker + http.Flusher + }{d, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 7 + return struct { + *responseWriterDelegator + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[readerFrom] = func(d *responseWriterDelegator) delegator { // 8 + return readerFromDelegator{d} + } + pickDelegator[readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 9 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.CloseNotifier + }{d, readerFromDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 10 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Flusher + }{d, readerFromDelegator{d}, flusherDelegator{d}} + } + pickDelegator[readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 11 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Flusher + http.CloseNotifier + }{d, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 12 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Hijacker + }{d, readerFromDelegator{d}, hijackerDelegator{d}} + } + pickDelegator[readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 13 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Hijacker + http.CloseNotifier + }{d, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 14 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Hijacker + http.Flusher + }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 15 + return struct { + *responseWriterDelegator + io.ReaderFrom + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go new file mode 100644 index 0000000000..31a7069569 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go @@ -0,0 +1,181 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build go1.8 + +package promhttp + +import ( + "io" + "net/http" +) + +type pusherDelegator struct{ *responseWriterDelegator } + +func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { + return d.ResponseWriter.(http.Pusher).Push(target, opts) +} + +func init() { + pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 + return pusherDelegator{d} + } + pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 + return struct { + *responseWriterDelegator + http.Pusher + http.CloseNotifier + }{d, pusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 + return struct { + *responseWriterDelegator + http.Pusher + http.Flusher + }{d, pusherDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 + return struct { + *responseWriterDelegator + http.Pusher + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + }{d, pusherDelegator{d}, hijackerDelegator{d}} + } + pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.CloseNotifier + }{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.Flusher + }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 + return struct { + *responseWriterDelegator + http.Pusher + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + }{d, pusherDelegator{d}, readerFromDelegator{d}} + } + pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Flusher + }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.Flusher + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} + } + pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 + return struct { + *responseWriterDelegator + http.Pusher + io.ReaderFrom + http.Hijacker + http.Flusher + http.CloseNotifier + }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} + } +} + +func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { + d := &responseWriterDelegator{ + ResponseWriter: w, + observeWriteHeader: observeWriteHeaderFunc, + } + + id := 0 + if _, ok := w.(http.CloseNotifier); ok { + id += closeNotifier + } + if _, ok := w.(http.Flusher); ok { + id += flusher + } + if _, ok := w.(http.Hijacker); ok { + id += hijacker + } + if _, ok := w.(io.ReaderFrom); ok { + id += readerFrom + } + if _, ok := w.(http.Pusher); ok { + id += pusher + } + + return pickDelegator[id](d) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go new file mode 100644 index 0000000000..8bb9b8b68f --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go @@ -0,0 +1,44 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !go1.8 + +package promhttp + +import ( + "io" + "net/http" +) + +func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { + d := &responseWriterDelegator{ + ResponseWriter: w, + observeWriteHeader: observeWriteHeaderFunc, + } + + id := 0 + if _, ok := w.(http.CloseNotifier); ok { + id += closeNotifier + } + if _, ok := w.(http.Flusher); ok { + id += flusher + } + if _, ok := w.(http.Hijacker); ok { + id += hijacker + } + if _, ok := w.(io.ReaderFrom); ok { + id += readerFrom + } + + return pickDelegator[id](d) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go new file mode 100644 index 0000000000..668eb6b3c9 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -0,0 +1,311 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package promhttp provides tooling around HTTP servers and clients. +// +// First, the package allows the creation of http.Handler instances to expose +// Prometheus metrics via HTTP. promhttp.Handler acts on the +// prometheus.DefaultGatherer. With HandlerFor, you can create a handler for a +// custom registry or anything that implements the Gatherer interface. It also +// allows the creation of handlers that act differently on errors or allow to +// log errors. +// +// Second, the package provides tooling to instrument instances of http.Handler +// via middleware. Middleware wrappers follow the naming scheme +// InstrumentHandlerX, where X describes the intended use of the middleware. +// See each function's doc comment for specific details. +// +// Finally, the package allows for an http.RoundTripper to be instrumented via +// middleware. Middleware wrappers follow the naming scheme +// InstrumentRoundTripperX, where X describes the intended use of the +// middleware. See each function's doc comment for specific details. +package promhttp + +import ( + "compress/gzip" + "fmt" + "io" + "net/http" + "strings" + "sync" + "time" + + "github.com/prometheus/common/expfmt" + + "github.com/prometheus/client_golang/prometheus" +) + +const ( + contentTypeHeader = "Content-Type" + contentLengthHeader = "Content-Length" + contentEncodingHeader = "Content-Encoding" + acceptEncodingHeader = "Accept-Encoding" +) + +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, +} + +// Handler returns an http.Handler for the prometheus.DefaultGatherer, using +// default HandlerOpts, i.e. it reports the first error as an HTTP error, it has +// no error logging, and it applies compression if requested by the client. +// +// The returned http.Handler is already instrumented using the +// InstrumentMetricHandler function and the prometheus.DefaultRegisterer. If you +// create multiple http.Handlers by separate calls of the Handler function, the +// metrics used for instrumentation will be shared between them, providing +// global scrape counts. +// +// This function is meant to cover the bulk of basic use cases. If you are doing +// anything that requires more customization (including using a non-default +// Gatherer, different instrumentation, and non-default HandlerOpts), use the +// HandlerFor function. See there for details. +func Handler() http.Handler { + return InstrumentMetricHandler( + prometheus.DefaultRegisterer, HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}), + ) +} + +// HandlerFor returns an uninstrumented http.Handler for the provided +// Gatherer. The behavior of the Handler is defined by the provided +// HandlerOpts. Thus, HandlerFor is useful to create http.Handlers for custom +// Gatherers, with non-default HandlerOpts, and/or with custom (or no) +// instrumentation. Use the InstrumentMetricHandler function to apply the same +// kind of instrumentation as it is used by the Handler function. +func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { + var inFlightSem chan struct{} + if opts.MaxRequestsInFlight > 0 { + inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight) + } + + h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { + if inFlightSem != nil { + select { + case inFlightSem <- struct{}{}: // All good, carry on. + defer func() { <-inFlightSem }() + default: + http.Error(rsp, fmt.Sprintf( + "Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight, + ), http.StatusServiceUnavailable) + return + } + } + mfs, err := reg.Gather() + if err != nil { + if opts.ErrorLog != nil { + opts.ErrorLog.Println("error gathering metrics:", err) + } + switch opts.ErrorHandling { + case PanicOnError: + panic(err) + case ContinueOnError: + if len(mfs) == 0 { + // Still report the error if no metrics have been gathered. + httpError(rsp, err) + return + } + case HTTPErrorOnError: + httpError(rsp, err) + return + } + } + + contentType := expfmt.Negotiate(req.Header) + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if !opts.DisableCompression && gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + + var lastErr error + for _, mf := range mfs { + if err := enc.Encode(mf); err != nil { + lastErr = err + if opts.ErrorLog != nil { + opts.ErrorLog.Println("error encoding and sending metric family:", err) + } + switch opts.ErrorHandling { + case PanicOnError: + panic(err) + case ContinueOnError: + // Handled later. + case HTTPErrorOnError: + httpError(rsp, err) + return + } + } + } + + if lastErr != nil { + httpError(rsp, lastErr) + } + }) + + if opts.Timeout <= 0 { + return h + } + return http.TimeoutHandler(h, opts.Timeout, fmt.Sprintf( + "Exceeded configured timeout of %v.\n", + opts.Timeout, + )) +} + +// InstrumentMetricHandler is usually used with an http.Handler returned by the +// HandlerFor function. It instruments the provided http.Handler with two +// metrics: A counter vector "promhttp_metric_handler_requests_total" to count +// scrapes partitioned by HTTP status code, and a gauge +// "promhttp_metric_handler_requests_in_flight" to track the number of +// simultaneous scrapes. This function idempotently registers collectors for +// both metrics with the provided Registerer. It panics if the registration +// fails. The provided metrics are useful to see how many scrapes hit the +// monitored target (which could be from different Prometheus servers or other +// scrapers), and how often they overlap (which would result in more than one +// scrape in flight at the same time). Note that the scrapes-in-flight gauge +// will contain the scrape by which it is exposed, while the scrape counter will +// only get incremented after the scrape is complete (as only then the status +// code is known). For tracking scrape durations, use the +// "scrape_duration_seconds" gauge created by the Prometheus server upon each +// scrape. +func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) http.Handler { + cnt := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "promhttp_metric_handler_requests_total", + Help: "Total number of scrapes by HTTP status code.", + }, + []string{"code"}, + ) + // Initialize the most likely HTTP status codes. + cnt.WithLabelValues("200") + cnt.WithLabelValues("500") + cnt.WithLabelValues("503") + if err := reg.Register(cnt); err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + cnt = are.ExistingCollector.(*prometheus.CounterVec) + } else { + panic(err) + } + } + + gge := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "promhttp_metric_handler_requests_in_flight", + Help: "Current number of scrapes being served.", + }) + if err := reg.Register(gge); err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + gge = are.ExistingCollector.(prometheus.Gauge) + } else { + panic(err) + } + } + + return InstrumentHandlerCounter(cnt, InstrumentHandlerInFlight(gge, handler)) +} + +// HandlerErrorHandling defines how a Handler serving metrics will handle +// errors. +type HandlerErrorHandling int + +// These constants cause handlers serving metrics to behave as described if +// errors are encountered. +const ( + // Serve an HTTP status code 500 upon the first error + // encountered. Report the error message in the body. + HTTPErrorOnError HandlerErrorHandling = iota + // Ignore errors and try to serve as many metrics as possible. However, + // if no metrics can be served, serve an HTTP status code 500 and the + // last error message in the body. Only use this in deliberate "best + // effort" metrics collection scenarios. It is recommended to at least + // log errors (by providing an ErrorLog in HandlerOpts) to not mask + // errors completely. + ContinueOnError + // Panic upon the first error encountered (useful for "crash only" apps). + PanicOnError +) + +// Logger is the minimal interface HandlerOpts needs for logging. Note that +// log.Logger from the standard library implements this interface, and it is +// easy to implement by custom loggers, if they don't do so already anyway. +type Logger interface { + Println(v ...interface{}) +} + +// HandlerOpts specifies options how to serve metrics via an http.Handler. The +// zero value of HandlerOpts is a reasonable default. +type HandlerOpts struct { + // ErrorLog specifies an optional logger for errors collecting and + // serving metrics. If nil, errors are not logged at all. + ErrorLog Logger + // ErrorHandling defines how errors are handled. Note that errors are + // logged regardless of the configured ErrorHandling provided ErrorLog + // is not nil. + ErrorHandling HandlerErrorHandling + // If DisableCompression is true, the handler will never compress the + // response, even if requested by the client. + DisableCompression bool + // The number of concurrent HTTP requests is limited to + // MaxRequestsInFlight. Additional requests are responded to with 503 + // Service Unavailable and a suitable message in the body. If + // MaxRequestsInFlight is 0 or negative, no limit is applied. + MaxRequestsInFlight int + // If handling a request takes longer than Timeout, it is responded to + // with 503 ServiceUnavailable and a suitable Message. No timeout is + // applied if Timeout is 0 or negative. Note that with the current + // implementation, reaching the timeout simply ends the HTTP requests as + // described above (and even that only if sending of the body hasn't + // started yet), while the bulk work of gathering all the metrics keeps + // running in the background (with the eventual result to be thrown + // away). Until the implementation is improved, it is recommended to + // implement a separate timeout in potentially slow Collectors. + Timeout time.Duration +} + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "gzip" || strings.HasPrefix(part, "gzip;") { + return true + } + } + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go new file mode 100644 index 0000000000..86fd564470 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go @@ -0,0 +1,97 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package promhttp + +import ( + "net/http" + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +// The RoundTripperFunc type is an adapter to allow the use of ordinary +// functions as RoundTrippers. If f is a function with the appropriate +// signature, RountTripperFunc(f) is a RoundTripper that calls f. +type RoundTripperFunc func(req *http.Request) (*http.Response, error) + +// RoundTrip implements the RoundTripper interface. +func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { + return rt(r) +} + +// InstrumentRoundTripperInFlight is a middleware that wraps the provided +// http.RoundTripper. It sets the provided prometheus.Gauge to the number of +// requests currently handled by the wrapped http.RoundTripper. +// +// See the example for ExampleInstrumentRoundTripperDuration for example usage. +func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc { + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + gauge.Inc() + defer gauge.Dec() + return next.RoundTrip(r) + }) +} + +// InstrumentRoundTripperCounter is a middleware that wraps the provided +// http.RoundTripper to observe the request result with the provided CounterVec. +// The CounterVec must have zero, one, or two non-const non-curried labels. For +// those, the only allowed label names are "code" and "method". The function +// panics otherwise. Partitioning of the CounterVec happens by HTTP status code +// and/or HTTP method if the respective instance label names are present in the +// CounterVec. For unpartitioned counting, use a CounterVec with zero labels. +// +// If the wrapped RoundTripper panics or returns a non-nil error, the Counter +// is not incremented. +// +// See the example for ExampleInstrumentRoundTripperDuration for example usage. +func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc { + code, method := checkLabels(counter) + + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + resp, err := next.RoundTrip(r) + if err == nil { + counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc() + } + return resp, err + }) +} + +// InstrumentRoundTripperDuration is a middleware that wraps the provided +// http.RoundTripper to observe the request duration with the provided +// ObserverVec. The ObserverVec must have zero, one, or two non-const +// non-curried labels. For those, the only allowed label names are "code" and +// "method". The function panics otherwise. The Observe method of the Observer +// in the ObserverVec is called with the request duration in +// seconds. Partitioning happens by HTTP status code and/or HTTP method if the +// respective instance label names are present in the ObserverVec. For +// unpartitioned observations, use an ObserverVec with zero labels. Note that +// partitioning of Histograms is expensive and should be used judiciously. +// +// If the wrapped RoundTripper panics or returns a non-nil error, no values are +// reported. +// +// Note that this method is only guaranteed to never observe negative durations +// if used with Go1.9+. +func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc { + code, method := checkLabels(obs) + + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + start := time.Now() + resp, err := next.RoundTrip(r) + if err == nil { + obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds()) + } + return resp, err + }) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go new file mode 100644 index 0000000000..a034d1ec0f --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go @@ -0,0 +1,144 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build go1.8 + +package promhttp + +import ( + "context" + "crypto/tls" + "net/http" + "net/http/httptrace" + "time" +) + +// InstrumentTrace is used to offer flexibility in instrumenting the available +// httptrace.ClientTrace hook functions. Each function is passed a float64 +// representing the time in seconds since the start of the http request. A user +// may choose to use separately buckets Histograms, or implement custom +// instance labels on a per function basis. +type InstrumentTrace struct { + GotConn func(float64) + PutIdleConn func(float64) + GotFirstResponseByte func(float64) + Got100Continue func(float64) + DNSStart func(float64) + DNSDone func(float64) + ConnectStart func(float64) + ConnectDone func(float64) + TLSHandshakeStart func(float64) + TLSHandshakeDone func(float64) + WroteHeaders func(float64) + Wait100Continue func(float64) + WroteRequest func(float64) +} + +// InstrumentRoundTripperTrace is a middleware that wraps the provided +// RoundTripper and reports times to hook functions provided in the +// InstrumentTrace struct. Hook functions that are not present in the provided +// InstrumentTrace struct are ignored. Times reported to the hook functions are +// time since the start of the request. Only with Go1.9+, those times are +// guaranteed to never be negative. (Earlier Go versions are not using a +// monotonic clock.) Note that partitioning of Histograms is expensive and +// should be used judiciously. +// +// For hook functions that receive an error as an argument, no observations are +// made in the event of a non-nil error value. +// +// See the example for ExampleInstrumentRoundTripperDuration for example usage. +func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + start := time.Now() + + trace := &httptrace.ClientTrace{ + GotConn: func(_ httptrace.GotConnInfo) { + if it.GotConn != nil { + it.GotConn(time.Since(start).Seconds()) + } + }, + PutIdleConn: func(err error) { + if err != nil { + return + } + if it.PutIdleConn != nil { + it.PutIdleConn(time.Since(start).Seconds()) + } + }, + DNSStart: func(_ httptrace.DNSStartInfo) { + if it.DNSStart != nil { + it.DNSStart(time.Since(start).Seconds()) + } + }, + DNSDone: func(_ httptrace.DNSDoneInfo) { + if it.DNSDone != nil { + it.DNSDone(time.Since(start).Seconds()) + } + }, + ConnectStart: func(_, _ string) { + if it.ConnectStart != nil { + it.ConnectStart(time.Since(start).Seconds()) + } + }, + ConnectDone: func(_, _ string, err error) { + if err != nil { + return + } + if it.ConnectDone != nil { + it.ConnectDone(time.Since(start).Seconds()) + } + }, + GotFirstResponseByte: func() { + if it.GotFirstResponseByte != nil { + it.GotFirstResponseByte(time.Since(start).Seconds()) + } + }, + Got100Continue: func() { + if it.Got100Continue != nil { + it.Got100Continue(time.Since(start).Seconds()) + } + }, + TLSHandshakeStart: func() { + if it.TLSHandshakeStart != nil { + it.TLSHandshakeStart(time.Since(start).Seconds()) + } + }, + TLSHandshakeDone: func(_ tls.ConnectionState, err error) { + if err != nil { + return + } + if it.TLSHandshakeDone != nil { + it.TLSHandshakeDone(time.Since(start).Seconds()) + } + }, + WroteHeaders: func() { + if it.WroteHeaders != nil { + it.WroteHeaders(time.Since(start).Seconds()) + } + }, + Wait100Continue: func() { + if it.Wait100Continue != nil { + it.Wait100Continue(time.Since(start).Seconds()) + } + }, + WroteRequest: func(_ httptrace.WroteRequestInfo) { + if it.WroteRequest != nil { + it.WroteRequest(time.Since(start).Seconds()) + } + }, + } + r = r.WithContext(httptrace.WithClientTrace(context.Background(), trace)) + + return next.RoundTrip(r) + }) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go new file mode 100644 index 0000000000..9db2438053 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go @@ -0,0 +1,447 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package promhttp + +import ( + "errors" + "net/http" + "strconv" + "strings" + "time" + + dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus" +) + +// magicString is used for the hacky label test in checkLabels. Remove once fixed. +const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa" + +// InstrumentHandlerInFlight is a middleware that wraps the provided +// http.Handler. It sets the provided prometheus.Gauge to the number of +// requests currently handled by the wrapped http.Handler. +// +// See the example for InstrumentHandlerDuration for example usage. +func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + g.Inc() + defer g.Dec() + next.ServeHTTP(w, r) + }) +} + +// InstrumentHandlerDuration is a middleware that wraps the provided +// http.Handler to observe the request duration with the provided ObserverVec. +// The ObserverVec must have zero, one, or two non-const non-curried labels. For +// those, the only allowed label names are "code" and "method". The function +// panics otherwise. The Observe method of the Observer in the ObserverVec is +// called with the request duration in seconds. Partitioning happens by HTTP +// status code and/or HTTP method if the respective instance label names are +// present in the ObserverVec. For unpartitioned observations, use an +// ObserverVec with zero labels. Note that partitioning of Histograms is +// expensive and should be used judiciously. +// +// If the wrapped Handler does not set a status code, a status code of 200 is assumed. +// +// If the wrapped Handler panics, no values are reported. +// +// Note that this method is only guaranteed to never observe negative durations +// if used with Go1.9+. +func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { + code, method := checkLabels(obs) + + if code { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + now := time.Now() + d := newDelegator(w, nil) + next.ServeHTTP(d, r) + + obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds()) + }) + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + now := time.Now() + next.ServeHTTP(w, r) + obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds()) + }) +} + +// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler +// to observe the request result with the provided CounterVec. The CounterVec +// must have zero, one, or two non-const non-curried labels. For those, the only +// allowed label names are "code" and "method". The function panics +// otherwise. Partitioning of the CounterVec happens by HTTP status code and/or +// HTTP method if the respective instance label names are present in the +// CounterVec. For unpartitioned counting, use a CounterVec with zero labels. +// +// If the wrapped Handler does not set a status code, a status code of 200 is assumed. +// +// If the wrapped Handler panics, the Counter is not incremented. +// +// See the example for InstrumentHandlerDuration for example usage. +func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc { + code, method := checkLabels(counter) + + if code { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + d := newDelegator(w, nil) + next.ServeHTTP(d, r) + counter.With(labels(code, method, r.Method, d.Status())).Inc() + }) + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + next.ServeHTTP(w, r) + counter.With(labels(code, method, r.Method, 0)).Inc() + }) +} + +// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided +// http.Handler to observe with the provided ObserverVec the request duration +// until the response headers are written. The ObserverVec must have zero, one, +// or two non-const non-curried labels. For those, the only allowed label names +// are "code" and "method". The function panics otherwise. The Observe method of +// the Observer in the ObserverVec is called with the request duration in +// seconds. Partitioning happens by HTTP status code and/or HTTP method if the +// respective instance label names are present in the ObserverVec. For +// unpartitioned observations, use an ObserverVec with zero labels. Note that +// partitioning of Histograms is expensive and should be used judiciously. +// +// If the wrapped Handler panics before calling WriteHeader, no value is +// reported. +// +// Note that this method is only guaranteed to never observe negative durations +// if used with Go1.9+. +// +// See the example for InstrumentHandlerDuration for example usage. +func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { + code, method := checkLabels(obs) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + now := time.Now() + d := newDelegator(w, func(status int) { + obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds()) + }) + next.ServeHTTP(d, r) + }) +} + +// InstrumentHandlerRequestSize is a middleware that wraps the provided +// http.Handler to observe the request size with the provided ObserverVec. The +// ObserverVec must have zero, one, or two non-const non-curried labels. For +// those, the only allowed label names are "code" and "method". The function +// panics otherwise. The Observe method of the Observer in the ObserverVec is +// called with the request size in bytes. Partitioning happens by HTTP status +// code and/or HTTP method if the respective instance label names are present in +// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero +// labels. Note that partitioning of Histograms is expensive and should be used +// judiciously. +// +// If the wrapped Handler does not set a status code, a status code of 200 is assumed. +// +// If the wrapped Handler panics, no values are reported. +// +// See the example for InstrumentHandlerDuration for example usage. +func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { + code, method := checkLabels(obs) + + if code { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + d := newDelegator(w, nil) + next.ServeHTTP(d, r) + size := computeApproximateRequestSize(r) + obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size)) + }) + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + next.ServeHTTP(w, r) + size := computeApproximateRequestSize(r) + obs.With(labels(code, method, r.Method, 0)).Observe(float64(size)) + }) +} + +// InstrumentHandlerResponseSize is a middleware that wraps the provided +// http.Handler to observe the response size with the provided ObserverVec. The +// ObserverVec must have zero, one, or two non-const non-curried labels. For +// those, the only allowed label names are "code" and "method". The function +// panics otherwise. The Observe method of the Observer in the ObserverVec is +// called with the response size in bytes. Partitioning happens by HTTP status +// code and/or HTTP method if the respective instance label names are present in +// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero +// labels. Note that partitioning of Histograms is expensive and should be used +// judiciously. +// +// If the wrapped Handler does not set a status code, a status code of 200 is assumed. +// +// If the wrapped Handler panics, no values are reported. +// +// See the example for InstrumentHandlerDuration for example usage. +func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler { + code, method := checkLabels(obs) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + d := newDelegator(w, nil) + next.ServeHTTP(d, r) + obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written())) + }) +} + +func checkLabels(c prometheus.Collector) (code bool, method bool) { + // TODO(beorn7): Remove this hacky way to check for instance labels + // once Descriptors can have their dimensionality queried. + var ( + desc *prometheus.Desc + m prometheus.Metric + pm dto.Metric + lvs []string + ) + + // Get the Desc from the Collector. + descc := make(chan *prometheus.Desc, 1) + c.Describe(descc) + + select { + case desc = <-descc: + default: + panic("no description provided by collector") + } + select { + case <-descc: + panic("more than one description provided by collector") + default: + } + + close(descc) + + // Create a ConstMetric with the Desc. Since we don't know how many + // variable labels there are, try for as long as it needs. + for err := errors.New("dummy"); err != nil; lvs = append(lvs, magicString) { + m, err = prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, lvs...) + } + + // Write out the metric into a proto message and look at the labels. + // If the value is not the magicString, it is a constLabel, which doesn't interest us. + // If the label is curried, it doesn't interest us. + // In all other cases, only "code" or "method" is allowed. + if err := m.Write(&pm); err != nil { + panic("error checking metric for labels") + } + for _, label := range pm.Label { + name, value := label.GetName(), label.GetValue() + if value != magicString || isLabelCurried(c, name) { + continue + } + switch name { + case "code": + code = true + case "method": + method = true + default: + panic("metric partitioned with non-supported labels") + } + } + return +} + +func isLabelCurried(c prometheus.Collector, label string) bool { + // This is even hackier than the label test above. + // We essentially try to curry again and see if it works. + // But for that, we need to type-convert to the two + // types we use here, ObserverVec or *CounterVec. + switch v := c.(type) { + case *prometheus.CounterVec: + if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil { + return false + } + case prometheus.ObserverVec: + if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil { + return false + } + default: + panic("unsupported metric vec type") + } + return true +} + +// emptyLabels is a one-time allocation for non-partitioned metrics to avoid +// unnecessary allocations on each request. +var emptyLabels = prometheus.Labels{} + +func labels(code, method bool, reqMethod string, status int) prometheus.Labels { + if !(code || method) { + return emptyLabels + } + labels := prometheus.Labels{} + + if code { + labels["code"] = sanitizeCode(status) + } + if method { + labels["method"] = sanitizeMethod(reqMethod) + } + + return labels +} + +func computeApproximateRequestSize(r *http.Request) int { + s := 0 + if r.URL != nil { + s += len(r.URL.String()) + } + + s += len(r.Method) + s += len(r.Proto) + for name, values := range r.Header { + s += len(name) + for _, value := range values { + s += len(value) + } + } + s += len(r.Host) + + // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. + + if r.ContentLength != -1 { + s += int(r.ContentLength) + } + return s +} + +func sanitizeMethod(m string) string { + switch m { + case "GET", "get": + return "get" + case "PUT", "put": + return "put" + case "HEAD", "head": + return "head" + case "POST", "post": + return "post" + case "DELETE", "delete": + return "delete" + case "CONNECT", "connect": + return "connect" + case "OPTIONS", "options": + return "options" + case "NOTIFY", "notify": + return "notify" + default: + return strings.ToLower(m) + } +} + +// If the wrapped http.Handler has not set a status code, i.e. the value is +// currently 0, santizeCode will return 200, for consistency with behavior in +// the stdlib. +func sanitizeCode(s int) string { + switch s { + case 100: + return "100" + case 101: + return "101" + + case 200, 0: + return "200" + case 201: + return "201" + case 202: + return "202" + case 203: + return "203" + case 204: + return "204" + case 205: + return "205" + case 206: + return "206" + + case 300: + return "300" + case 301: + return "301" + case 302: + return "302" + case 304: + return "304" + case 305: + return "305" + case 307: + return "307" + + case 400: + return "400" + case 401: + return "401" + case 402: + return "402" + case 403: + return "403" + case 404: + return "404" + case 405: + return "405" + case 406: + return "406" + case 407: + return "407" + case 408: + return "408" + case 409: + return "409" + case 410: + return "410" + case 411: + return "411" + case 412: + return "412" + case 413: + return "413" + case 414: + return "414" + case 415: + return "415" + case 416: + return "416" + case 417: + return "417" + case 418: + return "418" + + case 500: + return "500" + case 501: + return "501" + case 502: + return "502" + case 503: + return "503" + case 504: + return "504" + case 505: + return "505" + + case 428: + return "428" + case 429: + return "429" + case 431: + return "431" + case 511: + return "511" + + default: + return strconv.Itoa(s) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index 8c6b5bd8ee..b5e70b93fa 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -15,15 +15,22 @@ package prometheus import ( "bytes" - "errors" "fmt" + "io/ioutil" "os" + "path/filepath" + "runtime" "sort" + "strings" "sync" + "unicode/utf8" "github.com/golang/protobuf/proto" + "github.com/prometheus/common/expfmt" dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus/internal" ) const ( @@ -35,13 +42,14 @@ const ( // DefaultRegisterer and DefaultGatherer are the implementations of the // Registerer and Gatherer interface a number of convenience functions in this // package act on. Initially, both variables point to the same Registry, which -// has a process collector (see NewProcessCollector) and a Go collector (see -// NewGoCollector) already registered. This approach to keep default instances -// as global state mirrors the approach of other packages in the Go standard -// library. Note that there are caveats. Change the variables with caution and -// only if you understand the consequences. Users who want to avoid global state -// altogether should not use the convenience function and act on custom -// instances instead. +// has a process collector (currently on Linux only, see NewProcessCollector) +// and a Go collector (see NewGoCollector, in particular the note about +// stop-the-world implication with Go versions older than 1.9) already +// registered. This approach to keep default instances as global state mirrors +// the approach of other packages in the Go standard library. Note that there +// are caveats. Change the variables with caution and only if you understand the +// consequences. Users who want to avoid global state altogether should not use +// the convenience functions and act on custom instances instead. var ( defaultRegistry = NewRegistry() DefaultRegisterer Registerer = defaultRegistry @@ -49,7 +57,7 @@ var ( ) func init() { - MustRegister(NewProcessCollector(os.Getpid(), "")) + MustRegister(NewProcessCollector(ProcessCollectorOpts{})) MustRegister(NewGoCollector()) } @@ -65,7 +73,8 @@ func NewRegistry() *Registry { // NewPedanticRegistry returns a registry that checks during collection if each // collected Metric is consistent with its reported Desc, and if the Desc has -// actually been registered with the registry. +// actually been registered with the registry. Unchecked Collectors (those whose +// Describe methed does not yield any descriptors) are excluded from the check. // // Usually, a Registry will be happy as long as the union of all collected // Metrics is consistent and valid even if some metrics are not consistent with @@ -80,7 +89,7 @@ func NewPedanticRegistry() *Registry { // Registerer is the interface for the part of a registry in charge of // registering and unregistering. Users of custom registries should use -// Registerer as type for registration purposes (rather then the Registry type +// Registerer as type for registration purposes (rather than the Registry type // directly). In that way, they are free to use custom Registerer implementation // (e.g. for testing purposes). type Registerer interface { @@ -95,8 +104,13 @@ type Registerer interface { // returned error is an instance of AlreadyRegisteredError, which // contains the previously registered Collector. // - // It is in general not safe to register the same Collector multiple - // times concurrently. + // A Collector whose Describe method does not yield any Desc is treated + // as unchecked. Registration will always succeed. No check for + // re-registering (see previous paragraph) is performed. Thus, the + // caller is responsible for not double-registering the same unchecked + // Collector, and for providing a Collector that will not cause + // inconsistent metrics on collection. (This would lead to scrape + // errors.) Register(Collector) error // MustRegister works like Register but registers any number of // Collectors and panics upon the first registration that causes an @@ -105,7 +119,9 @@ type Registerer interface { // Unregister unregisters the Collector that equals the Collector passed // in as an argument. (Two Collectors are considered equal if their // Describe method yields the same set of descriptors.) The function - // returns whether a Collector was unregistered. + // returns whether a Collector was unregistered. Note that an unchecked + // Collector cannot be unregistered (as its Describe method does not + // yield any descriptor). // // Note that even after unregistering, it will not be possible to // register a new Collector that is inconsistent with the unregistered @@ -123,15 +139,23 @@ type Registerer interface { type Gatherer interface { // Gather calls the Collect method of the registered Collectors and then // gathers the collected metrics into a lexicographically sorted slice - // of MetricFamily protobufs. Even if an error occurs, Gather attempts - // to gather as many metrics as possible. Hence, if a non-nil error is - // returned, the returned MetricFamily slice could be nil (in case of a - // fatal error that prevented any meaningful metric collection) or - // contain a number of MetricFamily protobufs, some of which might be - // incomplete, and some might be missing altogether. The returned error - // (which might be a MultiError) explains the details. In scenarios - // where complete collection is critical, the returned MetricFamily - // protobufs should be disregarded if the returned error is non-nil. + // of uniquely named MetricFamily protobufs. Gather ensures that the + // returned slice is valid and self-consistent so that it can be used + // for valid exposition. As an exception to the strict consistency + // requirements described for metric.Desc, Gather will tolerate + // different sets of label names for metrics of the same metric family. + // + // Even if an error occurs, Gather attempts to gather as many metrics as + // possible. Hence, if a non-nil error is returned, the returned + // MetricFamily slice could be nil (in case of a fatal error that + // prevented any meaningful metric collection) or contain a number of + // MetricFamily protobufs, some of which might be incomplete, and some + // might be missing altogether. The returned error (which might be a + // MultiError) explains the details. Note that this is mostly useful for + // debugging purposes. If the gathered protobufs are to be used for + // exposition in actual monitoring, it is almost always better to not + // expose an incomplete result and instead disregard the returned + // MetricFamily protobufs in case the returned error is non-nil. Gather() ([]*dto.MetricFamily, error) } @@ -201,6 +225,13 @@ func (errs MultiError) Error() string { return buf.String() } +// Append appends the provided error if it is not nil. +func (errs *MultiError) Append(err error) { + if err != nil { + *errs = append(*errs, err) + } +} + // MaybeUnwrap returns nil if len(errs) is 0. It returns the first and only // contained error as error if len(errs is 1). In all other cases, it returns // the MultiError directly. This is helpful for returning a MultiError in a way @@ -225,6 +256,7 @@ type Registry struct { collectorsByID map[uint64]Collector // ID is a hash of the descIDs. descIDs map[uint64]struct{} dimHashesByName map[string]uint64 + uncheckedCollectors []Collector pedanticChecksEnabled bool } @@ -242,7 +274,12 @@ func (r *Registry) Register(c Collector) error { close(descChan) }() r.mtx.Lock() - defer r.mtx.Unlock() + defer func() { + // Drain channel in case of premature return to not leak a goroutine. + for range descChan { + } + r.mtx.Unlock() + }() // Conduct various tests... for desc := range descChan { @@ -282,9 +319,10 @@ func (r *Registry) Register(c Collector) error { } } } - // Did anything happen at all? + // A Collector yielding no Desc at all is considered unchecked. if len(newDescIDs) == 0 { - return errors.New("collector has no descriptors") + r.uncheckedCollectors = append(r.uncheckedCollectors, c) + return nil } if existing, exists := r.collectorsByID[collectorID]; exists { return AlreadyRegisteredError{ @@ -358,31 +396,25 @@ func (r *Registry) MustRegister(cs ...Collector) { // Gather implements Gatherer. func (r *Registry) Gather() ([]*dto.MetricFamily, error) { var ( - metricChan = make(chan Metric, capMetricChan) - metricHashes = map[uint64]struct{}{} - dimHashes = map[string]uint64{} - wg sync.WaitGroup - errs MultiError // The collected errors to return in the end. - registeredDescIDs map[uint64]struct{} // Only used for pedantic checks + checkedMetricChan = make(chan Metric, capMetricChan) + uncheckedMetricChan = make(chan Metric, capMetricChan) + metricHashes = map[uint64]struct{}{} + wg sync.WaitGroup + errs MultiError // The collected errors to return in the end. + registeredDescIDs map[uint64]struct{} // Only used for pedantic checks ) r.mtx.RLock() + goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) - - // Scatter. - // (Collectors could be complex and slow, so we call them all at once.) - wg.Add(len(r.collectorsByID)) - go func() { - wg.Wait() - close(metricChan) - }() + checkedCollectors := make(chan Collector, len(r.collectorsByID)) + uncheckedCollectors := make(chan Collector, len(r.uncheckedCollectors)) for _, collector := range r.collectorsByID { - go func(collector Collector) { - defer wg.Done() - collector.Collect(metricChan) - }(collector) + checkedCollectors <- collector + } + for _, collector := range r.uncheckedCollectors { + uncheckedCollectors <- collector } - // In case pedantic checks are enabled, we have to copy the map before // giving up the RLock. if r.pedanticChecksEnabled { @@ -391,127 +423,258 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { registeredDescIDs[id] = struct{}{} } } - r.mtx.RUnlock() - // Drain metricChan in case of premature return. + wg.Add(goroutineBudget) + + collectWorker := func() { + for { + select { + case collector := <-checkedCollectors: + collector.Collect(checkedMetricChan) + case collector := <-uncheckedCollectors: + collector.Collect(uncheckedMetricChan) + default: + return + } + wg.Done() + } + } + + // Start the first worker now to make sure at least one is running. + go collectWorker() + goroutineBudget-- + + // Close checkedMetricChan and uncheckedMetricChan once all collectors + // are collected. + go func() { + wg.Wait() + close(checkedMetricChan) + close(uncheckedMetricChan) + }() + + // Drain checkedMetricChan and uncheckedMetricChan in case of premature return. defer func() { - for range metricChan { + if checkedMetricChan != nil { + for range checkedMetricChan { + } + } + if uncheckedMetricChan != nil { + for range uncheckedMetricChan { + } } }() - // Gather. - for metric := range metricChan { - // This could be done concurrently, too, but it required locking - // of metricFamiliesByName (and of metricHashes if checks are - // enabled). Most likely not worth it. - desc := metric.Desc() - dtoMetric := &dto.Metric{} - if err := metric.Write(dtoMetric); err != nil { - errs = append(errs, fmt.Errorf( - "error collecting metric %v: %s", desc, err, + // Copy the channel references so we can nil them out later to remove + // them from the select statements below. + cmc := checkedMetricChan + umc := uncheckedMetricChan + + for { + select { + case metric, ok := <-cmc: + if !ok { + cmc = nil + break + } + errs.Append(processMetric( + metric, metricFamiliesByName, + metricHashes, + registeredDescIDs, )) - continue - } - metricFamily, ok := metricFamiliesByName[desc.fqName] - if ok { - if metricFamily.GetHelp() != desc.help { - errs = append(errs, fmt.Errorf( - "collected metric %s %s has help %q but should have %q", - desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(), - )) - continue + case metric, ok := <-umc: + if !ok { + umc = nil + break } - // TODO(beorn7): Simplify switch once Desc has type. - switch metricFamily.GetType() { - case dto.MetricType_COUNTER: - if dtoMetric.Counter == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Counter", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_GAUGE: - if dtoMetric.Gauge == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Gauge", - desc.fqName, dtoMetric, + errs.Append(processMetric( + metric, metricFamiliesByName, + metricHashes, + nil, + )) + default: + if goroutineBudget <= 0 || len(checkedCollectors)+len(uncheckedCollectors) == 0 { + // All collectors are already being worked on or + // we have already as many goroutines started as + // there are collectors. Do the same as above, + // just without the default. + select { + case metric, ok := <-cmc: + if !ok { + cmc = nil + break + } + errs.Append(processMetric( + metric, metricFamiliesByName, + metricHashes, + registeredDescIDs, )) - continue - } - case dto.MetricType_SUMMARY: - if dtoMetric.Summary == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Summary", - desc.fqName, dtoMetric, + case metric, ok := <-umc: + if !ok { + umc = nil + break + } + errs.Append(processMetric( + metric, metricFamiliesByName, + metricHashes, + nil, )) - continue } - case dto.MetricType_UNTYPED: - if dtoMetric.Untyped == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be Untyped", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_HISTOGRAM: - if dtoMetric.Histogram == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Histogram", - desc.fqName, dtoMetric, - )) - continue - } - default: - panic("encountered MetricFamily with invalid type") + break } - } else { - metricFamily = &dto.MetricFamily{} - metricFamily.Name = proto.String(desc.fqName) - metricFamily.Help = proto.String(desc.help) - // TODO(beorn7): Simplify switch once Desc has type. - switch { - case dtoMetric.Gauge != nil: - metricFamily.Type = dto.MetricType_GAUGE.Enum() - case dtoMetric.Counter != nil: - metricFamily.Type = dto.MetricType_COUNTER.Enum() - case dtoMetric.Summary != nil: - metricFamily.Type = dto.MetricType_SUMMARY.Enum() - case dtoMetric.Untyped != nil: - metricFamily.Type = dto.MetricType_UNTYPED.Enum() - case dtoMetric.Histogram != nil: - metricFamily.Type = dto.MetricType_HISTOGRAM.Enum() - default: - errs = append(errs, fmt.Errorf( - "empty metric collected: %s", dtoMetric, - )) - continue + // Start more workers. + go collectWorker() + goroutineBudget-- + runtime.Gosched() + } + // Once both checkedMetricChan and uncheckdMetricChan are closed + // and drained, the contraption above will nil out cmc and umc, + // and then we can leave the collect loop here. + if cmc == nil && umc == nil { + break + } + } + return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() +} + +// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the +// Prometheus text format, and writes it to a temporary file. Upon success, the +// temporary file is renamed to the provided filename. +// +// This is intended for use with the textfile collector of the node exporter. +// Note that the node exporter expects the filename to be suffixed with ".prom". +func WriteToTextfile(filename string, g Gatherer) error { + tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) + if err != nil { + return err + } + defer os.Remove(tmp.Name()) + + mfs, err := g.Gather() + if err != nil { + return err + } + for _, mf := range mfs { + if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil { + return err + } + } + if err := tmp.Close(); err != nil { + return err + } + + if err := os.Chmod(tmp.Name(), 0644); err != nil { + return err + } + return os.Rename(tmp.Name(), filename) +} + +// processMetric is an internal helper method only used by the Gather method. +func processMetric( + metric Metric, + metricFamiliesByName map[string]*dto.MetricFamily, + metricHashes map[uint64]struct{}, + registeredDescIDs map[uint64]struct{}, +) error { + desc := metric.Desc() + // Wrapped metrics collected by an unchecked Collector can have an + // invalid Desc. + if desc.err != nil { + return desc.err + } + dtoMetric := &dto.Metric{} + if err := metric.Write(dtoMetric); err != nil { + return fmt.Errorf("error collecting metric %v: %s", desc, err) + } + metricFamily, ok := metricFamiliesByName[desc.fqName] + if ok { // Existing name. + if metricFamily.GetHelp() != desc.help { + return fmt.Errorf( + "collected metric %s %s has help %q but should have %q", + desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(), + ) + } + // TODO(beorn7): Simplify switch once Desc has type. + switch metricFamily.GetType() { + case dto.MetricType_COUNTER: + if dtoMetric.Counter == nil { + return fmt.Errorf( + "collected metric %s %s should be a Counter", + desc.fqName, dtoMetric, + ) + } + case dto.MetricType_GAUGE: + if dtoMetric.Gauge == nil { + return fmt.Errorf( + "collected metric %s %s should be a Gauge", + desc.fqName, dtoMetric, + ) } - metricFamiliesByName[desc.fqName] = metricFamily - } - if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes, dimHashes); err != nil { - errs = append(errs, err) - continue - } - if r.pedanticChecksEnabled { - // Is the desc registered at all? - if _, exist := registeredDescIDs[desc.id]; !exist { - errs = append(errs, fmt.Errorf( - "collected metric %s %s with unregistered descriptor %s", - metricFamily.GetName(), dtoMetric, desc, - )) - continue + case dto.MetricType_SUMMARY: + if dtoMetric.Summary == nil { + return fmt.Errorf( + "collected metric %s %s should be a Summary", + desc.fqName, dtoMetric, + ) } - if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil { - errs = append(errs, err) - continue + case dto.MetricType_UNTYPED: + if dtoMetric.Untyped == nil { + return fmt.Errorf( + "collected metric %s %s should be Untyped", + desc.fqName, dtoMetric, + ) } + case dto.MetricType_HISTOGRAM: + if dtoMetric.Histogram == nil { + return fmt.Errorf( + "collected metric %s %s should be a Histogram", + desc.fqName, dtoMetric, + ) + } + default: + panic("encountered MetricFamily with invalid type") + } + } else { // New name. + metricFamily = &dto.MetricFamily{} + metricFamily.Name = proto.String(desc.fqName) + metricFamily.Help = proto.String(desc.help) + // TODO(beorn7): Simplify switch once Desc has type. + switch { + case dtoMetric.Gauge != nil: + metricFamily.Type = dto.MetricType_GAUGE.Enum() + case dtoMetric.Counter != nil: + metricFamily.Type = dto.MetricType_COUNTER.Enum() + case dtoMetric.Summary != nil: + metricFamily.Type = dto.MetricType_SUMMARY.Enum() + case dtoMetric.Untyped != nil: + metricFamily.Type = dto.MetricType_UNTYPED.Enum() + case dtoMetric.Histogram != nil: + metricFamily.Type = dto.MetricType_HISTOGRAM.Enum() + default: + return fmt.Errorf("empty metric collected: %s", dtoMetric) + } + if err := checkSuffixCollisions(metricFamily, metricFamiliesByName); err != nil { + return err + } + metricFamiliesByName[desc.fqName] = metricFamily + } + if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes); err != nil { + return err + } + if registeredDescIDs != nil { + // Is the desc registered at all? + if _, exist := registeredDescIDs[desc.id]; !exist { + return fmt.Errorf( + "collected metric %s %s with unregistered descriptor %s", + metricFamily.GetName(), dtoMetric, desc, + ) + } + if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil { + return err } - metricFamily.Metric = append(metricFamily.Metric, dtoMetric) } - return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() + metricFamily.Metric = append(metricFamily.Metric, dtoMetric) + return nil } // Gatherers is a slice of Gatherer instances that implements the Gatherer @@ -537,7 +700,6 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { var ( metricFamiliesByName = map[string]*dto.MetricFamily{} metricHashes = map[uint64]struct{}{} - dimHashes = map[string]uint64{} errs MultiError // The collected errors to return in the end. ) @@ -574,10 +736,14 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { existingMF.Name = mf.Name existingMF.Help = mf.Help existingMF.Type = mf.Type + if err := checkSuffixCollisions(existingMF, metricFamiliesByName); err != nil { + errs = append(errs, err) + continue + } metricFamiliesByName[mf.GetName()] = existingMF } for _, m := range mf.Metric { - if err := checkMetricConsistency(existingMF, m, metricHashes, dimHashes); err != nil { + if err := checkMetricConsistency(existingMF, m, metricHashes); err != nil { errs = append(errs, err) continue } @@ -585,88 +751,80 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { } } } - return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() -} - -// metricSorter is a sortable slice of *dto.Metric. -type metricSorter []*dto.Metric - -func (s metricSorter) Len() int { - return len(s) -} - -func (s metricSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] + return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() } -func (s metricSorter) Less(i, j int) bool { - if len(s[i].Label) != len(s[j].Label) { - // This should not happen. The metrics are - // inconsistent. However, we have to deal with the fact, as - // people might use custom collectors or metric family injection - // to create inconsistent metrics. So let's simply compare the - // number of labels in this case. That will still yield - // reproducible sorting. - return len(s[i].Label) < len(s[j].Label) - } - for n, lp := range s[i].Label { - vi := lp.GetValue() - vj := s[j].Label[n].GetValue() - if vi != vj { - return vi < vj - } - } - - // We should never arrive here. Multiple metrics with the same - // label set in the same scrape will lead to undefined ingestion - // behavior. However, as above, we have to provide stable sorting - // here, even for inconsistent metrics. So sort equal metrics - // by their timestamp, with missing timestamps (implying "now") - // coming last. - if s[i].TimestampMs == nil { - return false - } - if s[j].TimestampMs == nil { - return true - } - return s[i].GetTimestampMs() < s[j].GetTimestampMs() -} - -// normalizeMetricFamilies returns a MetricFamily slice with empty -// MetricFamilies pruned and the remaining MetricFamilies sorted by name within -// the slice, with the contained Metrics sorted within each MetricFamily. -func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { - for _, mf := range metricFamiliesByName { - sort.Sort(metricSorter(mf.Metric)) +// checkSuffixCollisions checks for collisions with the “magic” suffixes the +// Prometheus text format and the internal metric representation of the +// Prometheus server add while flattening Summaries and Histograms. +func checkSuffixCollisions(mf *dto.MetricFamily, mfs map[string]*dto.MetricFamily) error { + var ( + newName = mf.GetName() + newType = mf.GetType() + newNameWithoutSuffix = "" + ) + switch { + case strings.HasSuffix(newName, "_count"): + newNameWithoutSuffix = newName[:len(newName)-6] + case strings.HasSuffix(newName, "_sum"): + newNameWithoutSuffix = newName[:len(newName)-4] + case strings.HasSuffix(newName, "_bucket"): + newNameWithoutSuffix = newName[:len(newName)-7] + } + if newNameWithoutSuffix != "" { + if existingMF, ok := mfs[newNameWithoutSuffix]; ok { + switch existingMF.GetType() { + case dto.MetricType_SUMMARY: + if !strings.HasSuffix(newName, "_bucket") { + return fmt.Errorf( + "collected metric named %q collides with previously collected summary named %q", + newName, newNameWithoutSuffix, + ) + } + case dto.MetricType_HISTOGRAM: + return fmt.Errorf( + "collected metric named %q collides with previously collected histogram named %q", + newName, newNameWithoutSuffix, + ) + } + } } - names := make([]string, 0, len(metricFamiliesByName)) - for name, mf := range metricFamiliesByName { - if len(mf.Metric) > 0 { - names = append(names, name) + if newType == dto.MetricType_SUMMARY || newType == dto.MetricType_HISTOGRAM { + if _, ok := mfs[newName+"_count"]; ok { + return fmt.Errorf( + "collected histogram or summary named %q collides with previously collected metric named %q", + newName, newName+"_count", + ) + } + if _, ok := mfs[newName+"_sum"]; ok { + return fmt.Errorf( + "collected histogram or summary named %q collides with previously collected metric named %q", + newName, newName+"_sum", + ) } } - sort.Strings(names) - result := make([]*dto.MetricFamily, 0, len(names)) - for _, name := range names { - result = append(result, metricFamiliesByName[name]) + if newType == dto.MetricType_HISTOGRAM { + if _, ok := mfs[newName+"_bucket"]; ok { + return fmt.Errorf( + "collected histogram named %q collides with previously collected metric named %q", + newName, newName+"_bucket", + ) + } } - return result + return nil } // checkMetricConsistency checks if the provided Metric is consistent with the -// provided MetricFamily. It also hashed the Metric labels and the MetricFamily -// name. If the resulting hash is alread in the provided metricHashes, an error -// is returned. If not, it is added to metricHashes. The provided dimHashes maps -// MetricFamily names to their dimHash (hashed sorted label names). If dimHashes -// doesn't yet contain a hash for the provided MetricFamily, it is -// added. Otherwise, an error is returned if the existing dimHashes in not equal -// the calculated dimHash. +// provided MetricFamily. It also hashes the Metric labels and the MetricFamily +// name. If the resulting hash is already in the provided metricHashes, an error +// is returned. If not, it is added to metricHashes. func checkMetricConsistency( metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, metricHashes map[uint64]struct{}, - dimHashes map[string]uint64, ) error { + name := metricFamily.GetName() + // Type consistency with metric family. if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || @@ -674,41 +832,65 @@ func checkMetricConsistency( metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil || metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { return fmt.Errorf( - "collected metric %s %s is not a %s", - metricFamily.GetName(), dtoMetric, metricFamily.GetType(), + "collected metric %q { %s} is not a %s", + name, dtoMetric, metricFamily.GetType(), ) } - // Is the metric unique (i.e. no other metric with the same name and the same label values)? + previousLabelName := "" + for _, labelPair := range dtoMetric.GetLabel() { + labelName := labelPair.GetName() + if labelName == previousLabelName { + return fmt.Errorf( + "collected metric %q { %s} has two or more labels with the same name: %s", + name, dtoMetric, labelName, + ) + } + if !checkLabelName(labelName) { + return fmt.Errorf( + "collected metric %q { %s} has a label with an invalid name: %s", + name, dtoMetric, labelName, + ) + } + if dtoMetric.Summary != nil && labelName == quantileLabel { + return fmt.Errorf( + "collected metric %q { %s} must not have an explicit %q label", + name, dtoMetric, quantileLabel, + ) + } + if !utf8.ValidString(labelPair.GetValue()) { + return fmt.Errorf( + "collected metric %q { %s} has a label named %q whose value is not utf8: %#v", + name, dtoMetric, labelName, labelPair.GetValue()) + } + previousLabelName = labelName + } + + // Is the metric unique (i.e. no other metric with the same name and the same labels)? h := hashNew() - h = hashAdd(h, metricFamily.GetName()) + h = hashAdd(h, name) h = hashAddByte(h, separatorByte) - dh := hashNew() // Make sure label pairs are sorted. We depend on it for the consistency // check. - sort.Sort(LabelPairSorter(dtoMetric.Label)) + if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { + // We cannot sort dtoMetric.Label in place as it is immutable by contract. + copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) + copy(copiedLabels, dtoMetric.Label) + sort.Sort(labelPairSorter(copiedLabels)) + dtoMetric.Label = copiedLabels + } for _, lp := range dtoMetric.Label { + h = hashAdd(h, lp.GetName()) + h = hashAddByte(h, separatorByte) h = hashAdd(h, lp.GetValue()) h = hashAddByte(h, separatorByte) - dh = hashAdd(dh, lp.GetName()) - dh = hashAddByte(dh, separatorByte) } if _, exists := metricHashes[h]; exists { return fmt.Errorf( - "collected metric %s %s was collected before with the same name and label values", - metricFamily.GetName(), dtoMetric, + "collected metric %q { %s} was collected before with the same name and label values", + name, dtoMetric, ) } - if dimHash, ok := dimHashes[metricFamily.GetName()]; ok { - if dimHash != dh { - return fmt.Errorf( - "collected metric %s %s has label dimensions inconsistent with previously collected metrics in the same metric family", - metricFamily.GetName(), dtoMetric, - ) - } - } else { - dimHashes[metricFamily.GetName()] = dh - } metricHashes[h] = struct{}{} return nil } @@ -727,8 +909,8 @@ func checkDescConsistency( } // Is the desc consistent with the content of the metric? - lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) - lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) + lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label)) + copy(lpsFromDesc, desc.constLabelPairs) for _, l := range desc.variableLabels { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), @@ -740,7 +922,7 @@ func checkDescConsistency( metricFamily.GetName(), dtoMetric, desc, ) } - sort.Sort(LabelPairSorter(lpsFromDesc)) + sort.Sort(labelPairSorter(lpsFromDesc)) for i, lpFromDesc := range lpsFromDesc { lpFromMetric := dtoMetric.Label[i] if lpFromDesc.GetName() != lpFromMetric.GetName() || diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index 1c65e25ece..2980614dff 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -36,7 +36,10 @@ const quantileLabel = "quantile" // // A typical use-case is the observation of request latencies. By default, a // Summary provides the median, the 90th and the 99th percentile of the latency -// as rank estimations. +// as rank estimations. However, the default behavior will change in the +// upcoming v0.10 of the library. There will be no rank estimations at all by +// default. For a sane transition, it is recommended to set the desired rank +// estimations explicitly. // // Note that the rank estimations cannot be aggregated in a meaningful way with // the Prometheus query language (i.e. you cannot average or add them). If you @@ -78,8 +81,10 @@ const ( ) // SummaryOpts bundles the options for creating a Summary metric. It is -// mandatory to set Name and Help to a non-empty string. All other fields are -// optional and can safely be left at their zero value. +// mandatory to set Name to a non-empty string. While all other fields are +// optional and can safely be left at their zero value, it is recommended to set +// a help string and to explicitly set the Objectives field to the desired value +// as the default value will change in the upcoming v0.10 of the library. type SummaryOpts struct { // Namespace, Subsystem, and Name are components of the fully-qualified // name of the Summary (created by joining these components with @@ -90,29 +95,27 @@ type SummaryOpts struct { Subsystem string Name string - // Help provides information about this Summary. Mandatory! + // Help provides information about this Summary. // // Metrics with the same fully-qualified name must have the same Help // string. Help string - // ConstLabels are used to attach fixed labels to this - // Summary. Summaries with the same fully-qualified name must have the - // same label names in their ConstLabels. + // ConstLabels are used to attach fixed labels to this metric. Metrics + // with the same fully-qualified name must have the same label names in + // their ConstLabels. // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a - // SummaryVec. ConstLabels serve only special purposes. One is for the - // special case where the value of a label does not change during the - // lifetime of a process, e.g. if the revision of the running binary is - // put into a label. Another, more advanced purpose is if more than one - // Collector needs to collect Summaries with the same fully-qualified - // name. In that case, those Summaries must differ in the values of - // their ConstLabels. See the Collector examples. + // Due to the way a Summary is represented in the Prometheus text format + // and how it is handled by the Prometheus server internally, “quantile” + // is an illegal label name. Construction of a Summary or SummaryVec + // will panic if this label name is used in ConstLabels. // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). + // ConstLabels are only used rarely. In particular, do not use them to + // attach the same labels to all your metrics. Those use cases are + // better covered by target labels set by the scraping Prometheus + // server, or by one specific metric (e.g. a build_info or a + // machine_role metric). See also + // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels ConstLabels Labels // Objectives defines the quantile rank estimates with their respective @@ -178,7 +181,7 @@ func NewSummary(opts SummaryOpts) Summary { func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -399,13 +402,21 @@ func (s quantSort) Less(i, j int) bool { // (e.g. HTTP request latencies, partitioned by status code and method). Create // instances with NewSummaryVec. type SummaryVec struct { - *MetricVec + *metricVec } // NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and -// partitioned by the given label names. At least one label name must be -// provided. +// partitioned by the given label names. +// +// Due to the way a Summary is represented in the Prometheus text format and how +// it is handled by the Prometheus server internally, “quantile” is an illegal +// label name. NewSummaryVec will panic if this label name is used. func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { + for _, ln := range labelNames { + if ln == quantileLabel { + panic(errQuantileLabelNotAllowed) + } + } desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, @@ -413,28 +424,58 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { opts.ConstLabels, ) return &SummaryVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { + metricVec: newMetricVec(desc, func(lvs ...string) Metric { return newSummary(desc, opts, lvs...) }), } } -// GetMetricWithLabelValues replaces the method of the same name in MetricVec. -// The difference is that this method returns an Observer and not a Metric so -// that no type conversion to an Observer is required. -func (m *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) +// GetMetricWithLabelValues returns the Summary for the given slice of label +// values (same order as the VariableLabels in Desc). If that combination of +// label values is accessed for the first time, a new Summary is created. +// +// It is possible to call this method without using the returned Summary to only +// create the new Summary but leave it at its starting value, a Summary without +// any observations. +// +// Keeping the Summary for later use is possible (and should be considered if +// performance is critical), but keep in mind that Reset, DeleteLabelValues and +// Delete can be used to delete the Summary from the SummaryVec. In that case, +// the Summary will still exist, but it will not be exported anymore, even if a +// Summary with the same label values is created later. See also the CounterVec +// example. +// +// An error is returned if the number of label values is not the same as the +// number of VariableLabels in Desc (minus any curried labels). +// +// Note that for more than one label value, this method is prone to mistakes +// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as +// an alternative to avoid that type of mistake. For higher label numbers, the +// latter has a much more readable (albeit more verbose) syntax, but it comes +// with a performance overhead (for creating and processing the Labels map). +// See also the GaugeVec example. +func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { + metric, err := v.metricVec.getMetricWithLabelValues(lvs...) if metric != nil { return metric.(Observer), err } return nil, err } -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns an Observer and not a Metric so that -// no type conversion to an Observer is required. -func (m *SummaryVec) GetMetricWith(labels Labels) (Observer, error) { - metric, err := m.MetricVec.GetMetricWith(labels) +// GetMetricWith returns the Summary for the given Labels map (the label names +// must match those of the VariableLabels in Desc). If that label map is +// accessed for the first time, a new Summary is created. Implications of +// creating a Summary without using it and keeping the Summary for later use are +// the same as for GetMetricWithLabelValues. +// +// An error is returned if the number and names of the Labels are inconsistent +// with those of the VariableLabels in Desc (minus any curried labels). +// +// This method is used for the same purpose as +// GetMetricWithLabelValues(...string). See there for pros and cons of the two +// methods. +func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) { + metric, err := v.metricVec.getMetricWith(labels) if metric != nil { return metric.(Observer), err } @@ -442,18 +483,57 @@ func (m *SummaryVec) GetMetricWith(labels Labels) (Observer, error) { } // WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like +// GetMetricWithLabelValues would have returned an error. Not returning an +// error allows shortcuts like // myVec.WithLabelValues("404", "GET").Observe(42.21) -func (m *SummaryVec) WithLabelValues(lvs ...string) Observer { - return m.MetricVec.WithLabelValues(lvs...).(Observer) +func (v *SummaryVec) WithLabelValues(lvs ...string) Observer { + s, err := v.GetMetricWithLabelValues(lvs...) + if err != nil { + panic(err) + } + return s } // With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21) -func (m *SummaryVec) With(labels Labels) Observer { - return m.MetricVec.With(labels).(Observer) +// returned an error. Not returning an error allows shortcuts like +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) +func (v *SummaryVec) With(labels Labels) Observer { + s, err := v.GetMetricWith(labels) + if err != nil { + panic(err) + } + return s +} + +// CurryWith returns a vector curried with the provided labels, i.e. the +// returned vector has those labels pre-set for all labeled operations performed +// on it. The cardinality of the curried vector is reduced accordingly. The +// order of the remaining labels stays the same (just with the curried labels +// taken out of the sequence – which is relevant for the +// (GetMetric)WithLabelValues methods). It is possible to curry a curried +// vector, but only with labels not yet used for currying before. +// +// The metrics contained in the SummaryVec are shared between the curried and +// uncurried vectors. They are just accessed differently. Curried and uncurried +// vectors behave identically in terms of collection. Only one must be +// registered with a given registry (usually the uncurried version). The Reset +// method deletes all metrics, even if called on a curried vector. +func (v *SummaryVec) CurryWith(labels Labels) (ObserverVec, error) { + vec, err := v.curryWith(labels) + if vec != nil { + return &SummaryVec{vec}, err + } + return nil, err +} + +// MustCurryWith works as CurryWith but panics where CurryWith would have +// returned an error. +func (v *SummaryVec) MustCurryWith(labels Labels) ObserverVec { + vec, err := v.CurryWith(labels) + if err != nil { + panic(err) + } + return vec } type constSummary struct { @@ -506,7 +586,7 @@ func (s *constSummary) Write(out *dto.Metric) error { // map[float64]float64{0.5: 0.23, 0.99: 0.56} // // NewConstSummary returns an error if the length of labelValues is not -// consistent with the variable labels in Desc. +// consistent with the variable labels in Desc or if Desc is invalid. func NewConstSummary( desc *Desc, count uint64, @@ -514,8 +594,11 @@ func NewConstSummary( quantiles map[float64]float64, labelValues ...string, ) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality + if desc.err != nil { + return nil, desc.err + } + if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + return nil, err } return &constSummary{ desc: desc, diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go index 12b65699b9..8d5f105233 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -39,10 +39,16 @@ func NewTimer(o Observer) *Timer { // ObserveDuration records the duration passed since the Timer was created with // NewTimer. It calls the Observe method of the Observer provided during -// construction with the duration in seconds as an argument. ObserveDuration is -// usually called with a defer statement. -func (t *Timer) ObserveDuration() { +// construction with the duration in seconds as an argument. The observed +// duration is also returned. ObserveDuration is usually called with a defer +// statement. +// +// Note that this method is only guaranteed to never observe negative durations +// if used with Go1.9+. +func (t *Timer) ObserveDuration() time.Duration { + d := time.Since(t.begin) if t.observer != nil { - t.observer.Observe(time.Since(t.begin).Seconds()) + t.observer.Observe(d.Seconds()) } + return d } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go index 065501d38f..0f9ce63f40 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go @@ -13,113 +13,12 @@ package prometheus -// Untyped is a Metric that represents a single numerical value that can -// arbitrarily go up and down. -// -// An Untyped metric works the same as a Gauge. The only difference is that to -// no type information is implied. -// -// To create Untyped instances, use NewUntyped. -// -// Deprecated: The Untyped type is deprecated because it doesn't make sense in -// direct instrumentation. If you need to mirror an external metric of unknown -// type (usually while writing exporters), Use MustNewConstMetric to create an -// untyped metric instance on the fly. -type Untyped interface { - Metric - Collector - - // Set sets the Untyped metric to an arbitrary value. - Set(float64) - // Inc increments the Untyped metric by 1. - Inc() - // Dec decrements the Untyped metric by 1. - Dec() - // Add adds the given value to the Untyped metric. (The value can be - // negative, resulting in a decrease.) - Add(float64) - // Sub subtracts the given value from the Untyped metric. (The value can - // be negative, resulting in an increase.) - Sub(float64) -} - // UntypedOpts is an alias for Opts. See there for doc comments. type UntypedOpts Opts -// NewUntyped creates a new Untyped metric from the provided UntypedOpts. -func NewUntyped(opts UntypedOpts) Untyped { - return newValue(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), UntypedValue, 0) -} - -// UntypedVec is a Collector that bundles a set of Untyped metrics that all -// share the same Desc, but have different values for their variable -// labels. This is used if you want to count the same thing partitioned by -// various dimensions. Create instances with NewUntypedVec. -type UntypedVec struct { - *MetricVec -} - -// NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &UntypedVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newValue(desc, UntypedValue, 0, lvs...) - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns an Untyped and not a -// Metric so that no type conversion is required. -func (m *UntypedVec) GetMetricWithLabelValues(lvs ...string) (Untyped, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Untyped), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns an Untyped and not a Metric so that no -// type conversion is required. -func (m *UntypedVec) GetMetricWith(labels Labels) (Untyped, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Untyped), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Add(42) -func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped { - return m.MetricVec.WithLabelValues(lvs...).(Untyped) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *UntypedVec) With(labels Labels) Untyped { - return m.MetricVec.With(labels).(Untyped) -} - -// UntypedFunc is an Untyped whose value is determined at collect time by -// calling a provided function. +// UntypedFunc works like GaugeFunc but the collected metric is of type +// "Untyped". UntypedFunc is useful to mirror an external metric of unknown +// type. // // To create UntypedFunc instances, use NewUntypedFunc. type UntypedFunc interface { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index ff75ce5851..eb248f1087 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -14,16 +14,12 @@ package prometheus import ( - "errors" "fmt" - "math" "sort" - "sync/atomic" - "time" - - dto "github.com/prometheus/client_model/go" "github.com/golang/protobuf/proto" + + dto "github.com/prometheus/client_model/go" ) // ValueType is an enumeration of metric types that represent a simple value. @@ -37,81 +33,6 @@ const ( UntypedValue ) -var errInconsistentCardinality = errors.New("inconsistent label cardinality") - -// value is a generic metric for simple values. It implements Metric, Collector, -// Counter, Gauge, and Untyped. Its effective type is determined by -// ValueType. This is a low-level building block used by the library to back the -// implementations of Counter, Gauge, and Untyped. -type value struct { - // valBits contains the bits of the represented float64 value. It has - // to go first in the struct to guarantee alignment for atomic - // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG - valBits uint64 - - selfCollector - - desc *Desc - valType ValueType - labelPairs []*dto.LabelPair -} - -// newValue returns a newly allocated value with the given Desc, ValueType, -// sample value and label values. It panics if the number of label -// values is different from the number of variable labels in Desc. -func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value { - if len(labelValues) != len(desc.variableLabels) { - panic(errInconsistentCardinality) - } - result := &value{ - desc: desc, - valType: valueType, - valBits: math.Float64bits(val), - labelPairs: makeLabelPairs(desc, labelValues), - } - result.init(result) - return result -} - -func (v *value) Desc() *Desc { - return v.desc -} - -func (v *value) Set(val float64) { - atomic.StoreUint64(&v.valBits, math.Float64bits(val)) -} - -func (v *value) SetToCurrentTime() { - v.Set(float64(time.Now().UnixNano()) / 1e9) -} - -func (v *value) Inc() { - v.Add(1) -} - -func (v *value) Dec() { - v.Add(-1) -} - -func (v *value) Add(val float64) { - for { - oldBits := atomic.LoadUint64(&v.valBits) - newBits := math.Float64bits(math.Float64frombits(oldBits) + val) - if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) { - return - } - } -} - -func (v *value) Sub(val float64) { - v.Add(val * -1) -} - -func (v *value) Write(out *dto.Metric) error { - val := math.Float64frombits(atomic.LoadUint64(&v.valBits)) - return populateMetric(v.valType, val, v.labelPairs, out) -} - // valueFunc is a generic metric for simple values retrieved on collect time // from a function. It implements Metric and Collector. Its effective type is // determined by ValueType. This is a low-level building block used by the @@ -156,10 +77,14 @@ func (v *valueFunc) Write(out *dto.Metric) error { // operations. However, when implementing custom Collectors, it is useful as a // throw-away metric that is generated on the fly to send it to Prometheus in // the Collect method. NewConstMetric returns an error if the length of -// labelValues is not consistent with the variable labels in Desc. +// labelValues is not consistent with the variable labels in Desc or if Desc is +// invalid. func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality + if desc.err != nil { + return nil, desc.err + } + if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + return nil, err } return &constMetric{ desc: desc, @@ -231,9 +156,7 @@ func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { Value: proto.String(labelValues[i]), }) } - for _, lp := range desc.constLabelPairs { - labelPairs = append(labelPairs, lp) - } - sort.Sort(LabelPairSorter(labelPairs)) + labelPairs = append(labelPairs, desc.constLabelPairs...) + sort.Sort(labelPairSorter(labelPairs)) return labelPairs } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go index 7f3eef9a46..14ed9e856d 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/vec.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/vec.go @@ -20,200 +20,253 @@ import ( "github.com/prometheus/common/model" ) -// MetricVec is a Collector to bundle metrics of the same name that -// differ in their label values. MetricVec is usually not used directly but as a -// building block for implementations of vectors of a given metric -// type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already -// provided in this package. -type MetricVec struct { - mtx sync.RWMutex // Protects the children. - children map[uint64][]metricWithLabelValues - desc *Desc - - newMetric func(labelValues ...string) Metric - hashAdd func(h uint64, s string) uint64 // replace hash function for testing collision handling +// metricVec is a Collector to bundle metrics of the same name that differ in +// their label values. metricVec is not used directly (and therefore +// unexported). It is used as a building block for implementations of vectors of +// a given metric type, like GaugeVec, CounterVec, SummaryVec, and HistogramVec. +// It also handles label currying. It uses basicMetricVec internally. +type metricVec struct { + *metricMap + + curry []curriedLabelValue + + // hashAdd and hashAddByte can be replaced for testing collision handling. + hashAdd func(h uint64, s string) uint64 hashAddByte func(h uint64, b byte) uint64 } -// newMetricVec returns an initialized MetricVec. The concrete value is -// returned for embedding into another struct. -func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec { - return &MetricVec{ - children: map[uint64][]metricWithLabelValues{}, - desc: desc, - newMetric: newMetric, +// newMetricVec returns an initialized metricVec. +func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec { + return &metricVec{ + metricMap: &metricMap{ + metrics: map[uint64][]metricWithLabelValues{}, + desc: desc, + newMetric: newMetric, + }, hashAdd: hashAdd, hashAddByte: hashAddByte, } } -// metricWithLabelValues provides the metric and its label values for -// disambiguation on hash collision. -type metricWithLabelValues struct { - values []string - metric Metric -} +// DeleteLabelValues removes the metric where the variable labels are the same +// as those passed in as labels (same order as the VariableLabels in Desc). It +// returns true if a metric was deleted. +// +// It is not an error if the number of label values is not the same as the +// number of VariableLabels in Desc. However, such inconsistent label count can +// never match an actual metric, so the method will always return false in that +// case. +// +// Note that for more than one label value, this method is prone to mistakes +// caused by an incorrect order of arguments. Consider Delete(Labels) as an +// alternative to avoid that type of mistake. For higher label numbers, the +// latter has a much more readable (albeit more verbose) syntax, but it comes +// with a performance overhead (for creating and processing the Labels map). +// See also the CounterVec example. +func (m *metricVec) DeleteLabelValues(lvs ...string) bool { + h, err := m.hashLabelValues(lvs) + if err != nil { + return false + } -// Describe implements Collector. The length of the returned slice -// is always one. -func (m *MetricVec) Describe(ch chan<- *Desc) { - ch <- m.desc + return m.metricMap.deleteByHashWithLabelValues(h, lvs, m.curry) } -// Collect implements Collector. -func (m *MetricVec) Collect(ch chan<- Metric) { - m.mtx.RLock() - defer m.mtx.RUnlock() +// Delete deletes the metric where the variable labels are the same as those +// passed in as labels. It returns true if a metric was deleted. +// +// It is not an error if the number and names of the Labels are inconsistent +// with those of the VariableLabels in Desc. However, such inconsistent Labels +// can never match an actual metric, so the method will always return false in +// that case. +// +// This method is used for the same purpose as DeleteLabelValues(...string). See +// there for pros and cons of the two methods. +func (m *metricVec) Delete(labels Labels) bool { + h, err := m.hashLabels(labels) + if err != nil { + return false + } - for _, metrics := range m.children { - for _, metric := range metrics { - ch <- metric.metric + return m.metricMap.deleteByHashWithLabels(h, labels, m.curry) +} + +func (m *metricVec) curryWith(labels Labels) (*metricVec, error) { + var ( + newCurry []curriedLabelValue + oldCurry = m.curry + iCurry int + ) + for i, label := range m.desc.variableLabels { + val, ok := labels[label] + if iCurry < len(oldCurry) && oldCurry[iCurry].index == i { + if ok { + return nil, fmt.Errorf("label name %q is already curried", label) + } + newCurry = append(newCurry, oldCurry[iCurry]) + iCurry++ + } else { + if !ok { + continue // Label stays uncurried. + } + newCurry = append(newCurry, curriedLabelValue{i, val}) } } + if l := len(oldCurry) + len(labels) - len(newCurry); l > 0 { + return nil, fmt.Errorf("%d unknown label(s) found during currying", l) + } + + return &metricVec{ + metricMap: m.metricMap, + curry: newCurry, + hashAdd: m.hashAdd, + hashAddByte: m.hashAddByte, + }, nil } -// GetMetricWithLabelValues returns the Metric for the given slice of label -// values (same order as the VariableLabels in Desc). If that combination of -// label values is accessed for the first time, a new Metric is created. -// -// It is possible to call this method without using the returned Metric to only -// create the new Metric but leave it at its start value (e.g. a Summary or -// Histogram without any observations). See also the SummaryVec example. -// -// Keeping the Metric for later use is possible (and should be considered if -// performance is critical), but keep in mind that Reset, DeleteLabelValues and -// Delete can be used to delete the Metric from the MetricVec. In that case, the -// Metric will still exist, but it will not be exported anymore, even if a -// Metric with the same label values is created later. See also the CounterVec -// example. -// -// An error is returned if the number of label values is not the same as the -// number of VariableLabels in Desc. -// -// Note that for more than one label value, this method is prone to mistakes -// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as -// an alternative to avoid that type of mistake. For higher label numbers, the -// latter has a much more readable (albeit more verbose) syntax, but it comes -// with a performance overhead (for creating and processing the Labels map). -// See also the GaugeVec example. -func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) { +func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) { h, err := m.hashLabelValues(lvs) if err != nil { return nil, err } - return m.getOrCreateMetricWithLabelValues(h, lvs), nil + return m.metricMap.getOrCreateMetricWithLabelValues(h, lvs, m.curry), nil } -// GetMetricWith returns the Metric for the given Labels map (the label names -// must match those of the VariableLabels in Desc). If that label map is -// accessed for the first time, a new Metric is created. Implications of -// creating a Metric without using it and keeping the Metric for later use are -// the same as for GetMetricWithLabelValues. -// -// An error is returned if the number and names of the Labels are inconsistent -// with those of the VariableLabels in Desc. -// -// This method is used for the same purpose as -// GetMetricWithLabelValues(...string). See there for pros and cons of the two -// methods. -func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) { +func (m *metricVec) getMetricWith(labels Labels) (Metric, error) { h, err := m.hashLabels(labels) if err != nil { return nil, err } - return m.getOrCreateMetricWithLabels(h, labels), nil + return m.metricMap.getOrCreateMetricWithLabels(h, labels, m.curry), nil } -// WithLabelValues works as GetMetricWithLabelValues, but panics if an error -// occurs. The method allows neat syntax like: -// httpReqs.WithLabelValues("404", "POST").Inc() -func (m *MetricVec) WithLabelValues(lvs ...string) Metric { - metric, err := m.GetMetricWithLabelValues(lvs...) - if err != nil { - panic(err) +func (m *metricVec) hashLabelValues(vals []string) (uint64, error) { + if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil { + return 0, err + } + + var ( + h = hashNew() + curry = m.curry + iVals, iCurry int + ) + for i := 0; i < len(m.desc.variableLabels); i++ { + if iCurry < len(curry) && curry[iCurry].index == i { + h = m.hashAdd(h, curry[iCurry].value) + iCurry++ + } else { + h = m.hashAdd(h, vals[iVals]) + iVals++ + } + h = m.hashAddByte(h, model.SeparatorByte) } - return metric + return h, nil } -// With works as GetMetricWith, but panics if an error occurs. The method allows -// neat syntax like: -// httpReqs.With(Labels{"status":"404", "method":"POST"}).Inc() -func (m *MetricVec) With(labels Labels) Metric { - metric, err := m.GetMetricWith(labels) - if err != nil { - panic(err) +func (m *metricVec) hashLabels(labels Labels) (uint64, error) { + if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil { + return 0, err } - return metric + + var ( + h = hashNew() + curry = m.curry + iCurry int + ) + for i, label := range m.desc.variableLabels { + val, ok := labels[label] + if iCurry < len(curry) && curry[iCurry].index == i { + if ok { + return 0, fmt.Errorf("label name %q is already curried", label) + } + h = m.hashAdd(h, curry[iCurry].value) + iCurry++ + } else { + if !ok { + return 0, fmt.Errorf("label name %q missing in label map", label) + } + h = m.hashAdd(h, val) + } + h = m.hashAddByte(h, model.SeparatorByte) + } + return h, nil } -// DeleteLabelValues removes the metric where the variable labels are the same -// as those passed in as labels (same order as the VariableLabels in Desc). It -// returns true if a metric was deleted. -// -// It is not an error if the number of label values is not the same as the -// number of VariableLabels in Desc. However, such inconsistent label count can -// never match an actual Metric, so the method will always return false in that -// case. -// -// Note that for more than one label value, this method is prone to mistakes -// caused by an incorrect order of arguments. Consider Delete(Labels) as an -// alternative to avoid that type of mistake. For higher label numbers, the -// latter has a much more readable (albeit more verbose) syntax, but it comes -// with a performance overhead (for creating and processing the Labels map). -// See also the CounterVec example. -func (m *MetricVec) DeleteLabelValues(lvs ...string) bool { - m.mtx.Lock() - defer m.mtx.Unlock() +// metricWithLabelValues provides the metric and its label values for +// disambiguation on hash collision. +type metricWithLabelValues struct { + values []string + metric Metric +} - h, err := m.hashLabelValues(lvs) - if err != nil { - return false +// curriedLabelValue sets the curried value for a label at the given index. +type curriedLabelValue struct { + index int + value string +} + +// metricMap is a helper for metricVec and shared between differently curried +// metricVecs. +type metricMap struct { + mtx sync.RWMutex // Protects metrics. + metrics map[uint64][]metricWithLabelValues + desc *Desc + newMetric func(labelValues ...string) Metric +} + +// Describe implements Collector. It will send exactly one Desc to the provided +// channel. +func (m *metricMap) Describe(ch chan<- *Desc) { + ch <- m.desc +} + +// Collect implements Collector. +func (m *metricMap) Collect(ch chan<- Metric) { + m.mtx.RLock() + defer m.mtx.RUnlock() + + for _, metrics := range m.metrics { + for _, metric := range metrics { + ch <- metric.metric + } } - return m.deleteByHashWithLabelValues(h, lvs) } -// Delete deletes the metric where the variable labels are the same as those -// passed in as labels. It returns true if a metric was deleted. -// -// It is not an error if the number and names of the Labels are inconsistent -// with those of the VariableLabels in the Desc of the MetricVec. However, such -// inconsistent Labels can never match an actual Metric, so the method will -// always return false in that case. -// -// This method is used for the same purpose as DeleteLabelValues(...string). See -// there for pros and cons of the two methods. -func (m *MetricVec) Delete(labels Labels) bool { +// Reset deletes all metrics in this vector. +func (m *metricMap) Reset() { m.mtx.Lock() defer m.mtx.Unlock() - h, err := m.hashLabels(labels) - if err != nil { - return false + for h := range m.metrics { + delete(m.metrics, h) } - - return m.deleteByHashWithLabels(h, labels) } // deleteByHashWithLabelValues removes the metric from the hash bucket h. If // there are multiple matches in the bucket, use lvs to select a metric and // remove only that metric. -func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool { - metrics, ok := m.children[h] +func (m *metricMap) deleteByHashWithLabelValues( + h uint64, lvs []string, curry []curriedLabelValue, +) bool { + m.mtx.Lock() + defer m.mtx.Unlock() + + metrics, ok := m.metrics[h] if !ok { return false } - i := m.findMetricWithLabelValues(metrics, lvs) + i := findMetricWithLabelValues(metrics, lvs, curry) if i >= len(metrics) { return false } if len(metrics) > 1 { - m.children[h] = append(metrics[:i], metrics[i+1:]...) + m.metrics[h] = append(metrics[:i], metrics[i+1:]...) } else { - delete(m.children, h) + delete(m.metrics, h) } return true } @@ -221,69 +274,38 @@ func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool { // deleteByHashWithLabels removes the metric from the hash bucket h. If there // are multiple matches in the bucket, use lvs to select a metric and remove // only that metric. -func (m *MetricVec) deleteByHashWithLabels(h uint64, labels Labels) bool { - metrics, ok := m.children[h] +func (m *metricMap) deleteByHashWithLabels( + h uint64, labels Labels, curry []curriedLabelValue, +) bool { + m.mtx.Lock() + defer m.mtx.Unlock() + + metrics, ok := m.metrics[h] if !ok { return false } - i := m.findMetricWithLabels(metrics, labels) + i := findMetricWithLabels(m.desc, metrics, labels, curry) if i >= len(metrics) { return false } if len(metrics) > 1 { - m.children[h] = append(metrics[:i], metrics[i+1:]...) + m.metrics[h] = append(metrics[:i], metrics[i+1:]...) } else { - delete(m.children, h) + delete(m.metrics, h) } return true } -// Reset deletes all metrics in this vector. -func (m *MetricVec) Reset() { - m.mtx.Lock() - defer m.mtx.Unlock() - - for h := range m.children { - delete(m.children, h) - } -} - -func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) { - if len(vals) != len(m.desc.variableLabels) { - return 0, errInconsistentCardinality - } - h := hashNew() - for _, val := range vals { - h = m.hashAdd(h, val) - h = m.hashAddByte(h, model.SeparatorByte) - } - return h, nil -} - -func (m *MetricVec) hashLabels(labels Labels) (uint64, error) { - if len(labels) != len(m.desc.variableLabels) { - return 0, errInconsistentCardinality - } - h := hashNew() - for _, label := range m.desc.variableLabels { - val, ok := labels[label] - if !ok { - return 0, fmt.Errorf("label name %q missing in label map", label) - } - h = m.hashAdd(h, val) - h = m.hashAddByte(h, model.SeparatorByte) - } - return h, nil -} - // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value // or creates it and returns the new one. // // This function holds the mutex. -func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric { +func (m *metricMap) getOrCreateMetricWithLabelValues( + hash uint64, lvs []string, curry []curriedLabelValue, +) Metric { m.mtx.RLock() - metric, ok := m.getMetricWithLabelValues(hash, lvs) + metric, ok := m.getMetricWithHashAndLabelValues(hash, lvs, curry) m.mtx.RUnlock() if ok { return metric @@ -291,13 +313,11 @@ func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) m.mtx.Lock() defer m.mtx.Unlock() - metric, ok = m.getMetricWithLabelValues(hash, lvs) + metric, ok = m.getMetricWithHashAndLabelValues(hash, lvs, curry) if !ok { - // Copy to avoid allocation in case wo don't go down this code path. - copiedLVs := make([]string, len(lvs)) - copy(copiedLVs, lvs) - metric = m.newMetric(copiedLVs...) - m.children[hash] = append(m.children[hash], metricWithLabelValues{values: copiedLVs, metric: metric}) + inlinedLVs := inlineLabelValues(lvs, curry) + metric = m.newMetric(inlinedLVs...) + m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: inlinedLVs, metric: metric}) } return metric } @@ -306,9 +326,11 @@ func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) // or creates it and returns the new one. // // This function holds the mutex. -func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric { +func (m *metricMap) getOrCreateMetricWithLabels( + hash uint64, labels Labels, curry []curriedLabelValue, +) Metric { m.mtx.RLock() - metric, ok := m.getMetricWithLabels(hash, labels) + metric, ok := m.getMetricWithHashAndLabels(hash, labels, curry) m.mtx.RUnlock() if ok { return metric @@ -316,33 +338,37 @@ func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metr m.mtx.Lock() defer m.mtx.Unlock() - metric, ok = m.getMetricWithLabels(hash, labels) + metric, ok = m.getMetricWithHashAndLabels(hash, labels, curry) if !ok { - lvs := m.extractLabelValues(labels) + lvs := extractLabelValues(m.desc, labels, curry) metric = m.newMetric(lvs...) - m.children[hash] = append(m.children[hash], metricWithLabelValues{values: lvs, metric: metric}) + m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: lvs, metric: metric}) } return metric } -// getMetricWithLabelValues gets a metric while handling possible collisions in -// the hash space. Must be called while holding read mutex. -func (m *MetricVec) getMetricWithLabelValues(h uint64, lvs []string) (Metric, bool) { - metrics, ok := m.children[h] +// getMetricWithHashAndLabelValues gets a metric while handling possible +// collisions in the hash space. Must be called while holding the read mutex. +func (m *metricMap) getMetricWithHashAndLabelValues( + h uint64, lvs []string, curry []curriedLabelValue, +) (Metric, bool) { + metrics, ok := m.metrics[h] if ok { - if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) { + if i := findMetricWithLabelValues(metrics, lvs, curry); i < len(metrics) { return metrics[i].metric, true } } return nil, false } -// getMetricWithLabels gets a metric while handling possible collisions in +// getMetricWithHashAndLabels gets a metric while handling possible collisions in // the hash space. Must be called while holding read mutex. -func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) { - metrics, ok := m.children[h] +func (m *metricMap) getMetricWithHashAndLabels( + h uint64, labels Labels, curry []curriedLabelValue, +) (Metric, bool) { + metrics, ok := m.metrics[h] if ok { - if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) { + if i := findMetricWithLabels(m.desc, metrics, labels, curry); i < len(metrics) { return metrics[i].metric, true } } @@ -351,9 +377,11 @@ func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) // findMetricWithLabelValues returns the index of the matching metric or // len(metrics) if not found. -func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int { +func findMetricWithLabelValues( + metrics []metricWithLabelValues, lvs []string, curry []curriedLabelValue, +) int { for i, metric := range metrics { - if m.matchLabelValues(metric.values, lvs) { + if matchLabelValues(metric.values, lvs, curry) { return i } } @@ -362,32 +390,51 @@ func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, l // findMetricWithLabels returns the index of the matching metric or len(metrics) // if not found. -func (m *MetricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int { +func findMetricWithLabels( + desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue, +) int { for i, metric := range metrics { - if m.matchLabels(metric.values, labels) { + if matchLabels(desc, metric.values, labels, curry) { return i } } return len(metrics) } -func (m *MetricVec) matchLabelValues(values []string, lvs []string) bool { - if len(values) != len(lvs) { +func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool { + if len(values) != len(lvs)+len(curry) { return false } + var iLVs, iCurry int for i, v := range values { - if v != lvs[i] { + if iCurry < len(curry) && curry[iCurry].index == i { + if v != curry[iCurry].value { + return false + } + iCurry++ + continue + } + if v != lvs[iLVs] { return false } + iLVs++ } return true } -func (m *MetricVec) matchLabels(values []string, labels Labels) bool { - if len(labels) != len(values) { +func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool { + if len(values) != len(labels)+len(curry) { return false } - for i, k := range m.desc.variableLabels { + iCurry := 0 + for i, k := range desc.variableLabels { + if iCurry < len(curry) && curry[iCurry].index == i { + if values[i] != curry[iCurry].value { + return false + } + iCurry++ + continue + } if values[i] != labels[k] { return false } @@ -395,10 +442,31 @@ func (m *MetricVec) matchLabels(values []string, labels Labels) bool { return true } -func (m *MetricVec) extractLabelValues(labels Labels) []string { - labelValues := make([]string, len(labels)) - for i, k := range m.desc.variableLabels { +func extractLabelValues(desc *Desc, labels Labels, curry []curriedLabelValue) []string { + labelValues := make([]string, len(labels)+len(curry)) + iCurry := 0 + for i, k := range desc.variableLabels { + if iCurry < len(curry) && curry[iCurry].index == i { + labelValues[i] = curry[iCurry].value + iCurry++ + continue + } labelValues[i] = labels[k] } return labelValues } + +func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string { + labelValues := make([]string, len(lvs)+len(curry)) + var iCurry, iLVs int + for i := range labelValues { + if iCurry < len(curry) && curry[iCurry].index == i { + labelValues[i] = curry[iCurry].value + iCurry++ + continue + } + labelValues[i] = lvs[iLVs] + iLVs++ + } + return labelValues +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go new file mode 100644 index 0000000000..49159bf3eb --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go @@ -0,0 +1,179 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "fmt" + "sort" + + "github.com/golang/protobuf/proto" + + dto "github.com/prometheus/client_model/go" +) + +// WrapRegistererWith returns a Registerer wrapping the provided +// Registerer. Collectors registered with the returned Registerer will be +// registered with the wrapped Registerer in a modified way. The modified +// Collector adds the provided Labels to all Metrics it collects (as +// ConstLabels). The Metrics collected by the unmodified Collector must not +// duplicate any of those labels. +// +// WrapRegistererWith provides a way to add fixed labels to a subset of +// Collectors. It should not be used to add fixed labels to all metrics exposed. +// +// The Collector example demonstrates a use of WrapRegistererWith. +func WrapRegistererWith(labels Labels, reg Registerer) Registerer { + return &wrappingRegisterer{ + wrappedRegisterer: reg, + labels: labels, + } +} + +// WrapRegistererWithPrefix returns a Registerer wrapping the provided +// Registerer. Collectors registered with the returned Registerer will be +// registered with the wrapped Registerer in a modified way. The modified +// Collector adds the provided prefix to the name of all Metrics it collects. +// +// WrapRegistererWithPrefix is useful to have one place to prefix all metrics of +// a sub-system. To make this work, register metrics of the sub-system with the +// wrapping Registerer returned by WrapRegistererWithPrefix. It is rarely useful +// to use the same prefix for all metrics exposed. In particular, do not prefix +// metric names that are standardized across applications, as that would break +// horizontal monitoring, for example the metrics provided by the Go collector +// (see NewGoCollector) and the process collector (see NewProcessCollector). (In +// fact, those metrics are already prefixed with “go_” or “process_”, +// respectively.) +func WrapRegistererWithPrefix(prefix string, reg Registerer) Registerer { + return &wrappingRegisterer{ + wrappedRegisterer: reg, + prefix: prefix, + } +} + +type wrappingRegisterer struct { + wrappedRegisterer Registerer + prefix string + labels Labels +} + +func (r *wrappingRegisterer) Register(c Collector) error { + return r.wrappedRegisterer.Register(&wrappingCollector{ + wrappedCollector: c, + prefix: r.prefix, + labels: r.labels, + }) +} + +func (r *wrappingRegisterer) MustRegister(cs ...Collector) { + for _, c := range cs { + if err := r.Register(c); err != nil { + panic(err) + } + } +} + +func (r *wrappingRegisterer) Unregister(c Collector) bool { + return r.wrappedRegisterer.Unregister(&wrappingCollector{ + wrappedCollector: c, + prefix: r.prefix, + labels: r.labels, + }) +} + +type wrappingCollector struct { + wrappedCollector Collector + prefix string + labels Labels +} + +func (c *wrappingCollector) Collect(ch chan<- Metric) { + wrappedCh := make(chan Metric) + go func() { + c.wrappedCollector.Collect(wrappedCh) + close(wrappedCh) + }() + for m := range wrappedCh { + ch <- &wrappingMetric{ + wrappedMetric: m, + prefix: c.prefix, + labels: c.labels, + } + } +} + +func (c *wrappingCollector) Describe(ch chan<- *Desc) { + wrappedCh := make(chan *Desc) + go func() { + c.wrappedCollector.Describe(wrappedCh) + close(wrappedCh) + }() + for desc := range wrappedCh { + ch <- wrapDesc(desc, c.prefix, c.labels) + } +} + +type wrappingMetric struct { + wrappedMetric Metric + prefix string + labels Labels +} + +func (m *wrappingMetric) Desc() *Desc { + return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels) +} + +func (m *wrappingMetric) Write(out *dto.Metric) error { + if err := m.wrappedMetric.Write(out); err != nil { + return err + } + if len(m.labels) == 0 { + // No wrapping labels. + return nil + } + for ln, lv := range m.labels { + out.Label = append(out.Label, &dto.LabelPair{ + Name: proto.String(ln), + Value: proto.String(lv), + }) + } + sort.Sort(labelPairSorter(out.Label)) + return nil +} + +func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { + constLabels := Labels{} + for _, lp := range desc.constLabelPairs { + constLabels[*lp.Name] = *lp.Value + } + for ln, lv := range labels { + if _, alreadyUsed := constLabels[ln]; alreadyUsed { + return &Desc{ + fqName: desc.fqName, + help: desc.help, + variableLabels: desc.variableLabels, + constLabelPairs: desc.constLabelPairs, + err: fmt.Errorf("attempted wrapping with already existing label name %q", ln), + } + } + constLabels[ln] = lv + } + // NewDesc will do remaining validations. + newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) + // Propagate errors if there was any. This will override any errer + // created by NewDesc above, i.e. earlier errors get precedence. + if desc.err != nil { + newDesc.err = desc.err + } + return newDesc +} diff --git a/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md b/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..e559c074bb --- /dev/null +++ b/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +Sorry, we do not accept changes directly against this repository. Please see +CONTRIBUTING.md for information on where and how to contribute instead. diff --git a/vendor/k8s.io/code-generator/CONTRIBUTING.md b/vendor/k8s.io/code-generator/CONTRIBUTING.md new file mode 100644 index 0000000000..bc4e7697e8 --- /dev/null +++ b/vendor/k8s.io/code-generator/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/code-generator](https://git.k8s.io/kubernetes/staging/src/k8s.io/code-generator) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/code-generator/Godeps/Godeps.json b/vendor/k8s.io/code-generator/Godeps/Godeps.json new file mode 100644 index 0000000000..4546feed41 --- /dev/null +++ b/vendor/k8s.io/code-generator/Godeps/Godeps.json @@ -0,0 +1,166 @@ +{ + "ImportPath": "k8s.io/code-generator", + "GoVersion": "go1.11", + "GodepVersion": "v80", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "github.com/gogo/protobuf/gogoproto", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/compare", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/defaultcheck", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/description", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/embedcheck", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/enumstringer", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/equal", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/face", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/gostring", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/marshalto", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/oneofcheck", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/populate", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/size", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/stringer", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/testgen", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/union", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/plugin/unmarshal", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/proto", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/generator", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/grpc", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/plugin", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/sortkeys", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/vanity", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/gogo/protobuf/vanity/command", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" + }, + { + "ImportPath": "github.com/spf13/pflag", + "Rev": "583c0c0531f06d5278b7d917446061adc344b5cd" + }, + { + "ImportPath": "golang.org/x/tools/go/ast/astutil", + "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" + }, + { + "ImportPath": "golang.org/x/tools/imports", + "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" + }, + { + "ImportPath": "k8s.io/gengo/args", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/examples/deepcopy-gen/generators", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/examples/defaulter-gen/generators", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/examples/import-boss/generators", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/examples/set-gen/generators", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/examples/set-gen/sets", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/generator", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/namer", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/parser", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/gengo/types", + "Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95" + }, + { + "ImportPath": "k8s.io/klog", + "Rev": "8139d8cb77af419532b33dfa7dd09fbc5f1d344f" + } + ] +} diff --git a/vendor/k8s.io/code-generator/Godeps/OWNERS b/vendor/k8s.io/code-generator/Godeps/OWNERS new file mode 100644 index 0000000000..3d49f30605 --- /dev/null +++ b/vendor/k8s.io/code-generator/Godeps/OWNERS @@ -0,0 +1,2 @@ +approvers: +- dep-approvers diff --git a/vendor/k8s.io/code-generator/Godeps/Readme b/vendor/k8s.io/code-generator/Godeps/Readme new file mode 100644 index 0000000000..4cdaa53d56 --- /dev/null +++ b/vendor/k8s.io/code-generator/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/vendor/k8s.io/code-generator/LICENSE b/vendor/k8s.io/code-generator/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/k8s.io/code-generator/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/k8s.io/code-generator/OWNERS b/vendor/k8s.io/code-generator/OWNERS new file mode 100644 index 0000000000..4155fc60cc --- /dev/null +++ b/vendor/k8s.io/code-generator/OWNERS @@ -0,0 +1,11 @@ +approvers: +- lavalamp +- wojtek-t +- sttts +reviewers: +- lavalamp +- wojtek-t +- sttts +labels: +- sig/api-machinery +- area/code-generation diff --git a/vendor/k8s.io/code-generator/README.md b/vendor/k8s.io/code-generator/README.md new file mode 100644 index 0000000000..5808c86b35 --- /dev/null +++ b/vendor/k8s.io/code-generator/README.md @@ -0,0 +1,24 @@ +# code-generator + +Golang code-generators used to implement [Kubernetes-style API types](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md). + +## Purpose + +These code-generators can be used +- in the context of [CustomResourceDefinition](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/) to build native, versioned clients, + informers and other helpers +- in the context of [User-provider API Servers](https://github.com/kubernetes/apiserver) to build conversions between internal and versioned types, defaulters, protobuf codecs, + internal and versioned clients and informers. + +## Resources +- The example [sample controller](https://github.com/kubernetes/sample-controller) shows a code example of a controller that uses the clients, listers and informers generated by this library. +- The article [Kubernetes Deep Dive: Code Generation for CustomResources](https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/) gives a step by step instruction on how to use this library. + +## Compatibility + +HEAD of this repo will match HEAD of k8s.io/apiserver, k8s.io/apimachinery, and k8s.io/client-go. + +## Where does it come from? + +`code-generator` is synced from https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/code-generator. +Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here. diff --git a/vendor/k8s.io/code-generator/SECURITY_CONTACTS b/vendor/k8s.io/code-generator/SECURITY_CONTACTS new file mode 100644 index 0000000000..0648a8ebff --- /dev/null +++ b/vendor/k8s.io/code-generator/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/doc.go new file mode 100644 index 0000000000..e6614c0da6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.crd.code-generator.k8s.io +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/register.go b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/register.go new file mode 100644 index 0000000000..58371e0e94 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/types.go b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/types.go new file mode 100644 index 0000000000..d79ea38b72 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/types.go @@ -0,0 +1,74 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta + metav1.ListMeta + Items []ClusterTestType +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/autoscaling.Scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..a3b4bfa9c2 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,177 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..cce2e603a6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/clientset.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/clientset.go new file mode 100644 index 0000000000..72931e51ed --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/clientset.go @@ -0,0 +1,98 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + examplev1 "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ExampleV1() examplev1.ExampleV1Interface + // Deprecated: please explicitly pick a version if possible. + Example() examplev1.ExampleV1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + exampleV1 *examplev1.ExampleV1Client +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Deprecated: Example retrieves the default version of ExampleClient. +// Please explicitly pick a version. +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.exampleV1, err = examplev1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/doc.go new file mode 100644 index 0000000000..41721ca52d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 0000000000..9a7307606c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,82 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/code-generator/_examples/MixedCase/clientset/versioned" + examplev1 "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// Example retrieves the ExampleV1Client +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/doc.go new file mode 100644 index 0000000000..9b99e71670 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/register.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/register.go new file mode 100644 index 0000000000..7fe8bc6a5f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/doc.go new file mode 100644 index 0000000000..7dc3756168 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/register.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/register.go new file mode 100644 index 0000000000..2cf84f85a9 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go new file mode 100644 index 0000000000..559ce47eb7 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go @@ -0,0 +1,210 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + scheme "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme" + autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(*v1.ClusterTestType) (*v1.ClusterTestType, error) + Update(*v1.ClusterTestType) (*v1.ClusterTestType, error) + UpdateStatus(*v1.ClusterTestType) (*v1.ClusterTestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.ClusterTestType, error) + List(opts metav1.ListOptions) (*v1.ClusterTestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) + GetScale(clusterTestTypeName string, options metav1.GetOptions) (*autoscaling.Scale, error) + UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (*autoscaling.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + client rest.Interface +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { + return &clusterTestTypes{ + client: c.RESTClient(), + } +} + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *clusterTestTypes) Get(name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Get(). + Resource("clustertesttypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *clusterTestTypes) List(opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.ClusterTestTypeList{} + err = c.client.Get(). + Resource("clustertesttypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *clusterTestTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("clustertesttypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *clusterTestTypes) Create(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Post(). + Resource("clustertesttypes"). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *clusterTestTypes) Update(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestType.Name). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *clusterTestTypes) UpdateStatus(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestType.Name). + SubResource("status"). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *clusterTestTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Resource("clustertesttypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *clusterTestTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("clustertesttypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *clusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Patch(pt). + Resource("clustertesttypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscaling.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(clusterTestTypeName string, options metav1.GetOptions) (result *autoscaling.Scale, err error) { + result = &autoscaling.Scale{} + err = c.client.Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { + result = &autoscaling.Scale{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + Body(scale). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 0000000000..3af5d054f1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 0000000000..9fdbf4aad1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,95 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + ClusterTestTypesGetter + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go new file mode 100644 index 0000000000..edf217df0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go @@ -0,0 +1,152 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleV1 +} + +var clustertesttypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "clustertesttypes"} + +var clustertesttypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "ClusterTestType"} + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(opts v1.ListOptions) (result *examplev1.ClusterTestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clustertesttypesResource, clustertesttypesKind, opts), &examplev1.ClusterTestTypeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &examplev1.ClusterTestTypeList{ListMeta: obj.(*examplev1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*examplev1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(clusterTestType *examplev1.ClusterTestType) (*examplev1.ClusterTestType, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "status", clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clustertesttypesResource, listOptions) + + _, err := c.Fake.Invokes(action, &examplev1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clustertesttypesResource, name, pt, data, subresources...), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(clusterTestTypeName string, options v1.GetOptions) (result *autoscaling.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceAction(clustertesttypesResource, "scale", clusterTestTypeName), &autoscaling.Scale{}) + if obj == nil { + return nil, err + } + return obj.(*autoscaling.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "scale", scale), &autoscaling.Scale{}) + if obj == nil { + return nil, err + } + return obj.(*autoscaling.Scale), err +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 0000000000..265930a0e4 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 0000000000..2ff811a969 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *examplev1.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &examplev1.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &examplev1.TestTypeList{ListMeta: obj.(*examplev1.TestTypeList).ListMeta} + for _, item := range obj.(*examplev1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *examplev1.TestType) (*examplev1.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &examplev1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 0000000000..3059734a9e --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 0000000000..9944e3e7c7 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + scheme "k8s.io/code-generator/_examples/MixedCase/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*v1.TestType) (*v1.TestType, error) + Update(*v1.TestType) (*v1.TestType, error) + UpdateStatus(*v1.TestType) (*v1.TestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.TestType, error) + List(opts metav1.ListOptions) (*v1.TestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/interface.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/interface.go new file mode 100644 index 0000000000..a874fdc5d8 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go new file mode 100644 index 0000000000..e0607c11a0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + versioned "k8s.io/code-generator/_examples/MixedCase/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/MixedCase/listers/example/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().Watch(options) + }, + }, + &examplev1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&examplev1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() v1.ClusterTestTypeLister { + return v1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/interface.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/interface.go new file mode 100644 index 0000000000..5389d07fbb --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/testtype.go new file mode 100644 index 0000000000..18f3b88d0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" + versioned "k8s.io/code-generator/_examples/MixedCase/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/MixedCase/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(options) + }, + }, + &examplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&examplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() v1.TestTypeLister { + return v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/factory.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/factory.go new file mode 100644 index 0000000000..5a2d8f7487 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/factory.go @@ -0,0 +1,180 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/MixedCase/clientset/versioned" + example "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/example" + internalinterfaces "k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Example() example.Interface +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/generic.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/generic.go new file mode 100644 index 0000000000..e039c8edfb --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/generic.go @@ -0,0 +1,64 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..2ed31b44dd --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/MixedCase/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/clustertesttype.go new file mode 100644 index 0000000000..8e93b73f91 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/clustertesttype.go @@ -0,0 +1,65 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + Get(name string) (*v1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + indexer cache.Indexer +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{indexer: indexer} +} + +// List lists all ClusterTestTypes in the indexer. +func (s *clusterTestTypeLister) List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.ClusterTestType)) + }) + return ret, err +} + +// Get retrieves the ClusterTestType from the index for a given name. +func (s *clusterTestTypeLister) Get(name string) (*v1.ClusterTestType, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("clustertesttype"), name) + } + return obj.(*v1.ClusterTestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/expansion_generated.go new file mode 100644 index 0000000000..2681a29f47 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/testtype.go new file mode 100644 index 0000000000..292dcedd0b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/MixedCase/listers/example/v1/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/MixedCase/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("testtype"), name) + } + return obj.(*v1.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go new file mode 100644 index 0000000000..3285a056fa --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=example.apiserver.code-generator.k8s.io + +package example // import "k8s.io/code-generator/_examples/apiserver/apis/example" diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go new file mode 100644 index 0000000000..d056c5b788 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/code-generator/_examples/apiserver/apis/example" + "k8s.io/code-generator/_examples/apiserver/apis/example/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(example.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go new file mode 100644 index 0000000000..da397b524a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package example + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.api.code-generator.k8s.io", Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go new file mode 100644 index 0000000000..b4fc976684 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go @@ -0,0 +1,44 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package example + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + metav1.ObjectMeta + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go new file mode 100644 index 0000000000..6b1fe6c119 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +k8s:conversion-gen=k8s.io/code-generator/_examples/apiserver/apis/example +// +groupName=example.apiserver.code-generator.k8s.io + +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go new file mode 100644 index 0000000000..c99619d7ac --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go new file mode 100644 index 0000000000..5c2ebc4d6f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go new file mode 100644 index 0000000000..ba47dbe2e6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go @@ -0,0 +1,137 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + example "k8s.io/code-generator/_examples/apiserver/apis/example" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_example_TestType(a.(*TestType), b.(*example.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestType_To_v1_TestType(a.(*example.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_example_TestTypeList(a.(*TestTypeList), b.(*example.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestTypeList_To_v1_TestTypeList(a.(*example.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_example_TestTypeStatus(a.(*TestTypeStatus), b.(*example.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestTypeStatus_To_v1_TestTypeStatus(a.(*example.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_example_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_example_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_example_TestType(in, out, s) +} + +func autoConvert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_example_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_example_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_example_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]example.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_example_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_example_TestTypeList(in, out, s) +} + +func autoConvert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_example_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_example_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_example_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in, out, s) +} + +func autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_example_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..dae52ff128 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,101 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..cce2e603a6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go new file mode 100644 index 0000000000..980112fa89 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go @@ -0,0 +1,101 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package example + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go new file mode 100644 index 0000000000..0edb56dcdd --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=example.test.apiserver.code-generator.k8s.io +// +groupGoName=SecondExample + +package example2 // import "k8s.io/code-generator/_examples/apiserver/apis/example2" diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go new file mode 100644 index 0000000000..1e786f5c53 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/code-generator/_examples/apiserver/apis/example2" + "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(example2.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go new file mode 100644 index 0000000000..508565af7a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package example2 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go new file mode 100644 index 0000000000..10219129be --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go @@ -0,0 +1,44 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package example2 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + metav1.ObjectMeta + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go new file mode 100644 index 0000000000..211aefc8c4 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.test.apiserver.code-generator.k8s.io +// +k8s:conversion-gen=k8s.io/code-generator/_examples/apiserver/apis/example2 +// +groupGoName=SecondExample + +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go new file mode 100644 index 0000000000..19dd0c356f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go new file mode 100644 index 0000000000..5c2ebc4d6f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go new file mode 100644 index 0000000000..5bf9a98e95 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go @@ -0,0 +1,137 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example2.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_example2_TestType(a.(*TestType), b.(*example2.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestType_To_v1_TestType(a.(*example2.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example2.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_example2_TestTypeList(a.(*TestTypeList), b.(*example2.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestTypeList_To_v1_TestTypeList(a.(*example2.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example2.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(a.(*TestTypeStatus), b.(*example2.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(a.(*example2.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_example2_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_example2_TestType(in, out, s) +} + +func autoConvert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_example2_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_example2_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]example2.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_example2_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_example2_TestTypeList(in, out, s) +} + +func autoConvert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_example2_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_example2_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_example2_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in, out, s) +} + +func autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_example2_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..dae52ff128 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go @@ -0,0 +1,101 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..cce2e603a6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go new file mode 100644 index 0000000000..f9b317e57c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go @@ -0,0 +1,101 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package example2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go new file mode 100644 index 0000000000..ff88d121cd --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go @@ -0,0 +1,104 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + exampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" + secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + Example() exampleinternalversion.ExampleInterface + SecondExample() secondexampleinternalversion.SecondExampleInterface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + example *exampleinternalversion.ExampleClient + secondExample *secondexampleinternalversion.SecondExampleClient +} + +// Example retrieves the ExampleClient +func (c *Clientset) Example() exampleinternalversion.ExampleInterface { + return c.example +} + +// SecondExample retrieves the SecondExampleClient +func (c *Clientset) SecondExample() secondexampleinternalversion.SecondExampleInterface { + return c.secondExample +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.example, err = exampleinternalversion.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + cs.secondExample, err = secondexampleinternalversion.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.example = exampleinternalversion.NewForConfigOrDie(c) + cs.secondExample = secondexampleinternalversion.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.example = exampleinternalversion.New(c) + cs.secondExample = secondexampleinternalversion.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go new file mode 100644 index 0000000000..6c970b092a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go new file mode 100644 index 0000000000..37f1b724dc --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go @@ -0,0 +1,84 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" + exampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" + fakeexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake" + secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" + fakesecondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// Example retrieves the ExampleClient +func (c *Clientset) Example() exampleinternalversion.ExampleInterface { + return &fakeexampleinternalversion.FakeExample{Fake: &c.Fake} +} + +// SecondExample retrieves the SecondExampleClient +func (c *Clientset) SecondExample() secondexampleinternalversion.SecondExampleInterface { + return &fakesecondexampleinternalversion.FakeSecondExample{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go new file mode 100644 index 0000000000..9b99e71670 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go new file mode 100644 index 0000000000..5713015ce5 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + exampleinternalversion "k8s.io/code-generator/_examples/apiserver/apis/example" + secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/apis/example2" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + exampleinternalversion.AddToScheme, + secondexampleinternalversion.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go new file mode 100644 index 0000000000..7dc3756168 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go new file mode 100644 index 0000000000..97b03068e3 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go @@ -0,0 +1,43 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + example "k8s.io/code-generator/_examples/apiserver/apis/example/install" + secondexample "k8s.io/code-generator/_examples/apiserver/apis/example2/install" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + Install(Scheme) +} + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + example.Install(scheme) + secondexample.Install(scheme) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go new file mode 100644 index 0000000000..86602442ba --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go new file mode 100644 index 0000000000..61d99cad02 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go @@ -0,0 +1,96 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + rest "k8s.io/client-go/rest" + "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" +) + +type ExampleInterface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// ExampleClient is used to interact with features provided by the example.apiserver.code-generator.k8s.io group. +type ExampleClient struct { + restClient rest.Interface +} + +func (c *ExampleClient) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleClient for the given config. +func NewForConfig(c *rest.Config) (*ExampleClient, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ExampleClient{client}, nil +} + +// NewForConfigOrDie creates a new ExampleClient for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleClient { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleClient for the given RESTClient. +func New(c rest.Interface) *ExampleClient { + return &ExampleClient{c} +} + +func setConfigDefaults(config *rest.Config) error { + config.APIPath = "/apis" + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + if config.GroupVersion == nil || config.GroupVersion.Group != scheme.Scheme.PrioritizedVersionsForGroup("example.apiserver.code-generator.k8s.io")[0].Group { + gv := scheme.Scheme.PrioritizedVersionsForGroup("example.apiserver.code-generator.k8s.io")[0] + config.GroupVersion = &gv + } + config.NegotiatedSerializer = scheme.Codecs + + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleClient) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go new file mode 100644 index 0000000000..90564e4490 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" +) + +type FakeExample struct { + *testing.Fake +} + +func (c *FakeExample) TestTypes(namespace string) internalversion.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExample) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go new file mode 100644 index 0000000000..abff7bb0d6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + example "k8s.io/code-generator/_examples/apiserver/apis/example" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExample + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.apiserver.code-generator.k8s.io", Version: "", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.apiserver.code-generator.k8s.io", Version: "", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &example.TestTypeList{ListMeta: obj.(*example.TestTypeList).ListMeta} + for _, item := range obj.(*example.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *example.TestType) (result *example.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *example.TestType) (result *example.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *example.TestType) (*example.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &example.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &example.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go new file mode 100644 index 0000000000..50bdbd254a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go new file mode 100644 index 0000000000..a06b946169 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + example "k8s.io/code-generator/_examples/apiserver/apis/example" + scheme "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*example.TestType) (*example.TestType, error) + Update(*example.TestType) (*example.TestType, error) + UpdateStatus(*example.TestType) (*example.TestType, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*example.TestType, error) + List(opts v1.ListOptions) (*example.TestTypeList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleClient, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options v1.GetOptions) (result *example.TestType, err error) { + result = &example.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts v1.ListOptions) (result *example.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &example.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *example.TestType) (result *example.TestType, err error) { + result = &example.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *example.TestType) (result *example.TestType, err error) { + result = &example.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *example.TestType) (result *example.TestType, err error) { + result = &example.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) { + result = &example.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go new file mode 100644 index 0000000000..86602442ba --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go new file mode 100644 index 0000000000..0fcc7baa42 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go @@ -0,0 +1,96 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + rest "k8s.io/client-go/rest" + "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" +) + +type SecondExampleInterface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// SecondExampleClient is used to interact with features provided by the example.test.apiserver.code-generator.k8s.io group. +type SecondExampleClient struct { + restClient rest.Interface +} + +func (c *SecondExampleClient) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new SecondExampleClient for the given config. +func NewForConfig(c *rest.Config) (*SecondExampleClient, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SecondExampleClient{client}, nil +} + +// NewForConfigOrDie creates a new SecondExampleClient for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SecondExampleClient { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SecondExampleClient for the given RESTClient. +func New(c rest.Interface) *SecondExampleClient { + return &SecondExampleClient{c} +} + +func setConfigDefaults(config *rest.Config) error { + config.APIPath = "/apis" + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + if config.GroupVersion == nil || config.GroupVersion.Group != scheme.Scheme.PrioritizedVersionsForGroup("example.test.apiserver.code-generator.k8s.io")[0].Group { + gv := scheme.Scheme.PrioritizedVersionsForGroup("example.test.apiserver.code-generator.k8s.io")[0] + config.GroupVersion = &gv + } + config.NegotiatedSerializer = scheme.Codecs + + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SecondExampleClient) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go new file mode 100644 index 0000000000..235305e9db --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" +) + +type FakeSecondExample struct { + *testing.Fake +} + +func (c *FakeSecondExample) TestTypes(namespace string) internalversion.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSecondExample) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go new file mode 100644 index 0000000000..0d63cf1033 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeSecondExample + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.test.apiserver.code-generator.k8s.io", Version: "", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.test.apiserver.code-generator.k8s.io", Version: "", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &example2.TestTypeList{ListMeta: obj.(*example2.TestTypeList).ListMeta} + for _, item := range obj.(*example2.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *example2.TestType) (result *example2.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *example2.TestType) (result *example2.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *example2.TestType) (*example2.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &example2.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &example2.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go new file mode 100644 index 0000000000..50bdbd254a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go new file mode 100644 index 0000000000..5380b86ce7 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" + scheme "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*example2.TestType) (*example2.TestType, error) + Update(*example2.TestType) (*example2.TestType, error) + UpdateStatus(*example2.TestType) (*example2.TestType, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*example2.TestType, error) + List(opts v1.ListOptions) (*example2.TestTypeList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *SecondExampleClient, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options v1.GetOptions) (result *example2.TestType, err error) { + result = &example2.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts v1.ListOptions) (result *example2.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &example2.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *example2.TestType) (result *example2.TestType, err error) { + result = &example2.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *example2.TestType) (result *example2.TestType, err error) { + result = &example2.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *example2.TestType) (result *example2.TestType, err error) { + result = &example2.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) { + result = &example2.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go new file mode 100644 index 0000000000..8ba9799f5b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + examplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ExampleV1() examplev1.ExampleV1Interface + // Deprecated: please explicitly pick a version if possible. + Example() examplev1.ExampleV1Interface + SecondExampleV1() secondexamplev1.SecondExampleV1Interface + // Deprecated: please explicitly pick a version if possible. + SecondExample() secondexamplev1.SecondExampleV1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + exampleV1 *examplev1.ExampleV1Client + secondExampleV1 *secondexamplev1.SecondExampleV1Client +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Deprecated: Example retrieves the default version of ExampleClient. +// Please explicitly pick a version. +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// Deprecated: SecondExample retrieves the default version of SecondExampleClient. +// Please explicitly pick a version. +func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.exampleV1, err = examplev1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + cs.secondExampleV1, err = secondexamplev1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.NewForConfigOrDie(c) + cs.secondExampleV1 = secondexamplev1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.New(c) + cs.secondExampleV1 = secondexamplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go new file mode 100644 index 0000000000..41721ca52d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 0000000000..6dce4fed44 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/code-generator/_examples/apiserver/clientset/versioned" + examplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake" + secondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" + fakesecondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// Example retrieves the ExampleV1Client +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} + +// SecondExample retrieves the SecondExampleV1Client +func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go new file mode 100644 index 0000000000..9b99e71670 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go new file mode 100644 index 0000000000..75282b82f0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go new file mode 100644 index 0000000000..7dc3756168 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go new file mode 100644 index 0000000000..e4c8dc1020 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 0000000000..3af5d054f1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 0000000000..743c8ded29 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.apiserver.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 0000000000..509a5b427a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 0000000000..f7e2aacdee --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.apiserver.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.apiserver.code-generator.k8s.io", Version: "v1", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *examplev1.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &examplev1.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &examplev1.TestTypeList{ListMeta: obj.(*examplev1.TestTypeList).ListMeta} + for _, item := range obj.(*examplev1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *examplev1.TestType) (*examplev1.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &examplev1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 0000000000..d513810d0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 0000000000..e25fd1fc21 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + scheme "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*v1.TestType) (*v1.TestType, error) + Update(*v1.TestType) (*v1.TestType, error) + UpdateStatus(*v1.TestType) (*v1.TestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.TestType, error) + List(opts metav1.ListOptions) (*v1.TestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go new file mode 100644 index 0000000000..3af5d054f1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go new file mode 100644 index 0000000000..1271c0f19f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" + "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" +) + +type SecondExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// SecondExampleV1Client is used to interact with features provided by the example.test.apiserver.code-generator.k8s.io group. +type SecondExampleV1Client struct { + restClient rest.Interface +} + +func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new SecondExampleV1Client for the given config. +func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SecondExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SecondExampleV1Client for the given RESTClient. +func New(c rest.Interface) *SecondExampleV1Client { + return &SecondExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SecondExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go new file mode 100644 index 0000000000..1820e182cd --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" +) + +type FakeSecondExampleV1 struct { + *testing.Fake +} + +func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSecondExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go new file mode 100644 index 0000000000..ce0782e6e0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeSecondExampleV1 + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2v1.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2v1.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &example2v1.TestTypeList{ListMeta: obj.(*example2v1.TestTypeList).ListMeta} + for _, item := range obj.(*example2v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *example2v1.TestType) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *example2v1.TestType) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *example2v1.TestType) (*example2v1.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &example2v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go new file mode 100644 index 0000000000..d513810d0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go new file mode 100644 index 0000000000..f5afee94cc --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" + scheme "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*v1.TestType) (*v1.TestType, error) + Update(*v1.TestType) (*v1.TestType, error) + UpdateStatus(*v1.TestType) (*v1.TestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.TestType, error) + List(opts metav1.ListOptions) (*v1.TestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go new file mode 100644 index 0000000000..9cc5d1b0a0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go new file mode 100644 index 0000000000..1ccc8f3ca0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go new file mode 100644 index 0000000000..025113612c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/apiserver/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(options) + }, + }, + &examplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&examplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() v1.TestTypeLister { + return v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go new file mode 100644 index 0000000000..3a791dd0fb --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go new file mode 100644 index 0000000000..1ccc8f3ca0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go new file mode 100644 index 0000000000..979ee4d589 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" + versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/apiserver/listers/example2/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).Watch(options) + }, + }, + &example2v1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&example2v1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() v1.TestTypeLister { + return v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go new file mode 100644 index 0000000000..fc4aa0d392 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go @@ -0,0 +1,186 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" + example "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example" + example2 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Example() example.Interface + SecondExample() example2.Interface +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) SecondExample() example2.Interface { + return example2.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go new file mode 100644 index 0000000000..feb7b2028f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go @@ -0,0 +1,67 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" + example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example.apiserver.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + // Group=example.test.apiserver.code-generator.k8s.io, Version=v1 + case example2v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..21c6669028 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go new file mode 100644 index 0000000000..d2a36b3c8e --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + internalversion "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // InternalVersion provides access to shared informers for resources in InternalVersion. + InternalVersion() internalversion.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// InternalVersion returns a new internalversion.Interface. +func (g *group) InternalVersion() internalversion.Interface { + return internalversion.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go new file mode 100644 index 0000000000..0fd5f8c3b9 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go new file mode 100644 index 0000000000..22d7610567 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + example "k8s.io/code-generator/_examples/apiserver/apis/example" + clientsetinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" + internalversion "k8s.io/code-generator/_examples/apiserver/listers/example/internalversion" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() internalversion.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.Example().TestTypes(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.Example().TestTypes(namespace).Watch(options) + }, + }, + &example.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client clientsetinternalversion.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&example.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() internalversion.TestTypeLister { + return internalversion.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go new file mode 100644 index 0000000000..9a5b411a1c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + internalversion "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // InternalVersion provides access to shared informers for resources in InternalVersion. + InternalVersion() internalversion.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// InternalVersion returns a new internalversion.Interface. +func (g *group) InternalVersion() internalversion.Interface { + return internalversion.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go new file mode 100644 index 0000000000..0fd5f8c3b9 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go new file mode 100644 index 0000000000..dcac2ce84b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" + clientsetinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" + internalversion "k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() internalversion.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExample().TestTypes(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExample().TestTypes(namespace).Watch(options) + }, + }, + &example2.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client clientsetinternalversion.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&example2.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() internalversion.TestTypeLister { + return internalversion.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go new file mode 100644 index 0000000000..ca6d4defe9 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go @@ -0,0 +1,186 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" + example "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example" + example2 "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2" + internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client internalversion.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client internalversion.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client internalversion.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client internalversion.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Example() example.Interface + SecondExample() example2.Interface +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) SecondExample() example2.Interface { + return example2.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go new file mode 100644 index 0000000000..046ccac959 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go @@ -0,0 +1,67 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalversion + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + example "k8s.io/code-generator/_examples/apiserver/apis/example" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example.apiserver.code-generator.k8s.io, Version=internalVersion + case example.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().InternalVersion().TestTypes().Informer()}, nil + + // Group=example.test.apiserver.code-generator.k8s.io, Version=internalVersion + case example2.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().InternalVersion().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..5d01820f9c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" +) + +// NewInformerFunc takes internalversion.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(internalversion.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go new file mode 100644 index 0000000000..4bb87150c0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package internalversion + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go new file mode 100644 index 0000000000..9daa91bbcf --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package internalversion + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + example "k8s.io/code-generator/_examples/apiserver/apis/example" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*example.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*example.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*example.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*example.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*example.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*example.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*example.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*example.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(example.Resource("testtype"), name) + } + return obj.(*example.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go new file mode 100644 index 0000000000..0192e05f0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go new file mode 100644 index 0000000000..a9b3d87c07 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("testtype"), name) + } + return obj.(*v1.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go new file mode 100644 index 0000000000..4bb87150c0 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package internalversion + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go new file mode 100644 index 0000000000..724e638718 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package internalversion + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*example2.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*example2.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*example2.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*example2.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*example2.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*example2.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*example2.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*example2.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(example2.Resource("testtype"), name) + } + return obj.(*example2.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go new file mode 100644 index 0000000000..0192e05f0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go new file mode 100644 index 0000000000..8aa178af88 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("testtype"), name) + } + return obj.(*v1.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go new file mode 100644 index 0000000000..673ac55d7b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.crd.code-generator.k8s.io + +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go new file mode 100644 index 0000000000..58371e0e94 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go new file mode 100644 index 0000000000..d79ea38b72 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go @@ -0,0 +1,74 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta + metav1.ListMeta + Items []ClusterTestType +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/autoscaling.Scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..a3b4bfa9c2 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,177 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..cce2e603a6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go new file mode 100644 index 0000000000..5d1cbec5ef --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.test.crd.code-generator.k8s.io +// +groupGoName=SecondExample + +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go new file mode 100644 index 0000000000..d0a852a310 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go new file mode 100644 index 0000000000..5c2ebc4d6f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..dae52ff128 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go @@ -0,0 +1,101 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go new file mode 100644 index 0000000000..cce2e603a6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go new file mode 100644 index 0000000000..034e06ad06 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + examplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ExampleV1() examplev1.ExampleV1Interface + // Deprecated: please explicitly pick a version if possible. + Example() examplev1.ExampleV1Interface + SecondExampleV1() secondexamplev1.SecondExampleV1Interface + // Deprecated: please explicitly pick a version if possible. + SecondExample() secondexamplev1.SecondExampleV1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + exampleV1 *examplev1.ExampleV1Client + secondExampleV1 *secondexamplev1.SecondExampleV1Client +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Deprecated: Example retrieves the default version of ExampleClient. +// Please explicitly pick a version. +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// Deprecated: SecondExample retrieves the default version of SecondExampleClient. +// Please explicitly pick a version. +func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.exampleV1, err = examplev1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + cs.secondExampleV1, err = secondexamplev1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.NewForConfigOrDie(c) + cs.secondExampleV1 = secondexamplev1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.New(c) + cs.secondExampleV1 = secondexamplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go new file mode 100644 index 0000000000..41721ca52d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 0000000000..4ad8bba757 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/code-generator/_examples/crd/clientset/versioned" + examplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake" + secondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" + fakesecondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// Example retrieves the ExampleV1Client +func (c *Clientset) Example() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} + +// SecondExample retrieves the SecondExampleV1Client +func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go new file mode 100644 index 0000000000..9b99e71670 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go new file mode 100644 index 0000000000..f3fd49d0da --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go new file mode 100644 index 0000000000..7dc3756168 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go new file mode 100644 index 0000000000..a98fc7ea77 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go new file mode 100644 index 0000000000..1217dd8673 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go @@ -0,0 +1,210 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" + autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(*v1.ClusterTestType) (*v1.ClusterTestType, error) + Update(*v1.ClusterTestType) (*v1.ClusterTestType, error) + UpdateStatus(*v1.ClusterTestType) (*v1.ClusterTestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.ClusterTestType, error) + List(opts metav1.ListOptions) (*v1.ClusterTestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) + GetScale(clusterTestTypeName string, options metav1.GetOptions) (*autoscaling.Scale, error) + UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (*autoscaling.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + client rest.Interface +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { + return &clusterTestTypes{ + client: c.RESTClient(), + } +} + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *clusterTestTypes) Get(name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Get(). + Resource("clustertesttypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *clusterTestTypes) List(opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.ClusterTestTypeList{} + err = c.client.Get(). + Resource("clustertesttypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *clusterTestTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("clustertesttypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *clusterTestTypes) Create(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Post(). + Resource("clustertesttypes"). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *clusterTestTypes) Update(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestType.Name). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *clusterTestTypes) UpdateStatus(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestType.Name). + SubResource("status"). + Body(clusterTestType). + Do(). + Into(result) + return +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *clusterTestTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Resource("clustertesttypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *clusterTestTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("clustertesttypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *clusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) { + result = &v1.ClusterTestType{} + err = c.client.Patch(pt). + Resource("clustertesttypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscaling.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(clusterTestTypeName string, options metav1.GetOptions) (result *autoscaling.Scale, err error) { + result = &autoscaling.Scale{} + err = c.client.Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { + result = &autoscaling.Scale{} + err = c.client.Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + Body(scale). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 0000000000..3af5d054f1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 0000000000..25d80728c9 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,95 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + ClusterTestTypesGetter + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go new file mode 100644 index 0000000000..92d87b12fb --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go @@ -0,0 +1,152 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleV1 +} + +var clustertesttypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "clustertesttypes"} + +var clustertesttypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "ClusterTestType"} + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(opts v1.ListOptions) (result *examplev1.ClusterTestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clustertesttypesResource, clustertesttypesKind, opts), &examplev1.ClusterTestTypeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &examplev1.ClusterTestTypeList{ListMeta: obj.(*examplev1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*examplev1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(clusterTestType *examplev1.ClusterTestType) (*examplev1.ClusterTestType, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "status", clusterTestType), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clustertesttypesResource, listOptions) + + _, err := c.Fake.Invokes(action, &examplev1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.ClusterTestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clustertesttypesResource, name, pt, data, subresources...), &examplev1.ClusterTestType{}) + if obj == nil { + return nil, err + } + return obj.(*examplev1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(clusterTestTypeName string, options v1.GetOptions) (result *autoscaling.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceAction(clustertesttypesResource, "scale", clusterTestTypeName), &autoscaling.Scale{}) + if obj == nil { + return nil, err + } + return obj.(*autoscaling.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "scale", scale), &autoscaling.Scale{}) + if obj == nil { + return nil, err + } + return obj.(*autoscaling.Scale), err +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 0000000000..e6aa99993f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 0000000000..3ef9885d2c --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *examplev1.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &examplev1.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &examplev1.TestTypeList{ListMeta: obj.(*examplev1.TestTypeList).ListMeta} + for _, item := range obj.(*examplev1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *examplev1.TestType) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *examplev1.TestType) (*examplev1.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &examplev1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &examplev1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &examplev1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*examplev1.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 0000000000..3059734a9e --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 0000000000..164b0510e4 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*v1.TestType) (*v1.TestType, error) + Update(*v1.TestType) (*v1.TestType, error) + UpdateStatus(*v1.TestType) (*v1.TestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.TestType, error) + List(opts metav1.ListOptions) (*v1.TestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go new file mode 100644 index 0000000000..3af5d054f1 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go new file mode 100644 index 0000000000..210b6509f6 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" + "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" +) + +type SecondExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// SecondExampleV1Client is used to interact with features provided by the example.test.crd.code-generator.k8s.io group. +type SecondExampleV1Client struct { + restClient rest.Interface +} + +func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new SecondExampleV1Client for the given config. +func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SecondExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SecondExampleV1Client for the given RESTClient. +func New(c rest.Interface) *SecondExampleV1Client { + return &SecondExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SecondExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go new file mode 100644 index 0000000000..16f4439906 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go new file mode 100644 index 0000000000..0d55a6b8ef --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" +) + +type FakeSecondExampleV1 struct { + *testing.Fake +} + +func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSecondExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go new file mode 100644 index 0000000000..c4efc6597d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go @@ -0,0 +1,140 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeSecondExampleV1 + ns string +} + +var testtypesResource = schema.GroupVersionResource{Group: "example.test.crd.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} + +var testtypesKind = schema.GroupVersionKind{Group: "example.test.crd.code-generator.k8s.io", Version: "v1", Kind: "TestType"} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2v1.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2v1.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &example2v1.TestTypeList{ListMeta: obj.(*example2v1.TestTypeList).ListMeta} + for _, item := range obj.(*example2v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(testType *example2v1.TestType) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(testType *example2v1.TestType) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(testType *example2v1.TestType) (*example2v1.TestType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &example2v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2v1.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, pt, data, subresources...), &example2v1.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*example2v1.TestType), err +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go new file mode 100644 index 0000000000..d513810d0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go new file mode 100644 index 0000000000..2e3194e00a --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go @@ -0,0 +1,191 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" + scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(*v1.TestType) (*v1.TestType, error) + Update(*v1.TestType) (*v1.TestType, error) + UpdateStatus(*v1.TestType) (*v1.TestType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.TestType, error) + List(opts metav1.ListOptions) (*v1.TestTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + client rest.Interface + ns string +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { + return &testTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("testtypes"). + Body(testType). + Do(). + Into(result) + return +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + Body(testType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("testtypes"). + Name(testType.Name). + SubResource("status"). + Body(testType). + Do(). + Into(result) + return +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched testType. +func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { + result = &v1.TestType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("testtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go new file mode 100644 index 0000000000..10c18944cc --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go new file mode 100644 index 0000000000..13c38e44fa --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/crd/listers/example/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().Watch(options) + }, + }, + &examplev1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&examplev1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() v1.ClusterTestTypeLister { + return v1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go new file mode 100644 index 0000000000..1e17b13255 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go new file mode 100644 index 0000000000..47ca5b2872 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/crd/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(options) + }, + }, + &examplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&examplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() v1.TestTypeLister { + return v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go new file mode 100644 index 0000000000..9e00c7b809 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go new file mode 100644 index 0000000000..024352284e --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go new file mode 100644 index 0000000000..eb99c32d04 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" + versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" + v1 "k8s.io/code-generator/_examples/crd/listers/example2/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).Watch(options) + }, + }, + &example2v1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&example2v1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() v1.TestTypeLister { + return v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go new file mode 100644 index 0000000000..7d6d1f9347 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go @@ -0,0 +1,186 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" + example "k8s.io/code-generator/_examples/crd/informers/externalversions/example" + example2 "k8s.io/code-generator/_examples/crd/informers/externalversions/example2" + internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Example() example.Interface + SecondExample() example2.Interface +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) SecondExample() example2.Interface { + return example2.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go new file mode 100644 index 0000000000..f6b1174c6e --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" + example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + // Group=example.test.crd.code-generator.k8s.io, Version=v1 + case example2v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..86d63f376f --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go new file mode 100644 index 0000000000..584b3b2735 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go @@ -0,0 +1,65 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + Get(name string) (*v1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + indexer cache.Indexer +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{indexer: indexer} +} + +// List lists all ClusterTestTypes in the indexer. +func (s *clusterTestTypeLister) List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.ClusterTestType)) + }) + return ret, err +} + +// Get retrieves the ClusterTestType from the index for a given name. +func (s *clusterTestTypeLister) Get(name string) (*v1.ClusterTestType, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("clustertesttype"), name) + } + return obj.(*v1.ClusterTestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go new file mode 100644 index 0000000000..2681a29f47 --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go new file mode 100644 index 0000000000..7055b6cc4b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("testtype"), name) + } + return obj.(*v1.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go new file mode 100644 index 0000000000..0192e05f0d --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go new file mode 100644 index 0000000000..d3b15c0b9b --- /dev/null +++ b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go @@ -0,0 +1,94 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" +) + +// TestTypeLister helps list TestTypes. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + indexer cache.Indexer +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{indexer: indexer} +} + +// List lists all TestTypes in the indexer. +func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + Get(name string) (*v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TestTypes in the indexer for a given namespace. +func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TestType)) + }) + return ret, err +} + +// Get retrieves the TestType from the indexer for a given namespace and name. +func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("testtype"), name) + } + return obj.(*v1.TestType), nil +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/OWNERS b/vendor/k8s.io/code-generator/cmd/client-gen/OWNERS new file mode 100644 index 0000000000..0c408a1aa9 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/OWNERS @@ -0,0 +1,8 @@ +approvers: +- lavalamp +- wojtek-t +- caesarxuchao +reviewers: +- lavalamp +- wojtek-t +- caesarxuchao diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/README.md b/vendor/k8s.io/code-generator/cmd/client-gen/README.md new file mode 100644 index 0000000000..d1d67abdf9 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/README.md @@ -0,0 +1,4 @@ +See [generating-clientset.md](https://git.k8s.io/community/contributors/devel/generating-clientset.md) + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/staging/src/k8s.io/code-generator/client-gen/README.md?pixel)]() diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/client-gen/args/args.go new file mode 100644 index 0000000000..f45be1bb83 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/args/args.go @@ -0,0 +1,120 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + "path" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + + "k8s.io/code-generator/cmd/client-gen/types" + codegenutil "k8s.io/code-generator/pkg/util" +) + +var DefaultInputDirs = []string{} + +// ClientGenArgs is a wrapper for arguments to client-gen. +type CustomArgs struct { + // A sorted list of group versions to generate. For each of them the package path is found + // in GroupVersionToInputPath. + Groups []types.GroupVersions + + // Overrides for which types should be included in the client. + IncludedTypesOverrides map[types.GroupVersion][]string + + // ClientsetName is the name of the clientset to be generated. It's + // populated from command-line arguments. + ClientsetName string + // ClientsetAPIPath is the default API HTTP path for generated clients. + ClientsetAPIPath string + // ClientsetOnly determines if we should generate the clients for groups and + // types along with the clientset. It's populated from command-line + // arguments. + ClientsetOnly bool + // FakeClient determines if client-gen generates the fake clients. + FakeClient bool +} + +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{ + ClientsetName: "internalclientset", + ClientsetAPIPath: "/apis", + ClientsetOnly: false, + FakeClient: true, + } + genericArgs.CustomArgs = customArgs + genericArgs.InputDirs = DefaultInputDirs + + if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 { + genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/clientset") + } + + return genericArgs, customArgs +} + +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet, inputBase string) { + gvsBuilder := NewGroupVersionsBuilder(&ca.Groups) + pflag.Var(NewGVPackagesValue(gvsBuilder, nil), "input", "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".") + pflag.Var(NewGVTypesValue(&ca.IncludedTypesOverrides, []string{}), "included-types-overrides", "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.") + pflag.Var(NewInputBasePathValue(gvsBuilder, inputBase), "input-base", "base path to look for the api group.") + pflag.StringVarP(&ca.ClientsetName, "clientset-name", "n", ca.ClientsetName, "the name of the generated clientset package.") + pflag.StringVarP(&ca.ClientsetAPIPath, "clientset-api-path", "", ca.ClientsetAPIPath, "the value of default API HTTP path, starting with / and without trailing /.") + pflag.BoolVar(&ca.ClientsetOnly, "clientset-only", ca.ClientsetOnly, "when set, client-gen only generates the clientset shell, without generating the individual typed clients") + pflag.BoolVar(&ca.FakeClient, "fake-clientset", ca.FakeClient, "when set, client-gen will generate the fake clientset that can be used in tests") + + // support old flags + fs.SetNormalizeFunc(mapFlagName("clientset-path", "output-package", fs.GetNormalizeFunc())) +} + +func Validate(genericArgs *args.GeneratorArgs) error { + customArgs := genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputPackagePath) == 0 { + return fmt.Errorf("output package cannot be empty") + } + if len(customArgs.ClientsetName) == 0 { + return fmt.Errorf("clientset name cannot be empty") + } + if len(customArgs.ClientsetAPIPath) == 0 { + return fmt.Errorf("clientset API path cannot be empty") + } + + return nil +} + +// GroupVersionPackages returns a map from GroupVersion to the package with the types.go. +func (ca *CustomArgs) GroupVersionPackages() map[types.GroupVersion]string { + res := map[types.GroupVersion]string{} + for _, pkg := range ca.Groups { + for _, v := range pkg.Versions { + res[types.GroupVersion{Group: pkg.Group, Version: v.Version}] = v.Package + } + } + return res +} + +func mapFlagName(from, to string, old func(fs *pflag.FlagSet, name string) pflag.NormalizedName) func(fs *pflag.FlagSet, name string) pflag.NormalizedName { + return func(fs *pflag.FlagSet, name string) pflag.NormalizedName { + if name == from { + name = to + } + return old(fs, name) + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages.go b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages.go new file mode 100644 index 0000000000..8da71d6f9b --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages.go @@ -0,0 +1,183 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "bytes" + "encoding/csv" + "flag" + "path" + "sort" + "strings" + + "k8s.io/code-generator/cmd/client-gen/types" +) + +type inputBasePathValue struct { + builder *groupVersionsBuilder +} + +var _ flag.Value = &inputBasePathValue{} + +func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue { + v := &inputBasePathValue{ + builder: builder, + } + v.Set(def) + return v +} + +func (s *inputBasePathValue) Set(val string) error { + s.builder.importBasePath = val + return s.builder.update() +} + +func (s *inputBasePathValue) Type() string { + return "string" +} + +func (s *inputBasePathValue) String() string { + return s.builder.importBasePath +} + +type gvPackagesValue struct { + builder *groupVersionsBuilder + groups []string + changed bool +} + +func NewGVPackagesValue(builder *groupVersionsBuilder, def []string) *gvPackagesValue { + gvp := new(gvPackagesValue) + gvp.builder = builder + if def != nil { + if err := gvp.set(def); err != nil { + panic(err) + } + } + return gvp +} + +var _ flag.Value = &gvPackagesValue{} + +func (s *gvPackagesValue) set(vs []string) error { + if s.changed { + s.groups = append(s.groups, vs...) + } else { + s.groups = append([]string(nil), vs...) + } + + s.builder.groups = s.groups + return s.builder.update() +} + +func (s *gvPackagesValue) Set(val string) error { + vs, err := readAsCSV(val) + if err != nil { + return err + } + if err := s.set(vs); err != nil { + return err + } + s.changed = true + return nil +} + +func (s *gvPackagesValue) Type() string { + return "stringSlice" +} + +func (s *gvPackagesValue) String() string { + str, _ := writeAsCSV(s.groups) + return "[" + str + "]" +} + +type groupVersionsBuilder struct { + value *[]types.GroupVersions + groups []string + importBasePath string +} + +func NewGroupVersionsBuilder(groups *[]types.GroupVersions) *groupVersionsBuilder { + return &groupVersionsBuilder{ + value: groups, + } +} + +func (p *groupVersionsBuilder) update() error { + var seenGroups = make(map[types.Group]*types.GroupVersions) + for _, v := range p.groups { + pth, gvString := parsePathGroupVersion(v) + gv, err := types.ToGroupVersion(gvString) + if err != nil { + return err + } + + versionPkg := types.PackageVersion{Package: path.Join(p.importBasePath, pth, gv.Group.NonEmpty(), gv.Version.String()), Version: gv.Version} + if group, ok := seenGroups[gv.Group]; ok { + seenGroups[gv.Group].Versions = append(group.Versions, versionPkg) + } else { + seenGroups[gv.Group] = &types.GroupVersions{ + PackageName: gv.Group.NonEmpty(), + Group: gv.Group, + Versions: []types.PackageVersion{versionPkg}, + } + } + } + + var groupNames []string + for groupName := range seenGroups { + groupNames = append(groupNames, groupName.String()) + } + sort.Strings(groupNames) + *p.value = []types.GroupVersions{} + for _, groupName := range groupNames { + *p.value = append(*p.value, *seenGroups[types.Group(groupName)]) + } + + return nil +} + +func parsePathGroupVersion(pgvString string) (gvPath string, gvString string) { + subs := strings.Split(pgvString, "/") + length := len(subs) + switch length { + case 0, 1, 2: + return "", pgvString + default: + return strings.Join(subs[:length-2], "/"), strings.Join(subs[length-2:], "/") + } +} + +func readAsCSV(val string) ([]string, error) { + if val == "" { + return []string{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + return csvReader.Read() +} + +func writeAsCSV(vals []string) (string, error) { + b := &bytes.Buffer{} + w := csv.NewWriter(b) + err := w.Write(vals) + if err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/args/gvtype.go b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvtype.go new file mode 100644 index 0000000000..e4e3ccb536 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvtype.go @@ -0,0 +1,110 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "flag" + "fmt" + "strings" + + "k8s.io/code-generator/cmd/client-gen/types" +) + +type gvTypeValue struct { + gvToTypes *map[types.GroupVersion][]string + changed bool +} + +func NewGVTypesValue(gvToTypes *map[types.GroupVersion][]string, def []string) *gvTypeValue { + gvt := new(gvTypeValue) + gvt.gvToTypes = gvToTypes + if def != nil { + if err := gvt.set(def); err != nil { + panic(err) + } + } + return gvt +} + +var _ flag.Value = &gvTypeValue{} + +func (s *gvTypeValue) set(vs []string) error { + if !s.changed { + *s.gvToTypes = map[types.GroupVersion][]string{} + } + + for _, input := range vs { + gvString, typeStr, err := parseGroupVersionType(input) + if err != nil { + return err + } + gv, err := types.ToGroupVersion(gvString) + if err != nil { + return err + } + types, ok := (*s.gvToTypes)[gv] + if !ok { + types = []string{} + } + types = append(types, typeStr) + (*s.gvToTypes)[gv] = types + } + + return nil +} + +func (s *gvTypeValue) Set(val string) error { + vs, err := readAsCSV(val) + if err != nil { + return err + } + if err := s.set(vs); err != nil { + return err + } + s.changed = true + return nil +} + +func (s *gvTypeValue) Type() string { + return "stringSlice" +} + +func (s *gvTypeValue) String() string { + strs := make([]string, 0, len(*s.gvToTypes)) + for gv, ts := range *s.gvToTypes { + for _, t := range ts { + strs = append(strs, gv.Group.String()+"/"+gv.Version.String()+"/"+t) + } + } + str, _ := writeAsCSV(strs) + return "[" + str + "]" +} + +func parseGroupVersionType(gvtString string) (gvString string, typeStr string, err error) { + invalidFormatErr := fmt.Errorf("invalid value: %s, should be of the form group/version/type", gvtString) + subs := strings.Split(gvtString, "/") + length := len(subs) + switch length { + case 2: + // gvtString of the form group/type, e.g. api/Service,extensions/ReplicaSet + return subs[0] + "/", subs[1], nil + case 3: + return strings.Join(subs[:length-1], "/"), subs[length-1], nil + default: + return "", "", invalidFormatErr + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/client_generator.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/client_generator.go new file mode 100644 index 0000000000..ee6ebbcf09 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/client_generator.go @@ -0,0 +1,426 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package generators has the generators for the client-gen utility. +package generators + +import ( + "path/filepath" + "strings" + + clientgenargs "k8s.io/code-generator/cmd/client-gen/args" + "k8s.io/code-generator/cmd/client-gen/generators/fake" + "k8s.io/code-generator/cmd/client-gen/generators/scheme" + "k8s.io/code-generator/cmd/client-gen/generators/util" + "k8s.io/code-generator/cmd/client-gen/path" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + lowercaseNamer := namer.NewAllLowercasePluralNamer(pluralExceptions) + + publicNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicNamer(0), + } + privateNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "eventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPrivateNamer(0), + } + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(pluralExceptions), + } + privatePluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "eventResource" + // these exceptions are used to deconflict the generated code + "k8s.io/apis/events/v1beta1.Event": "eventResources", + "k8s.io/kubernetes/pkg/apis/events.Event": "eventResources", + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPrivatePluralNamer(pluralExceptions), + } + + return namer.NameSystems{ + "singularKind": namer.NewPublicNamer(0), + "public": publicNamer, + "private": privateNamer, + "raw": namer.NewRawNamer("", nil), + "publicPlural": publicPluralNamer, + "privatePlural": privatePluralNamer, + "allLowercasePlural": lowercaseNamer, + "resource": NewTagOverrideNamer("resourceName", lowercaseNamer), + } +} + +// ExceptionNamer allows you specify exceptional cases with exact names. This allows you to have control +// for handling various conflicts, like group and resource names for instance. +type ExceptionNamer struct { + Exceptions map[string]string + KeyFunc func(*types.Type) string + + Delegate namer.Namer +} + +// Name provides the requested name for a type. +func (n *ExceptionNamer) Name(t *types.Type) string { + key := n.KeyFunc(t) + if exception, ok := n.Exceptions[key]; ok { + return exception + } + return n.Delegate.Name(t) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, apiPath string, srcTreePath string, inputPackage string, boilerplate []byte) generator.Package { + groupVersionClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty())) + return &generator.DefaultPackage{ + PackageName: strings.ToLower(gv.Version.NonEmpty()), + PackagePath: groupVersionClientPackage, + HeaderText: boilerplate, + PackageDocumentation: []byte( + `// This package has the automatically generated typed clients. +`), + // GeneratorFunc returns a list of generators. Each generator makes a + // single file. + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.DefaultGen{OptionalName: "doc"}, + } + // Since we want a file per type that we generate a client for, we + // have to provide a function for this. + for _, t := range typeList { + generators = append(generators, &genClientForType{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(c.Namers["private"].Name(t)), + }, + outputPackage: groupVersionClientPackage, + clientsetPackage: clientsetPackage, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + typeToMatch: t, + imports: generator.NewImportTracker(), + }) + } + + generators = append(generators, &genGroup{ + DefaultGen: generator.DefaultGen{ + OptionalName: groupPackageName + "_client", + }, + outputPackage: groupVersionClientPackage, + inputPackage: inputPackage, + clientsetPackage: clientsetPackage, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + apiPath: apiPath, + types: typeList, + imports: generator.NewImportTracker(), + }) + + expansionFileName := "generated_expansion" + generators = append(generators, &genExpansion{ + groupPackagePath: filepath.Join(srcTreePath, groupVersionClientPackage), + DefaultGen: generator.DefaultGen{ + OptionalName: expansionFileName, + }, + types: typeList, + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient + }, + } +} + +func packageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package { + return &generator.DefaultPackage{ + PackageName: customArgs.ClientsetName, + PackagePath: clientsetPackage, + HeaderText: boilerplate, + PackageDocumentation: []byte( + `// This package has the automatically generated clientset. +`), + // GeneratorFunc returns a list of generators. Each generator generates a + // single file. + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.DefaultGen{OptionalName: "doc"}, + + &genClientset{ + DefaultGen: generator.DefaultGen{ + OptionalName: "clientset", + }, + groups: customArgs.Groups, + groupGoNames: groupGoNames, + clientsetPackage: clientsetPackage, + outputPackage: customArgs.ClientsetName, + imports: generator.NewImportTracker(), + }, + } + return generators + }, + } +} + +func packageForScheme(customArgs *clientgenargs.CustomArgs, clientsetPackage string, srcTreePath string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package { + schemePackage := filepath.Join(clientsetPackage, "scheme") + + // create runtime.Registry for internal client because it has to know about group versions + internalClient := false +NextGroup: + for _, group := range customArgs.Groups { + for _, v := range group.Versions { + if v.String() == "" { + internalClient = true + break NextGroup + } + } + } + + return &generator.DefaultPackage{ + PackageName: "scheme", + PackagePath: schemePackage, + HeaderText: boilerplate, + PackageDocumentation: []byte( + `// This package contains the scheme of the automatically generated clientset. +`), + // GeneratorFunc returns a list of generators. Each generator generates a + // single file. + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.DefaultGen{OptionalName: "doc"}, + + &scheme.GenScheme{ + DefaultGen: generator.DefaultGen{ + OptionalName: "register", + }, + InputPackages: customArgs.GroupVersionPackages(), + OutputPackage: schemePackage, + OutputPath: filepath.Join(srcTreePath, schemePackage), + Groups: customArgs.Groups, + GroupGoNames: groupGoNames, + ImportTracker: generator.NewImportTracker(), + CreateRegistry: internalClient, + }, + } + return generators + }, + } +} + +// applyGroupOverrides applies group name overrides to each package, if applicable. If there is a +// comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", use the +// first field (somegroup) as the name of the group in Go code, e.g. as the func name in a clientset. +// +// If the first field of the groupName is not unique within the clientset, use "// +groupName=unique +func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.CustomArgs) { + // Create a map from "old GV" to "new GV" so we know what changes we need to make. + changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion) + for gv, inputDir := range customArgs.GroupVersionPackages() { + p := universe.Package(inputDir) + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + newGV := clientgentypes.GroupVersion{ + Group: clientgentypes.Group(override[0]), + Version: gv.Version, + } + changes[gv] = newGV + } + } + + // Modify customArgs.Groups based on the groupName overrides. + newGroups := make([]clientgentypes.GroupVersions, 0, len(customArgs.Groups)) + for _, gvs := range customArgs.Groups { + gv := clientgentypes.GroupVersion{ + Group: gvs.Group, + Version: gvs.Versions[0].Version, // we only need a version, and the first will do + } + if newGV, ok := changes[gv]; ok { + // There's an override, so use it. + newGVS := clientgentypes.GroupVersions{ + PackageName: gvs.PackageName, + Group: newGV.Group, + Versions: gvs.Versions, + } + newGroups = append(newGroups, newGVS) + } else { + // No override. + newGroups = append(newGroups, gvs) + } + } + customArgs.Groups = newGroups +} + +// Packages makes the client package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + customArgs, ok := arguments.CustomArgs.(*clientgenargs.CustomArgs) + if !ok { + klog.Fatalf("cannot convert arguments.CustomArgs to clientgenargs.CustomArgs") + } + includedTypesOverrides := customArgs.IncludedTypesOverrides + + applyGroupOverrides(context.Universe, customArgs) + + gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{} + groupGoNames := make(map[clientgentypes.GroupVersion]string) + for gv, inputDir := range customArgs.GroupVersionPackages() { + p := context.Universe.Package(path.Vendorless(inputDir)) + + // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as + // the Go group identifier in CamelCase. It defaults + groupGoNames[gv] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) + if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[gv] = namer.IC(override[0]) + } + + // Package are indexed with the vendor prefix stripped + for n, t := range p.Types { + // filter out types which are not included in user specified overrides. + typesOverride, ok := includedTypesOverrides[gv] + if ok { + found := false + for _, typeStr := range typesOverride { + if typeStr == n { + found = true + break + } + } + if !found { + continue + } + } else { + // User has not specified any override for this group version. + // filter out types which dont have genclient. + if tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)); !tags.GenerateClient { + continue + } + } + if _, found := gvToTypes[gv]; !found { + gvToTypes[gv] = []*types.Type{} + } + gvToTypes[gv] = append(gvToTypes[gv], t) + } + } + + var packageList []generator.Package + clientsetPackage := filepath.Join(arguments.OutputPackagePath, customArgs.ClientsetName) + + packageList = append(packageList, packageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate)) + packageList = append(packageList, packageForScheme(customArgs, clientsetPackage, arguments.OutputBase, groupGoNames, boilerplate)) + if customArgs.FakeClient { + packageList = append(packageList, fake.PackageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate)) + } + + // If --clientset-only=true, we don't regenerate the individual typed clients. + if customArgs.ClientsetOnly { + return generator.Packages(packageList) + } + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + gvPackages := customArgs.GroupVersionPackages() + for _, group := range customArgs.Groups { + for _, version := range group.Versions { + gv := clientgentypes.GroupVersion{Group: group.Group, Version: version.Version} + types := gvToTypes[gv] + inputPath := gvPackages[gv] + packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, boilerplate)) + if customArgs.FakeClient { + packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, boilerplate)) + } + } + } + + return generator.Packages(packageList) +} + +// tagOverrideNamer is a namer which pulls names from a given tag, if specified, +// and otherwise falls back to a different namer. +type tagOverrideNamer struct { + tagName string + fallback namer.Namer +} + +func (n *tagOverrideNamer) Name(t *types.Type) string { + if nameOverride := extractTag(n.tagName, append(t.SecondClosestCommentLines, t.CommentLines...)); nameOverride != "" { + return nameOverride + } + + return n.fallback.Name(t) +} + +// NewTagOverrideNamer creates a namer.Namer which uses the contents of the given tag as +// the name, or falls back to another Namer if the tag is not present. +func NewTagOverrideNamer(tagName string, fallback namer.Namer) namer.Namer { + return &tagOverrideNamer{ + tagName: tagName, + fallback: fallback, + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go new file mode 100644 index 0000000000..4b3854be6e --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go @@ -0,0 +1,130 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/types" + + clientgenargs "k8s.io/code-generator/cmd/client-gen/args" + scheme "k8s.io/code-generator/cmd/client-gen/generators/scheme" + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" +) + +func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, inputPackage string, boilerplate []byte) generator.Package { + outputPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()), "fake") + // TODO: should make this a function, called by here and in client-generator.go + realClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty())) + return &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: outputPackage, + HeaderText: boilerplate, + PackageDocumentation: []byte( + `// Package fake has the automatically generated clients. +`), + // GeneratorFunc returns a list of generators. Each generator makes a + // single file. + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.DefaultGen{OptionalName: "doc"}, + } + // Since we want a file per type that we generate a client for, we + // have to provide a function for this. + for _, t := range typeList { + generators = append(generators, &genFakeForType{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake_" + strings.ToLower(c.Namers["private"].Name(t)), + }, + outputPackage: outputPackage, + inputPackage: inputPackage, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + typeToMatch: t, + imports: generator.NewImportTracker(), + }) + } + + generators = append(generators, &genFakeForGroup{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake_" + groupPackageName + "_client", + }, + outputPackage: outputPackage, + realClientPackage: realClientPackage, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + types: typeList, + imports: generator.NewImportTracker(), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient + }, + } +} + +func PackageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package { + return &generator.DefaultPackage{ + // TODO: we'll generate fake clientset for different release in the future. + // Package name and path are hard coded for now. + PackageName: "fake", + PackagePath: filepath.Join(clientsetPackage, "fake"), + HeaderText: boilerplate, + PackageDocumentation: []byte( + `// This package has the automatically generated fake clientset. +`), + // GeneratorFunc returns a list of generators. Each generator generates a + // single file. + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.DefaultGen{OptionalName: "doc"}, + + &genClientset{ + DefaultGen: generator.DefaultGen{ + OptionalName: "clientset_generated", + }, + groups: customArgs.Groups, + groupGoNames: groupGoNames, + fakeClientsetPackage: clientsetPackage, + outputPackage: "fake", + imports: generator.NewImportTracker(), + realClientsetPackage: clientsetPackage, + }, + &scheme.GenScheme{ + DefaultGen: generator.DefaultGen{ + OptionalName: "register", + }, + InputPackages: customArgs.GroupVersionPackages(), + OutputPackage: clientsetPackage, + Groups: customArgs.Groups, + GroupGoNames: groupGoNames, + ImportTracker: generator.NewImportTracker(), + PrivateScheme: true, + }, + } + return generators + }, + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go new file mode 100644 index 0000000000..61b3334f40 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go @@ -0,0 +1,173 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "fmt" + "io" + "path/filepath" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// genClientset generates a package for a clientset. +type genClientset struct { + generator.DefaultGen + groups []clientgentypes.GroupVersions + groupGoNames map[clientgentypes.GroupVersion]string + fakeClientsetPackage string + outputPackage string + imports namer.ImportTracker + clientsetGenerated bool + // the import path of the generated real clientset. + realClientsetPackage string +} + +var _ generator.Generator = &genClientset{} + +func (g *genClientset) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +// We only want to call GenerateType() once. +func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.clientsetGenerated + g.clientsetGenerated = true + return ret +} + +func (g *genClientset) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + for _, group := range g.groups { + for _, version := range group.Versions { + groupClientPackage := filepath.Join(g.fakeClientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty())) + fakeGroupClientPackage := filepath.Join(groupClientPackage, "fake") + + groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), groupClientPackage)) + imports = append(imports, fmt.Sprintf("fake%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), fakeGroupClientPackage)) + } + } + // the package that has the clientset Interface + imports = append(imports, fmt.Sprintf("clientset \"%s\"", g.realClientsetPackage)) + // imports for the code in commonTemplate + imports = append(imports, + "k8s.io/client-go/testing", + "k8s.io/client-go/discovery", + "fakediscovery \"k8s.io/client-go/discovery/fake\"", + "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/watch", + ) + + return +} + +func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + // TODO: We actually don't need any type information to generate the clientset, + // perhaps we can adapt the go2ild framework to this kind of usage. + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames) + + sw.Do(common, nil) + sw.Do(checkImpl, nil) + + for _, group := range allGroups { + m := map[string]interface{}{ + "group": group.Group, + "version": group.Version, + "PackageAlias": group.PackageAlias, + "GroupGoName": group.GroupGoName, + "Version": namer.IC(group.Version.String()), + } + + sw.Do(clientsetInterfaceImplTemplate, m) + // don't generated the default method if generating internalversion clientset + if group.IsDefaultVersion && group.Version != "" { + sw.Do(clientsetInterfaceDefaultVersionImpl, m) + } + } + + return sw.Error() +} + +// This part of code is version-independent, unchanging. +var common = ` +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} +` + +var checkImpl = ` +var _ clientset.Interface = &Clientset{} +` + +var clientsetInterfaceImplTemplate = ` +// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client +func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return &fake$.PackageAlias$.Fake$.GroupGoName$$.Version${Fake: &c.Fake} +} +` + +var clientsetInterfaceDefaultVersionImpl = ` +// $.GroupGoName$ retrieves the $.GroupGoName$$.Version$Client +func (c *Clientset) $.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return &fake$.PackageAlias$.Fake$.GroupGoName$$.Version${Fake: &c.Fake} +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go new file mode 100644 index 0000000000..8f4d5785ef --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go @@ -0,0 +1,130 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "fmt" + "io" + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genFakeForGroup produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genFakeForGroup struct { + generator.DefaultGen + outputPackage string + realClientPackage string + group string + version string + groupGoName string + // types in this group + types []*types.Type + imports namer.ImportTracker + // If the genGroup has been called. This generator should only execute once. + called bool +} + +var _ generator.Generator = &genFakeForGroup{} + +// We only want to call GenerateType() once per group. +func (g *genFakeForGroup) Filter(c *generator.Context, t *types.Type) bool { + if !g.called { + g.called = true + return true + } + return false +} + +func (g *genFakeForGroup) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genFakeForGroup) Imports(c *generator.Context) (imports []string) { + imports = g.imports.ImportLines() + if len(g.types) != 0 { + imports = append(imports, fmt.Sprintf("%s \"%s\"", strings.ToLower(filepath.Base(g.realClientPackage)), g.realClientPackage)) + } + return imports +} + +func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + m := map[string]interface{}{ + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "Fake": c.Universe.Type(types.Name{Package: "k8s.io/client-go/testing", Name: "Fake"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "RESTClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClient"}), + } + + sw.Do(groupClientTemplate, m) + for _, t := range g.types { + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + wrapper := map[string]interface{}{ + "type": t, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "realClientPackage": strings.ToLower(filepath.Base(g.realClientPackage)), + } + if tags.NonNamespaced { + sw.Do(getterImplNonNamespaced, wrapper) + continue + } + sw.Do(getterImplNamespaced, wrapper) + } + sw.Do(getRESTClient, m) + return sw.Error() +} + +var groupClientTemplate = ` +type Fake$.GroupGoName$$.Version$ struct { + *$.Fake|raw$ +} +` + +var getterImplNamespaced = ` +func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$(namespace string) $.realClientPackage$.$.type|public$Interface { + return &Fake$.type|publicPlural${c, namespace} +} +` + +var getterImplNonNamespaced = ` +func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$() $.realClientPackage$.$.type|public$Interface { + return &Fake$.type|publicPlural${c} +} +` + +var getRESTClient = ` +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *Fake$.GroupGoName$$.Version$) RESTClient() $.RESTClientInterface|raw$ { + var ret *$.RESTClient|raw$ + return ret +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go new file mode 100644 index 0000000000..f5888aef15 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go @@ -0,0 +1,479 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "io" + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + "k8s.io/code-generator/cmd/client-gen/path" +) + +// genFakeForType produces a file for each top-level type. +type genFakeForType struct { + generator.DefaultGen + outputPackage string + group string + version string + groupGoName string + inputPackage string + typeToMatch *types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = &genFakeForType{} + +// Filter ignores all but one type because we're making a single file per type. +func (g *genFakeForType) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch } + +func (g *genFakeForType) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genFakeForType) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +// Ideally, we'd like genStatus to return true if there is a subresource path +// registered for "status" in the API server, but we do not have that +// information, so genStatus returns true if the type has a status field. +func genStatus(t *types.Type) bool { + // Default to true if we have a Status member + hasStatus := false + for _, m := range t.Members { + if m.Name == "Status" { + hasStatus = true + break + } + } + + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return hasStatus && !tags.NoStatus +} + +// hasObjectMeta returns true if the type has a ObjectMeta field. +func hasObjectMeta(t *types.Type) bool { + for _, m := range t.Members { + if m.Embedded == true && m.Name == "ObjectMeta" { + return true + } + } + return false +} + +// GenerateType makes the body of a file implementing the individual typed client for type t. +func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + pkg := filepath.Base(t.Name.Package) + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + canonicalGroup := g.group + if canonicalGroup == "core" { + canonicalGroup = "" + } + + groupName := g.group + if g.group == "core" { + groupName = "" + } + + // allow user to define a group name that's different from the one parsed from the directory. + p := c.Universe.Package(path.Vendorless(g.inputPackage)) + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + groupName = override[0] + } + + const pkgClientGoTesting = "k8s.io/client-go/testing" + m := map[string]interface{}{ + "type": t, + "inputType": t, + "resultType": t, + "subresourcePath": "", + "package": pkg, + "Package": namer.IC(pkg), + "namespaced": !tags.NonNamespaced, + "Group": namer.IC(g.group), + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "group": canonicalGroup, + "groupName": groupName, + "version": g.version, + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}), + "GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}), + "GroupVersionKind": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), + + "NewRootListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListAction"}), + "NewListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListAction"}), + "NewRootGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetAction"}), + "NewGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetAction"}), + "NewRootDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteAction"}), + "NewDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteAction"}), + "NewRootDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteCollectionAction"}), + "NewDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteCollectionAction"}), + "NewRootUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateAction"}), + "NewUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateAction"}), + "NewRootCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateAction"}), + "NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}), + "NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}), + "NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}), + "NewCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceAction"}), + "NewRootCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateSubresourceAction"}), + "NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}), + "NewGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceAction"}), + "NewRootGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetSubresourceAction"}), + "NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}), + "NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}), + "NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}), + "NewRootPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchSubresourceAction"}), + "NewPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchSubresourceAction"}), + "ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}), + } + + if tags.NonNamespaced { + sw.Do(structNonNamespaced, m) + } else { + sw.Do(structNamespaced, m) + } + + if tags.NoVerbs { + return sw.Error() + } + sw.Do(resource, m) + sw.Do(kind, m) + + if tags.HasVerb("get") { + sw.Do(getTemplate, m) + } + if tags.HasVerb("list") { + if hasObjectMeta(t) { + sw.Do(listUsingOptionsTemplate, m) + } else { + sw.Do(listTemplate, m) + } + } + if tags.HasVerb("watch") { + sw.Do(watchTemplate, m) + } + + if tags.HasVerb("create") { + sw.Do(createTemplate, m) + } + if tags.HasVerb("update") { + sw.Do(updateTemplate, m) + } + if tags.HasVerb("updateStatus") && genStatus(t) { + sw.Do(updateStatusTemplate, m) + } + if tags.HasVerb("delete") { + sw.Do(deleteTemplate, m) + } + if tags.HasVerb("deleteCollection") { + sw.Do(deleteCollectionTemplate, m) + } + if tags.HasVerb("patch") { + sw.Do(patchTemplate, m) + } + + // generate extended client methods + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + } + + return sw.Error() +} + +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1) +} + +// template for the struct that implements the type's interface +var structNamespaced = ` +// Fake$.type|publicPlural$ implements $.type|public$Interface +type Fake$.type|publicPlural$ struct { + Fake *Fake$.GroupGoName$$.Version$ + ns string +} +` + +// template for the struct that implements the type's interface +var structNonNamespaced = ` +// Fake$.type|publicPlural$ implements $.type|public$Interface +type Fake$.type|publicPlural$ struct { + Fake *Fake$.GroupGoName$$.Version$ +} +` + +var resource = ` +var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|resource$"} +` + +var kind = ` +var $.type|allLowercasePlural$Kind = $.GroupVersionKind|raw${Group: "$.groupName$", Version: "$.version$", Kind: "$.type|singularKind$"} +` + +var listTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. +func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{}) + $else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.type|raw$List), err +} +` + +var listUsingOptionsTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. +func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{}) + $else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$ + if obj == nil { + return nil, err + } + + label, _, _ := $.ExtractFromListOptions|raw$(opts) + if label == nil { + label = $.Everything|raw$() + } + list := &$.type|raw$List{ListMeta: obj.(*$.type|raw$List).ListMeta} + for _, item := range obj.(*$.type|raw$List).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} +` + +var getTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.resultType|raw${}) + $else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var getSubresourceTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name), &$.resultType|raw${}) + $else$Invokes($.NewRootGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.type|private$Name), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var deleteTemplate = ` +// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. +func (c *Fake$.type|publicPlural$) Delete(name string, options *$.DeleteOptions|raw$) error { + _, err := c.Fake. + $if .namespaced$Invokes($.NewDeleteAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${}) + $else$Invokes($.NewRootDeleteAction|raw$($.type|allLowercasePlural$Resource, name), &$.type|raw${})$end$ + return err +} +` + +var deleteCollectionTemplate = ` +// DeleteCollection deletes a collection of objects. +func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error { + $if .namespaced$action := $.NewDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, c.ns, listOptions) + $else$action := $.NewRootDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, listOptions) + $end$ + _, err := c.Fake.Invokes(action, &$.type|raw$List{}) + return err +} +` +var createTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewCreateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${}) + $else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$), &$.resultType|raw${}) + $else$Invokes($.NewRootCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.inputType|private$), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${}) + $else$Invokes($.NewRootUpdateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateSubresourceTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${}) + $else$Invokes($.NewRootUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.inputType|private$), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateStatusTemplate = ` +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *Fake$.type|publicPlural$) UpdateStatus($.type|private$ *$.type|raw$) (*$.type|raw$, error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$), &$.type|raw${}) + $else$Invokes($.NewRootUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", $.type|private$), &$.type|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.type|raw$), err +} +` + +var watchTemplate = ` +// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$. +func (c *Fake$.type|publicPlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error) { + return c.Fake. + $if .namespaced$InvokesWatch($.NewWatchAction|raw$($.type|allLowercasePlural$Resource, c.ns, opts)) + $else$InvokesWatch($.NewRootWatchAction|raw$($.type|allLowercasePlural$Resource, opts))$end$ +} +` + +var patchTemplate = ` +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, pt, data, subresources... ), &$.resultType|raw${}) + $else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, pt, data, subresources...), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_clientset.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_clientset.go new file mode 100644 index 0000000000..6fdb29a94a --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_clientset.go @@ -0,0 +1,192 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "path/filepath" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// genClientset generates a package for a clientset. +type genClientset struct { + generator.DefaultGen + groups []clientgentypes.GroupVersions + groupGoNames map[clientgentypes.GroupVersion]string + clientsetPackage string + outputPackage string + imports namer.ImportTracker + clientsetGenerated bool +} + +var _ generator.Generator = &genClientset{} + +func (g *genClientset) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +// We only want to call GenerateType() once. +func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.clientsetGenerated + g.clientsetGenerated = true + return ret +} + +func (g *genClientset) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + for _, group := range g.groups { + for _, version := range group.Versions { + typedClientPath := filepath.Join(g.clientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty())) + groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), typedClientPath)) + } + } + return +} + +func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + // TODO: We actually don't need any type information to generate the clientset, + // perhaps we can adapt the go2ild framework to this kind of usage. + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames) + m := map[string]interface{}{ + "allGroups": allGroups, + "Config": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "DiscoveryInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryInterface"}), + "DiscoveryClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryClient"}), + "NewDiscoveryClientForConfig": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfig"}), + "NewDiscoveryClientForConfigOrDie": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfigOrDie"}), + "NewDiscoveryClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClient"}), + "flowcontrolNewTokenBucketRateLimiter": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/flowcontrol", Name: "NewTokenBucketRateLimiter"}), + } + sw.Do(clientsetInterface, m) + sw.Do(clientsetTemplate, m) + for _, g := range allGroups { + sw.Do(clientsetInterfaceImplTemplate, g) + // don't generated the default method if generating internalversion clientset + if g.IsDefaultVersion && g.Version != "" { + sw.Do(clientsetInterfaceDefaultVersionImpl, g) + } + } + sw.Do(getDiscoveryTemplate, m) + sw.Do(newClientsetForConfigTemplate, m) + sw.Do(newClientsetForConfigOrDieTemplate, m) + sw.Do(newClientsetForRESTClientTemplate, m) + + return sw.Error() +} + +var clientsetInterface = ` +type Interface interface { + Discovery() $.DiscoveryInterface|raw$ + $range .allGroups$$.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface + $if .IsDefaultVersion$// Deprecated: please explicitly pick a version if possible. + $.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface + $end$$end$ +} +` + +var clientsetTemplate = ` +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *$.DiscoveryClient|raw$ + $range .allGroups$$.LowerCaseGroupGoName$$.Version$ *$.PackageAlias$.$.GroupGoName$$.Version$Client + $end$ +} +` + +var clientsetInterfaceImplTemplate = ` +// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client +func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return c.$.LowerCaseGroupGoName$$.Version$ +} +` + +var clientsetInterfaceDefaultVersionImpl = ` +// Deprecated: $.GroupGoName$ retrieves the default version of $.GroupGoName$Client. +// Please explicitly pick a version. +func (c *Clientset) $.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return c.$.LowerCaseGroupGoName$$.Version$ +} +` + +var getDiscoveryTemplate = ` +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() $.DiscoveryInterface|raw$ { + if c == nil { + return nil + } + return c.DiscoveryClient +} +` + +var newClientsetForConfigTemplate = ` +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *$.Config|raw$) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = $.flowcontrolNewTokenBucketRateLimiter|raw$(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error +$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$, err =$.PackageAlias$.NewForConfig(&configShallowCopy) + if err!=nil { + return nil, err + } +$end$ + cs.DiscoveryClient, err = $.NewDiscoveryClientForConfig|raw$(&configShallowCopy) + if err!=nil { + return nil, err + } + return &cs, nil +} +` + +var newClientsetForConfigOrDieTemplate = ` +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *$.Config|raw$) *Clientset { + var cs Clientset +$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$ =$.PackageAlias$.NewForConfigOrDie(c) +$end$ + cs.DiscoveryClient = $.NewDiscoveryClientForConfigOrDie|raw$(c) + return &cs +} +` + +var newClientsetForRESTClientTemplate = ` +// New creates a new Clientset for the given RESTClient. +func New(c $.RESTClientInterface|raw$) *Clientset { + var cs Clientset +$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$ =$.PackageAlias$.New(c) +$end$ + cs.DiscoveryClient = $.NewDiscoveryClient|raw$(c) + return &cs +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_expansion.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_expansion.go new file mode 100644 index 0000000000..f47c079e02 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_expansion.go @@ -0,0 +1,54 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "os" + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/types" +) + +// genExpansion produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genExpansion struct { + generator.DefaultGen + groupPackagePath string + // types in a group + types []*types.Type +} + +// We only want to call GenerateType() once per group. +func (g *genExpansion) Filter(c *generator.Context, t *types.Type) bool { + return len(g.types) == 0 || t == g.types[0] +} + +func (g *genExpansion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + for _, t := range g.types { + if _, err := os.Stat(filepath.Join(g.groupPackagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) { + sw.Do(expansionInterfaceTemplate, t) + } + } + return sw.Error() +} + +var expansionInterfaceTemplate = ` +type $.|public$Expansion interface {} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_group.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_group.go new file mode 100644 index 0000000000..fd59715c42 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_group.go @@ -0,0 +1,247 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "path/filepath" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + "k8s.io/code-generator/cmd/client-gen/path" +) + +// genGroup produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genGroup struct { + generator.DefaultGen + outputPackage string + group string + version string + groupGoName string + apiPath string + // types in this group + types []*types.Type + imports namer.ImportTracker + inputPackage string + clientsetPackage string + // If the genGroup has been called. This generator should only execute once. + called bool +} + +var _ generator.Generator = &genGroup{} + +// We only want to call GenerateType() once per group. +func (g *genGroup) Filter(c *generator.Context, t *types.Type) bool { + if !g.called { + g.called = true + return true + } + return false +} + +func (g *genGroup) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genGroup) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + imports = append(imports, filepath.Join(g.clientsetPackage, "scheme")) + return +} + +func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + apiPath := func(group string) string { + if group == "core" { + return `"/api"` + } + return `"` + g.apiPath + `"` + } + + groupName := g.group + if g.group == "core" { + groupName = "" + } + // allow user to define a group name that's different from the one parsed from the directory. + p := c.Universe.Package(path.Vendorless(g.inputPackage)) + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + groupName = override[0] + } + + m := map[string]interface{}{ + "group": g.group, + "version": g.version, + "groupName": groupName, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "types": g.types, + "apiPath": apiPath(g.group), + "schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}), + "runtimeAPIVersionInternal": c.Universe.Variable(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "APIVersionInternal"}), + "serializerDirectCodecFactory": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "DirectCodecFactory"}), + "restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "restDefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}), + "restRESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "restRESTClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientFor"}), + "SchemeGroupVersion": c.Universe.Variable(types.Name{Package: path.Vendorless(g.inputPackage), Name: "SchemeGroupVersion"}), + } + sw.Do(groupInterfaceTemplate, m) + sw.Do(groupClientTemplate, m) + for _, t := range g.types { + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + wrapper := map[string]interface{}{ + "type": t, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + } + if tags.NonNamespaced { + sw.Do(getterImplNonNamespaced, wrapper) + } else { + sw.Do(getterImplNamespaced, wrapper) + } + } + sw.Do(newClientForConfigTemplate, m) + sw.Do(newClientForConfigOrDieTemplate, m) + sw.Do(newClientForRESTClientTemplate, m) + if g.version == "" { + sw.Do(setInternalVersionClientDefaultsTemplate, m) + } else { + sw.Do(setClientDefaultsTemplate, m) + } + sw.Do(getRESTClient, m) + + return sw.Error() +} + +var groupInterfaceTemplate = ` +type $.GroupGoName$$.Version$Interface interface { + RESTClient() $.restRESTClientInterface|raw$ + $range .types$ $.|publicPlural$Getter + $end$ +} +` + +var groupClientTemplate = ` +// $.GroupGoName$$.Version$Client is used to interact with features provided by the $.groupName$ group. +type $.GroupGoName$$.Version$Client struct { + restClient $.restRESTClientInterface|raw$ +} +` + +var getterImplNamespaced = ` +func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$(namespace string) $.type|public$Interface { + return new$.type|publicPlural$(c, namespace) +} +` + +var getterImplNonNamespaced = ` +func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$() $.type|public$Interface { + return new$.type|publicPlural$(c) +} +` + +var newClientForConfigTemplate = ` +// NewForConfig creates a new $.GroupGoName$$.Version$Client for the given config. +func NewForConfig(c *$.restConfig|raw$) (*$.GroupGoName$$.Version$Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := $.restRESTClientFor|raw$(&config) + if err != nil { + return nil, err + } + return &$.GroupGoName$$.Version$Client{client}, nil +} +` + +var newClientForConfigOrDieTemplate = ` +// NewForConfigOrDie creates a new $.GroupGoName$$.Version$Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *$.restConfig|raw$) *$.GroupGoName$$.Version$Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} +` + +var getRESTClient = ` +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *$.GroupGoName$$.Version$Client) RESTClient() $.restRESTClientInterface|raw$ { + if c == nil { + return nil + } + return c.restClient +} +` + +var newClientForRESTClientTemplate = ` +// New creates a new $.GroupGoName$$.Version$Client for the given RESTClient. +func New(c $.restRESTClientInterface|raw$) *$.GroupGoName$$.Version$Client { + return &$.GroupGoName$$.Version$Client{c} +} +` + +var setInternalVersionClientDefaultsTemplate = ` +func setConfigDefaults(config *$.restConfig|raw$) error { + config.APIPath = $.apiPath$ + if config.UserAgent == "" { + config.UserAgent = $.restDefaultKubernetesUserAgent|raw$() + } + if config.GroupVersion == nil || config.GroupVersion.Group != scheme.Scheme.PrioritizedVersionsForGroup("$.groupName$")[0].Group { + gv := scheme.Scheme.PrioritizedVersionsForGroup("$.groupName$")[0] + config.GroupVersion = &gv + } + config.NegotiatedSerializer = scheme.Codecs + + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + + return nil +} +` + +var setClientDefaultsTemplate = ` +func setConfigDefaults(config *$.restConfig|raw$) error { + gv := $.SchemeGroupVersion|raw$ + config.GroupVersion = &gv + config.APIPath = $.apiPath$ + config.NegotiatedSerializer = $.serializerDirectCodecFactory|raw${CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = $.restDefaultKubernetesUserAgent|raw$() + } + + return nil +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_type.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_type.go new file mode 100644 index 0000000000..3e8fc7c4c6 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_type.go @@ -0,0 +1,599 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genClientForType produces a file for each top-level type. +type genClientForType struct { + generator.DefaultGen + outputPackage string + clientsetPackage string + group string + version string + groupGoName string + typeToMatch *types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = &genClientForType{} + +// Filter ignores all but one type because we're making a single file per type. +func (g *genClientForType) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch } + +func (g *genClientForType) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genClientForType) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +// Ideally, we'd like genStatus to return true if there is a subresource path +// registered for "status" in the API server, but we do not have that +// information, so genStatus returns true if the type has a status field. +func genStatus(t *types.Type) bool { + // Default to true if we have a Status member + hasStatus := false + for _, m := range t.Members { + if m.Name == "Status" { + hasStatus = true + break + } + } + return hasStatus && !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).NoStatus +} + +// GenerateType makes the body of a file implementing the individual typed client for type t. +func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + pkg := filepath.Base(t.Name.Package) + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + type extendedInterfaceMethod struct { + template string + args map[string]interface{} + } + extendedMethods := []extendedInterfaceMethod{} + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + // TODO: Extract this to some helper method as this code is copied into + // 2 other places. + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + var updatedVerbtemplate string + if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(") + } else { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(") + } + extendedMethods = append(extendedMethods, extendedInterfaceMethod{ + template: updatedVerbtemplate, + args: map[string]interface{}{ + "type": t, + "inputType": &inputType, + "resultType": &resultType, + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + }, + }) + } + m := map[string]interface{}{ + "type": t, + "inputType": t, + "resultType": t, + "package": pkg, + "Package": namer.IC(pkg), + "namespaced": !tags.NonNamespaced, + "Group": namer.IC(g.group), + "subresource": false, + "subresourcePath": "", + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}), + } + + sw.Do(getterComment, m) + if tags.NonNamespaced { + sw.Do(getterNonNamespaced, m) + } else { + sw.Do(getterNamespaced, m) + } + + sw.Do(interfaceTemplate1, m) + if !tags.NoVerbs { + if !genStatus(t) { + tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus") + } + interfaceSuffix := "" + if len(extendedMethods) > 0 { + interfaceSuffix = "\n" + } + sw.Do("\n"+generateInterface(tags)+interfaceSuffix, m) + // add extended verbs into interface + for _, v := range extendedMethods { + sw.Do(v.template+interfaceSuffix, v.args) + } + + } + sw.Do(interfaceTemplate4, m) + + if tags.NonNamespaced { + sw.Do(structNonNamespaced, m) + sw.Do(newStructNonNamespaced, m) + } else { + sw.Do(structNamespaced, m) + sw.Do(newStructNamespaced, m) + } + + if tags.NoVerbs { + return sw.Error() + } + + if tags.HasVerb("get") { + sw.Do(getTemplate, m) + } + if tags.HasVerb("list") { + sw.Do(listTemplate, m) + } + if tags.HasVerb("watch") { + sw.Do(watchTemplate, m) + } + + if tags.HasVerb("create") { + sw.Do(createTemplate, m) + } + if tags.HasVerb("update") { + sw.Do(updateTemplate, m) + } + if tags.HasVerb("updateStatus") { + sw.Do(updateStatusTemplate, m) + } + if tags.HasVerb("delete") { + sw.Do(deleteTemplate, m) + } + if tags.HasVerb("deleteCollection") { + sw.Do(deleteCollectionTemplate, m) + } + if tags.HasVerb("patch") { + sw.Do(patchTemplate, m) + } + + // generate expansion methods + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + } + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + } + + return sw.Error() +} + +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1) +} + +func generateInterface(tags util.Tags) string { + // need an ordered list here to guarantee order of generated methods. + out := []string{} + for _, m := range util.SupportedVerbs { + if tags.HasVerb(m) { + out = append(out, defaultVerbTemplates[m]) + } + } + return strings.Join(out, "\n") +} + +var subresourceDefaultVerbTemplates = map[string]string{ + "create": `Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`, + "list": `List($.type|private$Name string, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, + "update": `Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`, + "get": `Get($.type|private$Name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`, +} + +var defaultVerbTemplates = map[string]string{ + "create": `Create(*$.inputType|raw$) (*$.resultType|raw$, error)`, + "update": `Update(*$.inputType|raw$) (*$.resultType|raw$, error)`, + "updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`, + "delete": `Delete(name string, options *$.DeleteOptions|raw$) error`, + "deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`, + "get": `Get(name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`, + "list": `List(opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, + "watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`, + "patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error)`, +} + +// group client will implement this interface. +var getterComment = ` +// $.type|publicPlural$Getter has a method to return a $.type|public$Interface. +// A group's client should implement this interface.` + +var getterNamespaced = ` +type $.type|publicPlural$Getter interface { + $.type|publicPlural$(namespace string) $.type|public$Interface +} +` + +var getterNonNamespaced = ` +type $.type|publicPlural$Getter interface { + $.type|publicPlural$() $.type|public$Interface +} +` + +// this type's interface, typed client will implement this interface. +var interfaceTemplate1 = ` +// $.type|public$Interface has methods to work with $.type|public$ resources. +type $.type|public$Interface interface {` + +var interfaceTemplate4 = ` + $.type|public$Expansion +} +` + +// template for the struct that implements the type's interface +var structNamespaced = ` +// $.type|privatePlural$ implements $.type|public$Interface +type $.type|privatePlural$ struct { + client $.RESTClientInterface|raw$ + ns string +} +` + +// template for the struct that implements the type's interface +var structNonNamespaced = ` +// $.type|privatePlural$ implements $.type|public$Interface +type $.type|privatePlural$ struct { + client $.RESTClientInterface|raw$ +} +` + +var newStructNamespaced = ` +// new$.type|publicPlural$ returns a $.type|publicPlural$ +func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ { + return &$.type|privatePlural${ + client: c.RESTClient(), + ns: namespace, + } +} +` + +var newStructNonNamespaced = ` +// new$.type|publicPlural$ returns a $.type|publicPlural$ +func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ { + return &$.type|privatePlural${ + client: c.RESTClient(), + } +} +` +var listTemplate = ` +// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &$.resultType|raw$List{} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Do(). + Into(result) + return +} +` + +var listSubresourceTemplate = ` +// List takes $.type|raw$ name, label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &$.resultType|raw$List{} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Do(). + Into(result) + return +} +` + +var getTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name(name). + VersionedParams(&options, $.schemeParameterCodec|raw$). + Do(). + Into(result) + return +} +` + +var getSubresourceTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|raw$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&options, $.schemeParameterCodec|raw$). + Do(). + Into(result) + return +} +` + +var deleteTemplate = ` +// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. +func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error { + return c.client.Delete(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name(name). + Body(options). + Do(). + Error() +} +` + +var deleteCollectionTemplate = ` +// DeleteCollection deletes a collection of objects. +func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil{ + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + VersionedParams(&listOptions, $.schemeParameterCodec|raw$). + Timeout(timeout). + Body(options). + Do(). + Error() +} +` + +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Post(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + +var createTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Post(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + +var updateSubresourceTemplate = ` +// Update takes the top resource name and the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Put(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + +var updateTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Put(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.inputType|private$.Name). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + +var updateStatusTemplate = ` +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *$.type|privatePlural$) UpdateStatus($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { + result = &$.type|raw${} + err = c.client.Put(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$.Name). + SubResource("status"). + Body($.type|private$). + Do(). + Into(result) + return +} +` + +var watchTemplate = ` +// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$. +func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Watch() +} +` + +var patchTemplate = ` +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Patch(pt). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go new file mode 100644 index 0000000000..a698a28b68 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go @@ -0,0 +1,186 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheme + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/path" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// GenScheme produces a package for a clientset with the scheme, codecs and parameter codecs. +type GenScheme struct { + generator.DefaultGen + OutputPackage string + Groups []clientgentypes.GroupVersions + GroupGoNames map[clientgentypes.GroupVersion]string + InputPackages map[clientgentypes.GroupVersion]string + OutputPath string + ImportTracker namer.ImportTracker + PrivateScheme bool + CreateRegistry bool + schemeGenerated bool +} + +func (g *GenScheme) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.OutputPackage, g.ImportTracker), + } +} + +// We only want to call GenerateType() once. +func (g *GenScheme) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.schemeGenerated + g.schemeGenerated = true + return ret +} + +func (g *GenScheme) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.ImportTracker.ImportLines()...) + for _, group := range g.Groups { + for _, version := range group.Versions { + packagePath := g.InputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}] + groupAlias := strings.ToLower(g.GroupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + if g.CreateRegistry { + // import the install package for internal clientsets instead of the type package with register.go + if version.Version != "" { + packagePath = filepath.Dir(packagePath) + } + packagePath = filepath.Join(packagePath, "install") + + imports = append(imports, fmt.Sprintf("%s \"%s\"", groupAlias, path.Vendorless(packagePath))) + break + } else { + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.Version.NonEmpty()), path.Vendorless(packagePath))) + } + } + } + return +} + +func (g *GenScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroupVersions := clientgentypes.ToGroupVersionInfo(g.Groups, g.GroupGoNames) + allInstallGroups := clientgentypes.ToGroupInstallPackages(g.Groups, g.GroupGoNames) + + m := map[string]interface{}{ + "allGroupVersions": allGroupVersions, + "allInstallGroups": allInstallGroups, + "customRegister": false, + "runtimeNewParameterCodec": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewParameterCodec"}), + "runtimeNewScheme": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewScheme"}), + "serializerNewCodecFactory": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "NewCodecFactory"}), + "runtimeScheme": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Scheme"}), + "runtimeSchemeBuilder": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "SchemeBuilder"}), + "runtimeUtilMust": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/util/runtime", Name: "Must"}), + "schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}), + "metav1AddToGroupVersion": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}), + } + globals := map[string]string{ + "Scheme": "Scheme", + "Codecs": "Codecs", + "ParameterCodec": "ParameterCodec", + "Registry": "Registry", + } + for k, v := range globals { + if g.PrivateScheme { + m[k] = strings.ToLower(v[0:1]) + v[1:] + } else { + m[k] = v + } + } + + sw.Do(globalsTemplate, m) + + if g.OutputPath != "" { + if _, err := os.Stat(filepath.Join(g.OutputPath, strings.ToLower("register_custom.go"))); err == nil { + m["customRegister"] = true + } + } + + if g.CreateRegistry { + sw.Do(registryRegistration, m) + } else { + sw.Do(simpleRegistration, m) + } + + return sw.Error() +} + +var globalsTemplate = ` +var $.Scheme$ = $.runtimeNewScheme|raw$() +var $.Codecs$ = $.serializerNewCodecFactory|raw$($.Scheme$) +var $.ParameterCodec$ = $.runtimeNewParameterCodec|raw$($.Scheme$)` + +var registryRegistration = ` + +func init() { + $.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"}) + Install($.Scheme$) +} + +// Install registers the API group and adds types to a scheme +func Install(scheme *$.runtimeScheme|raw$) { + $- range .allInstallGroups$ + $.InstallPackageAlias$.Install(scheme) + $- end$ + $if .customRegister$ + ExtraInstall(scheme) + $end -$ +} +` + +var simpleRegistration = ` +var localSchemeBuilder = $.runtimeSchemeBuilder|raw${ + $- range .allGroupVersions$ + $.PackageAlias$.AddToScheme, + $- end$ + $if .customRegister$ + ExtraAddToScheme, + $end -$ +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + $.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"}) + $.runtimeUtilMust|raw$(AddToScheme($.Scheme$)) +} +` diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/tags.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/tags.go new file mode 100644 index 0000000000..b004081036 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/tags.go @@ -0,0 +1,32 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "k8s.io/gengo/types" +) + +// extractTag gets the comment-tags for the key. If the tag did not exist, it +// returns the empty string. +func extractTag(key string, lines []string) string { + val, present := types.ExtractCommentTags("+", lines)[key] + if !present || len(val) < 1 { + return "" + } + + return val[0] +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags.go new file mode 100644 index 0000000000..0b7d68ca88 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags.go @@ -0,0 +1,341 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "errors" + "fmt" + "strings" + + "k8s.io/gengo/types" +) + +var supportedTags = []string{ + "genclient", + "genclient:nonNamespaced", + "genclient:noVerbs", + "genclient:onlyVerbs", + "genclient:skipVerbs", + "genclient:noStatus", + "genclient:readonly", + "genclient:method", +} + +// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs. +var SupportedVerbs = []string{ + "create", + "update", + "updateStatus", + "delete", + "deleteCollection", + "get", + "list", + "watch", + "patch", +} + +// ReadonlyVerbs represents a list of read-only verbs. +var ReadonlyVerbs = []string{ + "get", + "list", + "watch", +} + +// genClientPrefix is the default prefix for all genclient tags. +const genClientPrefix = "genclient:" + +// unsupportedExtensionVerbs is a list of verbs we don't support generating +// extension client functions for. +var unsupportedExtensionVerbs = []string{ + "updateStatus", + "deleteCollection", + "watch", + "delete", +} + +// inputTypeSupportedVerbs is a list of verb types that supports overriding the +// input argument type. +var inputTypeSupportedVerbs = []string{ + "create", + "update", +} + +// resultTypeSupportedVerbs is a list of verb types that supports overriding the +// resulting type. +var resultTypeSupportedVerbs = []string{ + "create", + "update", + "get", + "list", + "patch", +} + +// Extensions allows to extend the default set of client verbs +// (CRUD+watch+patch+list+deleteCollection) for a given type with custom defined +// verbs. Custom verbs can have custom input and result types and also allow to +// use a sub-resource in a request instead of top-level resource type. +// +// Example: +// +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale +// +// type ReplicaSet struct { ... } +// +// The 'method=UpdateScale' is the name of the client function. +// The 'verb=update' here means the client function will use 'PUT' action. +// The 'subresource=scale' means we will use SubResource template to generate this client function. +// The 'input' is the input type used for creation (function argument). +// The 'result' (not needed in this case) is the result type returned from the +// client function. +// +type extension struct { + // VerbName is the name of the custom verb (Scale, Instantiate, etc..) + VerbName string + // VerbType is the type of the verb (only verbs from SupportedVerbs are + // supported) + VerbType string + // SubResourcePath defines a path to a sub-resource to use in the request. + // (optional) + SubResourcePath string + // InputTypeOverride overrides the input parameter type for the verb. By + // default the original type is used. Overriding the input type only works for + // "create" and "update" verb types. The given type must exists in the same + // package as the original type. + // (optional) + InputTypeOverride string + // ResultTypeOverride overrides the resulting object type for the verb. By + // default the original type is used. Overriding the result type works. + // (optional) + ResultTypeOverride string +} + +// IsSubresource indicates if this extension should generate the sub-resource. +func (e *extension) IsSubresource() bool { + return len(e.SubResourcePath) > 0 +} + +// HasVerb checks if the extension matches the given verb. +func (e *extension) HasVerb(verb string) bool { + return e.VerbType == verb +} + +// Input returns the input override package path and the type. +func (e *extension) Input() (string, string) { + parts := strings.Split(e.InputTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + +// Result returns the result override package path and the type. +func (e *extension) Result() (string, string) { + parts := strings.Split(e.ResultTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + +// Tags represents a genclient configuration for a single type. +type Tags struct { + // +genclient + GenerateClient bool + // +genclient:nonNamespaced + NonNamespaced bool + // +genclient:noStatus + NoStatus bool + // +genclient:noVerbs + NoVerbs bool + // +genclient:skipVerbs=get,update + // +genclient:onlyVerbs=create,delete + SkipVerbs []string + // +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale + Extensions []extension +} + +// HasVerb returns true if we should include the given verb in final client interface and +// generate the function for it. +func (t Tags) HasVerb(verb string) bool { + if len(t.SkipVerbs) == 0 { + return true + } + for _, s := range t.SkipVerbs { + if verb == s { + return false + } + } + return true +} + +// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics. +func MustParseClientGenTags(lines []string) Tags { + tags, err := ParseClientGenTags(lines) + if err != nil { + panic(err.Error()) + } + return tags +} + +// ParseClientGenTags parse the provided genclient tags and validates that no unknown +// tags are provided. +func ParseClientGenTags(lines []string) (Tags, error) { + ret := Tags{} + values := types.ExtractCommentTags("+", lines) + value := []string{} + value, ret.GenerateClient = values["genclient"] + // Check the old format and error when used to avoid generating client when //+genclient=false + if len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value) + } + _, ret.NonNamespaced = values[genClientPrefix+"nonNamespaced"] + // Check the old format and error when used + if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0]) + } + _, ret.NoVerbs = values[genClientPrefix+"noVerbs"] + _, ret.NoStatus = values[genClientPrefix+"noStatus"] + onlyVerbs := []string{} + if _, isReadonly := values[genClientPrefix+"readonly"]; isReadonly { + onlyVerbs = ReadonlyVerbs + } + // Check the old format and error when used + if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0]) + } + if v, exists := values[genClientPrefix+"skipVerbs"]; exists { + ret.SkipVerbs = strings.Split(v[0], ",") + } + if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 { + if len(v) > 0 { + onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...) + } + skipVerbs := []string{} + for _, m := range SupportedVerbs { + skip := true + for _, o := range onlyVerbs { + if o == m { + skip = false + break + } + } + // Check for conflicts + for _, v := range skipVerbs { + if v == m { + return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v) + } + } + if skip { + skipVerbs = append(skipVerbs, m) + } + } + ret.SkipVerbs = skipVerbs + } + var err error + if ret.Extensions, err = parseClientExtensions(values); err != nil { + return ret, err + } + return ret, validateClientGenTags(values) +} + +func parseClientExtensions(tags map[string][]string) ([]extension, error) { + var ret []extension + for name, values := range tags { + if !strings.HasPrefix(name, genClientPrefix+"method") { + continue + } + for _, value := range values { + // the value comes in this form: "Foo,verb=create" + ext := extension{} + parts := strings.Split(value, ",") + if len(parts) == 0 { + return nil, fmt.Errorf("invalid of empty extension verb name: %q", value) + } + // The first part represents the name of the extension + ext.VerbName = parts[0] + if len(ext.VerbName) == 0 { + return nil, fmt.Errorf("must specify a verb name (// +genclient:method=Foo,verb=create)") + } + // Parse rest of the arguments + params := parts[1:] + for _, p := range params { + parts := strings.Split(p, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid extension tag specification %q", p) + } + key, val := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) + if len(val) == 0 { + return nil, fmt.Errorf("empty value of %q for %q extension", key, ext.VerbName) + } + switch key { + case "verb": + ext.VerbType = val + case "subresource": + ext.SubResourcePath = val + case "input": + ext.InputTypeOverride = val + case "result": + ext.ResultTypeOverride = val + default: + return nil, fmt.Errorf("unknown extension configuration key %q", key) + } + } + // Validate resulting extension configuration + if len(ext.VerbType) == 0 { + return nil, fmt.Errorf("verb type must be specified (use '// +genclient:method=%s,verb=create')", ext.VerbName) + } + if len(ext.ResultTypeOverride) > 0 { + supported := false + for _, v := range resultTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: result type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, resultTypeSupportedVerbs) + } + } + if len(ext.InputTypeOverride) > 0 { + supported := false + for _, v := range inputTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: input type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, inputTypeSupportedVerbs) + } + } + for _, t := range unsupportedExtensionVerbs { + if ext.VerbType == t { + return nil, fmt.Errorf("verb %q is not supported by extension generator", ext.VerbType) + } + } + ret = append(ret, ext) + } + } + return ret, nil +} + +// validateTags validates that only supported genclient tags were provided. +func validateClientGenTags(values map[string][]string) error { + for _, k := range supportedTags { + delete(values, k) + } + for key := range values { + if strings.HasPrefix(key, strings.TrimSuffix(genClientPrefix, ":")) { + return errors.New("unknown tag detected: " + key) + } + } + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/main.go b/vendor/k8s.io/code-generator/cmd/client-gen/main.go new file mode 100644 index 0000000000..6e0d187f5c --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/main.go @@ -0,0 +1,66 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// client-gen makes the individual typed clients using gengo. +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/client-gen/args" + "k8s.io/code-generator/cmd/client-gen/generators" + "k8s.io/code-generator/pkg/util" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of client-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/clientset_generated/" + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of client-gen + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + // add group version package as input dirs for gengo + for _, pkg := range customArgs.Groups { + for _, v := range pkg.Versions { + genericArgs.InputDirs = append(genericArgs.InputDirs, v.Package) + } + } + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/path/path.go b/vendor/k8s.io/code-generator/cmd/client-gen/path/path.go new file mode 100644 index 0000000000..19b269bdf2 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/path/path.go @@ -0,0 +1,31 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package path + +import "strings" + +// Vendorless removes the longest match of "*/vendor/" from the front of p. +// It is useful if a package locates in vendor/, e.g., +// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1, because gengo +// indexes the package with its import path, e.g., +// k8s.io/apimachinery/pkg/apis/meta/v1, +func Vendorless(p string) string { + if pos := strings.LastIndex(p, "/vendor/"); pos != -1 { + return p[pos+len("/vendor/"):] + } + return p +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/types/helpers.go b/vendor/k8s.io/code-generator/cmd/client-gen/types/helpers.go new file mode 100644 index 0000000000..33e6ac451b --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/types/helpers.go @@ -0,0 +1,123 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "k8s.io/gengo/namer" +) + +// ToGroupVersion turns "group/version" string into a GroupVersion struct. It reports error +// if it cannot parse the string. +func ToGroupVersion(gv string) (GroupVersion, error) { + // this can be the internal version for the legacy kube types + // TODO once we've cleared the last uses as strings, this special case should be removed. + if (len(gv) == 0) || (gv == "/") { + return GroupVersion{}, nil + } + + switch strings.Count(gv, "/") { + case 0: + return GroupVersion{Group(gv), ""}, nil + case 1: + i := strings.Index(gv, "/") + return GroupVersion{Group(gv[:i]), Version(gv[i+1:])}, nil + default: + return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv) + } +} + +type sortableSliceOfVersions []string + +func (a sortableSliceOfVersions) Len() int { return len(a) } +func (a sortableSliceOfVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a sortableSliceOfVersions) Less(i, j int) bool { + vi, vj := strings.TrimLeft(a[i], "v"), strings.TrimLeft(a[j], "v") + major := regexp.MustCompile("^[0-9]+") + viMajor, vjMajor := major.FindString(vi), major.FindString(vj) + viRemaining, vjRemaining := strings.TrimLeft(vi, viMajor), strings.TrimLeft(vj, vjMajor) + switch { + case len(viRemaining) == 0 && len(vjRemaining) == 0: + return viMajor < vjMajor + case len(viRemaining) == 0 && len(vjRemaining) != 0: + // stable version is greater than unstable version + return false + case len(viRemaining) != 0 && len(vjRemaining) == 0: + // stable version is greater than unstable version + return true + } + // neither are stable versions + if viMajor != vjMajor { + return viMajor < vjMajor + } + // assuming at most we have one alpha or one beta version, so if vi contains "alpha", it's the lesser one. + return strings.Contains(viRemaining, "alpha") +} + +// Determine the default version among versions. If a user calls a group client +// without specifying the version (e.g., c.Core(), instead of c.CoreV1()), the +// default version will be returned. +func defaultVersion(versions []PackageVersion) Version { + var versionStrings []string + for _, version := range versions { + versionStrings = append(versionStrings, version.Version.String()) + } + sort.Sort(sortableSliceOfVersions(versionStrings)) + return Version(versionStrings[len(versionStrings)-1]) +} + +// ToGroupVersionInfo is a helper function used by generators for groups. +func ToGroupVersionInfo(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupVersionInfo { + var groupVersionPackages []GroupVersionInfo + for _, group := range groups { + defaultVersion := defaultVersion(group.Versions) + for _, version := range group.Versions { + groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: version.Version}] + groupVersionPackages = append(groupVersionPackages, GroupVersionInfo{ + Group: Group(namer.IC(group.Group.NonEmpty())), + Version: Version(namer.IC(version.Version.String())), + PackageAlias: strings.ToLower(groupGoName + version.Version.NonEmpty()), + IsDefaultVersion: version.Version == defaultVersion && version.Version != "", + GroupGoName: groupGoName, + LowerCaseGroupGoName: namer.IL(groupGoName), + }) + } + } + return groupVersionPackages +} + +func ToGroupInstallPackages(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupInstallPackage { + var groupInstallPackages []GroupInstallPackage + for _, group := range groups { + defaultVersion := defaultVersion(group.Versions) + groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: defaultVersion}] + groupInstallPackages = append(groupInstallPackages, GroupInstallPackage{ + Group: Group(namer.IC(group.Group.NonEmpty())), + InstallPackageAlias: strings.ToLower(groupGoName), + }) + } + return groupInstallPackages +} + +// NormalizeGroupVersion calls normalizes the GroupVersion. +//func NormalizeGroupVersion(gv GroupVersion) GroupVersion { +// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)} +//} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/types/types.go b/vendor/k8s.io/code-generator/cmd/client-gen/types/types.go new file mode 100644 index 0000000000..17fd6e92a7 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/types/types.go @@ -0,0 +1,78 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +type Version string + +func (v Version) String() string { + return string(v) +} + +func (v Version) NonEmpty() string { + if v == "" { + return "internalVersion" + } + return v.String() +} + +type Group string + +func (g Group) String() string { + return string(g) +} + +func (g Group) NonEmpty() string { + if g == "api" { + return "core" + } + return string(g) +} + +type PackageVersion struct { + Version + // The fully qualified package, e.g. k8s.io/kubernetes/pkg/apis/apps, where the types.go is found. + Package string +} + +type GroupVersion struct { + Group Group + Version Version +} + +type GroupVersions struct { + // The name of the package for this group, e.g. apps. + PackageName string + Group Group + Versions []PackageVersion +} + +// GroupVersionInfo contains all the info around a group version. +type GroupVersionInfo struct { + Group Group + Version Version + // If a user calls a group client without specifying the version (e.g., + // c.Core(), instead of c.CoreV1()), the default version will be returned. + IsDefaultVersion bool + PackageAlias string + GroupGoName string + LowerCaseGroupGoName string +} + +type GroupInstallPackage struct { + Group Group + InstallPackageAlias string +} diff --git a/vendor/k8s.io/code-generator/cmd/conversion-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/conversion-gen/args/args.go new file mode 100644 index 0000000000..07ce6e72bf --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/conversion-gen/args/args.go @@ -0,0 +1,83 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" +) + +// DefaultBasePeerDirs are the peer-dirs nearly everybody will use, i.e. those coming from +// apimachinery. +var DefaultBasePeerDirs = []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/conversion", + "k8s.io/apimachinery/pkg/runtime", +} + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs struct { + // Base peer dirs which nearly everybody will use, i.e. outside of Kubernetes core. Peer dirs + // are declared to make the generator pick up manually written conversion funcs from external + // packages. + BasePeerDirs []string + + // Custom peer dirs which are application specific. Peer dirs are declared to make the + // generator pick up manually written conversion funcs from external packages. + ExtraPeerDirs []string + + // SkipUnsafe indicates whether to generate unsafe conversions to improve the efficiency + // of these operations. The unsafe operation is a direct pointer assignment via unsafe + // (within the allowed uses of unsafe) and is equivalent to a proposed Golang change to + // allow structs that are identical to be assigned to each other. + SkipUnsafe bool +} + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{ + BasePeerDirs: DefaultBasePeerDirs, + SkipUnsafe: false, + } + genericArgs.CustomArgs = customArgs + genericArgs.OutputFileBaseName = "conversion_generated" + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + pflag.CommandLine.StringSliceVar(&ca.BasePeerDirs, "base-peer-dirs", ca.BasePeerDirs, + "Comma-separated list of apimachinery import paths which are considered, after tag-specified peers, for conversions. Only change these if you have very good reasons.") + pflag.CommandLine.StringSliceVar(&ca.ExtraPeerDirs, "extra-peer-dirs", ca.ExtraPeerDirs, + "Application specific comma-separated list of import paths which are considered, after tag-specified peers and base-peer-dirs, for conversions.") + pflag.CommandLine.BoolVar(&ca.SkipUnsafe, "skip-unsafe", ca.SkipUnsafe, + "If true, will not generate code using unsafe pointer conversions; resulting code may be slower.") +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + _ = genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputFileBaseName) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/conversion-gen/generators/conversion.go b/vendor/k8s.io/code-generator/cmd/conversion-gen/generators/conversion.go new file mode 100644 index 0000000000..775972d123 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/conversion-gen/generators/conversion.go @@ -0,0 +1,984 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "bytes" + "fmt" + "io" + "path/filepath" + "sort" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" + + conversionargs "k8s.io/code-generator/cmd/conversion-gen/args" +) + +// These are the comment tags that carry parameters for conversion generation. +const ( + // e.g., "+k8s:conversion-gen=" in doc.go, where is the + // import path of the package the peer types are defined in. + // e.g., "+k8s:conversion-gen=false" in a type's comment will let + // conversion-gen skip that type. + tagName = "k8s:conversion-gen" + // e.g., "+k8s:conversion-gen-external-types=" in doc.go, where + // is the relative path to the package the types are defined in. + externalTypesTagName = "k8s:conversion-gen-external-types" +) + +func extractTag(comments []string) []string { + return types.ExtractCommentTags("+", comments)[tagName] +} + +func extractExternalTypesTag(comments []string) []string { + return types.ExtractCommentTags("+", comments)[externalTypesTagName] +} + +func isCopyOnly(comments []string) bool { + values := types.ExtractCommentTags("+", comments)["k8s:conversion-fn"] + return len(values) == 1 && values[0] == "copy-only" +} + +func isDrop(comments []string) bool { + values := types.ExtractCommentTags("+", comments)["k8s:conversion-fn"] + return len(values) == 1 && values[0] == "drop" +} + +// TODO: This is created only to reduce number of changes in a single PR. +// Remove it and use PublicNamer instead. +func conversionNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Join: func(pre string, in []string, post string) string { + return strings.Join(in, "_") + }, + PrependPackageNames: 1, + } +} + +func defaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": conversionNamer(), + "raw": namer.NewRawNamer("", nil), + "defaultfn": defaultFnNamer(), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func getPeerTypeFor(context *generator.Context, t *types.Type, potenialPeerPkgs []string) *types.Type { + for _, ppp := range potenialPeerPkgs { + p := context.Universe.Package(ppp) + if p == nil { + continue + } + if p.Has(t.Name.Name) { + return p.Type(t.Name.Name) + } + } + return nil +} + +type conversionPair struct { + inType *types.Type + outType *types.Type +} + +// All of the types in conversions map are of type "DeclarationOf" with +// the underlying type being "Func". +type conversionFuncMap map[conversionPair]*types.Type + +// Returns all manually-defined conversion functions in the package. +func getManualConversionFunctions(context *generator.Context, pkg *types.Package, manualMap conversionFuncMap) { + if pkg == nil { + klog.Warningf("Skipping nil package passed to getManualConversionFunctions") + return + } + klog.V(5).Infof("Scanning for conversion functions in %v", pkg.Name) + + scopeName := types.Ref(conversionPackagePath, "Scope").Name + errorName := types.Ref("", "error").Name + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + for _, f := range pkg.Functions { + if f.Underlying == nil || f.Underlying.Kind != types.Func { + klog.Errorf("Malformed function: %#v", f) + continue + } + if f.Underlying.Signature == nil { + klog.Errorf("Function without signature: %#v", f) + continue + } + klog.V(8).Infof("Considering function %s", f.Name) + signature := f.Underlying.Signature + // Check whether the function is conversion function. + // Note that all of them have signature: + // func Convert_inType_To_outType(inType, outType, conversion.Scope) error + if signature.Receiver != nil { + klog.V(8).Infof("%s has a receiver", f.Name) + continue + } + if len(signature.Parameters) != 3 || signature.Parameters[2].Name != scopeName { + klog.V(8).Infof("%s has wrong parameters", f.Name) + continue + } + if len(signature.Results) != 1 || signature.Results[0].Name != errorName { + klog.V(8).Infof("%s has wrong results", f.Name) + continue + } + inType := signature.Parameters[0] + outType := signature.Parameters[1] + if inType.Kind != types.Pointer || outType.Kind != types.Pointer { + klog.V(8).Infof("%s has wrong parameter types", f.Name) + continue + } + // Now check if the name satisfies the convention. + // TODO: This should call the Namer directly. + args := argsFromType(inType.Elem, outType.Elem) + sw.Do("Convert_$.inType|public$_To_$.outType|public$", args) + if f.Name.Name == buffer.String() { + klog.V(4).Infof("Found conversion function %s", f.Name) + key := conversionPair{inType.Elem, outType.Elem} + // We might scan the same package twice, and that's OK. + if v, ok := manualMap[key]; ok && v != nil && v.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static conversion defined: %s -> %s from:\n%s.%s\n%s.%s", key.inType, key.outType, v.Name.Package, v.Name.Name, f.Name.Package, f.Name.Name)) + } + manualMap[key] = f + } else { + // prevent user error when they don't get the correct conversion signature + if strings.HasPrefix(f.Name.Name, "Convert_") { + klog.Errorf("Rename function %s %s -> %s to match expected conversion signature", f.Name.Package, f.Name.Name, buffer.String()) + } + klog.V(8).Infof("%s has wrong name", f.Name) + } + buffer.Reset() + } +} + +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + packages := generator.Packages{} + header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) + + // Accumulate pre-existing conversion functions. + // TODO: This is too ad-hoc. We need a better way. + manualConversions := conversionFuncMap{} + + // Record types that are memory equivalent. A type is memory equivalent + // if it has the same memory layout and no nested manual conversion is + // defined. + // TODO: in the future, relax the nested manual conversion requirement + // if we can show that a large enough types are memory identical but + // have non-trivial conversion + memoryEquivalentTypes := equalMemoryTypes{} + + // We are generating conversions only for packages that are explicitly + // passed as InputDir. + processed := map[string]bool{} + for _, i := range context.Inputs { + // skip duplicates + if processed[i] { + continue + } + processed[i] = true + + klog.V(5).Infof("considering pkg %q", i) + pkg := context.Universe[i] + // typesPkg is where the versioned types are defined. Sometimes it is + // different from pkg. For example, kubernetes core/v1 types are defined + // in vendor/k8s.io/api/core/v1, while pkg is at pkg/api/v1. + typesPkg := pkg + if pkg == nil { + // If the input had no Go files, for example. + continue + } + + // Add conversion and defaulting functions. + getManualConversionFunctions(context, pkg, manualConversions) + + // Only generate conversions for packages which explicitly request it + // by specifying one or more "+k8s:conversion-gen=" + // in their doc.go file. + peerPkgs := extractTag(pkg.Comments) + if peerPkgs != nil { + klog.V(5).Infof(" tags: %q", peerPkgs) + } else { + klog.V(5).Infof(" no tag") + continue + } + skipUnsafe := false + if customArgs, ok := arguments.CustomArgs.(*conversionargs.CustomArgs); ok { + peerPkgs = append(peerPkgs, customArgs.BasePeerDirs...) + peerPkgs = append(peerPkgs, customArgs.ExtraPeerDirs...) + skipUnsafe = customArgs.SkipUnsafe + } + + // if the external types are not in the same package where the conversion functions to be generated + externalTypesValues := extractExternalTypesTag(pkg.Comments) + if externalTypesValues != nil { + if len(externalTypesValues) != 1 { + klog.Fatalf(" expect only one value for %q tag, got: %q", externalTypesTagName, externalTypesValues) + } + externalTypes := externalTypesValues[0] + klog.V(5).Infof(" external types tags: %q", externalTypes) + var err error + typesPkg, err = context.AddDirectory(externalTypes) + if err != nil { + klog.Fatalf("cannot import package %s", externalTypes) + } + // update context.Order to the latest context.Universe + orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)} + context.Order = orderer.OrderUniverse(context.Universe) + } + + // if the source path is within a /vendor/ directory (for example, + // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow + // generation to output to the proper relative path (under vendor). + // Otherwise, the generator will create the file in the wrong location + // in the output directory. + // TODO: build a more fundamental concept in gengo for dealing with modifications + // to vendored packages. + vendorless := func(pkg string) string { + if pos := strings.LastIndex(pkg, "/vendor/"); pos != -1 { + return pkg[pos+len("/vendor/"):] + } + return pkg + } + for i := range peerPkgs { + peerPkgs[i] = vendorless(peerPkgs[i]) + } + + // Make sure our peer-packages are added and fully parsed. + for _, pp := range peerPkgs { + context.AddDir(pp) + p := context.Universe[pp] + if nil == p { + klog.Fatalf("failed to find pkg: %s", pp) + } + getManualConversionFunctions(context, p, manualConversions) + } + + unsafeEquality := TypesEqual(memoryEquivalentTypes) + if skipUnsafe { + unsafeEquality = noEquality{} + } + + path := pkg.Path + // if the source path is within a /vendor/ directory (for example, + // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow + // generation to output to the proper relative path (under vendor). + // Otherwise, the generator will create the file in the wrong location + // in the output directory. + // TODO: build a more fundamental concept in gengo for dealing with modifications + // to vendored packages. + if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) { + expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase) + if strings.Contains(expandedPath, "/vendor/") { + path = expandedPath + } + } + packages = append(packages, + &generator.DefaultPackage{ + PackageName: filepath.Base(pkg.Path), + PackagePath: path, + HeaderText: header, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenConversion(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, manualConversions, peerPkgs, unsafeEquality), + } + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == typesPkg.Path + }, + }) + } + + // If there is a manual conversion defined between two types, exclude it + // from being a candidate for unsafe conversion + for k, v := range manualConversions { + if isCopyOnly(v.CommentLines) { + klog.V(5).Infof("Conversion function %s will not block memory copy because it is copy-only", v.Name) + continue + } + // this type should be excluded from all equivalence, because the converter must be called. + memoryEquivalentTypes.Skip(k.inType, k.outType) + } + + return packages +} + +type equalMemoryTypes map[conversionPair]bool + +func (e equalMemoryTypes) Skip(a, b *types.Type) { + e[conversionPair{a, b}] = false + e[conversionPair{b, a}] = false +} + +func (e equalMemoryTypes) Equal(a, b *types.Type) bool { + // alreadyVisitedTypes holds all the types that have already been checked in the structural type recursion. + alreadyVisitedTypes := make(map[*types.Type]bool) + return e.cachingEqual(a, b, alreadyVisitedTypes) +} + +func (e equalMemoryTypes) cachingEqual(a, b *types.Type, alreadyVisitedTypes map[*types.Type]bool) bool { + if a == b { + return true + } + if equal, ok := e[conversionPair{a, b}]; ok { + return equal + } + if equal, ok := e[conversionPair{b, a}]; ok { + return equal + } + result := e.equal(a, b, alreadyVisitedTypes) + e[conversionPair{a, b}] = result + e[conversionPair{b, a}] = result + return result +} + +func (e equalMemoryTypes) equal(a, b *types.Type, alreadyVisitedTypes map[*types.Type]bool) bool { + in, out := unwrapAlias(a), unwrapAlias(b) + switch { + case in == out: + return true + case in.Kind == out.Kind: + // if the type exists already, return early to avoid recursion + if alreadyVisitedTypes[in] { + return true + } + alreadyVisitedTypes[in] = true + + switch in.Kind { + case types.Struct: + if len(in.Members) != len(out.Members) { + return false + } + for i, inMember := range in.Members { + outMember := out.Members[i] + if !e.cachingEqual(inMember.Type, outMember.Type, alreadyVisitedTypes) { + return false + } + } + return true + case types.Pointer: + return e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Map: + return e.cachingEqual(in.Key, out.Key, alreadyVisitedTypes) && e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Slice: + return e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Interface: + // TODO: determine whether the interfaces are actually equivalent - for now, they must have the + // same type. + return false + case types.Builtin: + return in.Name.Name == out.Name.Name + } + } + return false +} + +func findMember(t *types.Type, name string) (types.Member, bool) { + if t.Kind != types.Struct { + return types.Member{}, false + } + for _, member := range t.Members { + if member.Name == name { + return member, true + } + } + return types.Member{}, false +} + +// unwrapAlias recurses down aliased types to find the bedrock type. +func unwrapAlias(in *types.Type) *types.Type { + for in.Kind == types.Alias { + in = in.Underlying + } + return in +} + +const ( + runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" + conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" +) + +type noEquality struct{} + +func (noEquality) Equal(_, _ *types.Type) bool { return false } + +type TypesEqual interface { + Equal(a, b *types.Type) bool +} + +// genConversion produces a file with a autogenerated conversions. +type genConversion struct { + generator.DefaultGen + // the package that contains the types that conversion func are going to be + // generated for + typesPackage string + // the package that the conversion funcs are going to be output to + outputPackage string + // packages that contain the peer of types in typesPacakge + peerPackages []string + manualConversions conversionFuncMap + imports namer.ImportTracker + types []*types.Type + skippedFields map[*types.Type][]string + useUnsafe TypesEqual +} + +func NewGenConversion(sanitizedName, typesPackage, outputPackage string, manualConversions conversionFuncMap, peerPkgs []string, useUnsafe TypesEqual) generator.Generator { + return &genConversion{ + DefaultGen: generator.DefaultGen{ + OptionalName: sanitizedName, + }, + typesPackage: typesPackage, + outputPackage: outputPackage, + peerPackages: peerPkgs, + manualConversions: manualConversions, + imports: generator.NewImportTracker(), + types: []*types.Type{}, + skippedFields: map[*types.Type][]string{}, + useUnsafe: useUnsafe, + } +} + +func (g *genConversion) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicIT": &namerPlusImportTracking{ + delegate: conversionNamer(), + tracker: g.imports, + }, + } +} + +type namerPlusImportTracking struct { + delegate namer.Namer + tracker namer.ImportTracker +} + +func (n *namerPlusImportTracking) Name(t *types.Type) string { + n.tracker.AddType(t) + return n.delegate.Name(t) +} + +func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool { + var t *types.Type + var other *types.Type + if inType.Name.Package == g.typesPackage { + t, other = inType, outType + } else { + t, other = outType, inType + } + + if t.Name.Package != g.typesPackage { + return false + } + // If the type has opted out, skip it. + tagvals := extractTag(t.CommentLines) + if tagvals != nil { + if tagvals[0] != "false" { + klog.Fatalf("Type %v: unsupported %s value: %q", t, tagName, tagvals[0]) + } + klog.V(5).Infof("type %v requests no conversion generation, skipping", t) + return false + } + // TODO: Consider generating functions for other kinds too. + if t.Kind != types.Struct { + return false + } + // Also, filter out private types. + if namer.IsPrivateGoName(other.Name.Name) { + return false + } + return true +} + +func (g *genConversion) Filter(c *generator.Context, t *types.Type) bool { + peerType := getPeerTypeFor(c, t, g.peerPackages) + if peerType == nil { + return false + } + if !g.convertibleOnlyWithinPackage(t, peerType) { + return false + } + + g.types = append(g.types, t) + return true +} + +func (g *genConversion) isOtherPackage(pkg string) bool { + if pkg == g.outputPackage { + return false + } + if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) { + return false + } + return true +} + +func (g *genConversion) Imports(c *generator.Context) (imports []string) { + var importLines []string + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func argsFromType(inType, outType *types.Type) generator.Args { + return generator.Args{ + "inType": inType, + "outType": outType, + } +} + +const nameTmpl = "Convert_$.inType|publicIT$_To_$.outType|publicIT$" + +func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, bool) { + function, ok := g.manualConversions[conversionPair{inType, outType}] + return function, ok +} + +func (g *genConversion) Init(c *generator.Context, w io.Writer) error { + if klog.V(5) { + if m, ok := g.useUnsafe.(equalMemoryTypes); ok { + var result []string + klog.Infof("All objects without identical memory layout:") + for k, v := range m { + if v { + continue + } + result = append(result, fmt.Sprintf(" %s -> %s = %t", k.inType, k.outType, v)) + } + sort.Strings(result) + for _, s := range result { + klog.Infof(s) + } + } + } + sw := generator.NewSnippetWriter(w, c, "$", "$") + sw.Do("func init() {\n", nil) + sw.Do("localSchemeBuilder.Register(RegisterConversions)\n", nil) + sw.Do("}\n", nil) + + scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"}) + schemePtr := &types.Type{ + Kind: types.Pointer, + Elem: scheme, + } + sw.Do("// RegisterConversions adds conversion functions to the given scheme.\n", nil) + sw.Do("// Public to allow building arbitrary schemes.\n", nil) + sw.Do("func RegisterConversions(s $.|raw$) error {\n", schemePtr) + for _, t := range g.types { + peerType := getPeerTypeFor(c, t, g.peerPackages) + args := argsFromType(t, peerType).With("Scope", types.Ref(conversionPackagePath, "Scope")) + sw.Do("if err := s.AddGeneratedConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return "+nameTmpl+"(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + args = argsFromType(peerType, t).With("Scope", types.Ref(conversionPackagePath, "Scope")) + sw.Do("if err := s.AddGeneratedConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return "+nameTmpl+"(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + var pairs []conversionPair + for pair, t := range g.manualConversions { + if t.Name.Package != g.outputPackage { + continue + } + pairs = append(pairs, pair) + } + // sort by name of the conversion function + sort.Slice(pairs, func(i, j int) bool { + if g.manualConversions[pairs[i]].Name.Name < g.manualConversions[pairs[j]].Name.Name { + return true + } + return false + }) + for _, pair := range pairs { + args := argsFromType(pair.inType, pair.outType).With("Scope", types.Ref(conversionPackagePath, "Scope")).With("fn", g.manualConversions[pair]) + sw.Do("if err := s.AddConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return $.fn|raw$(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + return sw.Error() +} + +func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + klog.V(5).Infof("generating for type %v", t) + peerType := getPeerTypeFor(c, t, g.peerPackages) + sw := generator.NewSnippetWriter(w, c, "$", "$") + g.generateConversion(t, peerType, sw) + g.generateConversion(peerType, t, sw) + return sw.Error() +} + +func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { + args := argsFromType(inType, outType). + With("Scope", types.Ref(conversionPackagePath, "Scope")) + + sw.Do("func auto"+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + g.generateFor(inType, outType, sw) + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + + if _, found := g.preexists(inType, outType); found { + // There is a public manual Conversion method: use it. + } else if skipped := g.skippedFields[inType]; len(skipped) != 0 { + // The inType had some fields we could not generate. + klog.Errorf("Warning: could not find nor generate a final Conversion function for %v -> %v", inType, outType) + klog.Errorf(" the following fields need manual conversion:") + for _, f := range skipped { + klog.Errorf(" - %v", f) + } + } else { + // Emit a public conversion function. + sw.Do("// "+nameTmpl+" is an autogenerated conversion function.\n", args) + sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) + sw.Do("}\n\n", nil) + } +} + +// we use the system of shadowing 'in' and 'out' so that the same code is valid +// at any nesting level. This makes the autogenerator easy to understand, and +// the compiler shouldn't care. +func (g *genConversion) generateFor(inType, outType *types.Type, sw *generator.SnippetWriter) { + klog.V(5).Infof("generating %v -> %v", inType, outType) + var f func(*types.Type, *types.Type, *generator.SnippetWriter) + + switch inType.Kind { + case types.Builtin: + f = g.doBuiltin + case types.Map: + f = g.doMap + case types.Slice: + f = g.doSlice + case types.Struct: + f = g.doStruct + case types.Pointer: + f = g.doPointer + case types.Alias: + f = g.doAlias + default: + f = g.doUnknown + } + + f(inType, outType, sw) +} + +func (g *genConversion) doBuiltin(inType, outType *types.Type, sw *generator.SnippetWriter) { + if inType == outType { + sw.Do("*out = *in\n", nil) + } else { + sw.Do("*out = $.|raw$(*in)\n", outType) + } +} + +func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = make($.|raw$, len(*in))\n", outType) + if isDirectlyAssignable(inType.Key, outType.Key) { + sw.Do("for key, val := range *in {\n", nil) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Key == outType.Key { + sw.Do("(*out)[key] = ", nil) + } else { + sw.Do("(*out)[$.|raw$(key)] = ", outType.Key) + } + if inType.Elem == outType.Elem { + sw.Do("val\n", nil) + } else { + sw.Do("$.|raw$(val)\n", outType.Elem) + } + } else { + sw.Do("newVal := new($.|raw$)\n", outType.Elem) + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(&val, newVal, 0); err != nil {\n", nil) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + if inType.Key == outType.Key { + sw.Do("(*out)[key] = *newVal\n", nil) + } else { + sw.Do("(*out)[$.|raw$(key)] = *newVal\n", outType.Key) + } + } + } else { + // TODO: Implement it when necessary. + sw.Do("for range *in {\n", nil) + sw.Do("// FIXME: Converting unassignable keys unsupported $.|raw$\n", inType.Key) + } + sw.Do("}\n", nil) +} + +func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = make($.|raw$, len(*in))\n", outType) + if inType.Elem == outType.Elem && inType.Elem.Kind == types.Builtin { + sw.Do("copy(*out, *in)\n", nil) + } else { + sw.Do("for i := range *in {\n", nil) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Elem == outType.Elem { + sw.Do("(*out)[i] = (*in)[i]\n", nil) + } else { + sw.Do("(*out)[i] = $.|raw$((*in)[i])\n", outType.Elem) + } + } else { + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + // TODO: This triggers on metav1.ObjectMeta <-> metav1.ObjectMeta and + // similar because neither package is the target package, and + // we really don't know which package will have the conversion + // function defined. This fires on basically every object + // conversion outside of pkg/api/v1. + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {\n", nil) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + sw.Do("}\n", nil) + } +} + +func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { + for _, inMember := range inType.Members { + if tagvals := extractTag(inMember.CommentLines); tagvals != nil && tagvals[0] == "false" { + // This field is excluded from conversion. + sw.Do("// INFO: in."+inMember.Name+" opted out of conversion generation\n", nil) + continue + } + outMember, found := findMember(outType, inMember.Name) + if !found { + // This field doesn't exist in the peer. + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: does not exist in peer-type\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) + continue + } + + inMemberType, outMemberType := inMember.Type, outMember.Type + // create a copy of both underlying types but give them the top level alias name (since aliases + // are assignable) + if underlying := unwrapAlias(inMemberType); underlying != inMemberType { + copied := *underlying + copied.Name = inMemberType.Name + inMemberType = &copied + } + if underlying := unwrapAlias(outMemberType); underlying != outMemberType { + copied := *underlying + copied.Name = outMemberType.Name + outMemberType = &copied + } + + args := argsFromType(inMemberType, outMemberType).With("name", inMember.Name) + + // try a direct memory copy for any type that has exactly equivalent values + if g.useUnsafe.Equal(inMemberType, outMemberType) { + args = args. + With("Pointer", types.Ref("unsafe", "Pointer")). + With("SliceHeader", types.Ref("reflect", "SliceHeader")) + switch inMemberType.Kind { + case types.Pointer: + sw.Do("out.$.name$ = ($.outType|raw$)($.Pointer|raw$(in.$.name$))\n", args) + continue + case types.Map: + sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args) + continue + case types.Slice: + sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args) + continue + } + } + + // check based on the top level name, not the underlying names + if function, ok := g.preexists(inMember.Type, outMember.Type); ok { + if isDrop(function.CommentLines) { + continue + } + // copy-only functions that are directly assignable can be inlined instead of invoked. + // As an example, conversion functions exist that allow types with private fields to be + // correctly copied between types. These functions are equivalent to a memory assignment, + // and are necessary for the reflection path, but should not block memory conversion. + // Convert_unversioned_Time_to_unversioned_Time is an example of this logic. + if !isCopyOnly(function.CommentLines) || !g.isFastConversion(inMemberType, outMemberType) { + args["function"] = function + sw.Do("if err := $.function|raw$(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + continue + } + klog.V(5).Infof("Skipped function %s because it is copy-only and we can use direct assignment", function.Name) + } + + // If we can't auto-convert, punt before we emit any code. + if inMemberType.Kind != outMemberType.Kind { + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: inconvertible types ("+ + inMemberType.String()+" vs "+outMemberType.String()+")\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) + continue + } + + switch inMemberType.Kind { + case types.Builtin: + if inMemberType == outMemberType { + sw.Do("out.$.name$ = in.$.name$\n", args) + } else { + sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) + } + case types.Map, types.Slice, types.Pointer: + if g.isDirectlyAssignable(inMemberType, outMemberType) { + sw.Do("out.$.name$ = in.$.name$\n", args) + continue + } + + sw.Do("if in.$.name$ != nil {\n", args) + sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) + g.generateFor(inMemberType, outMemberType, sw) + sw.Do("} else {\n", nil) + sw.Do("out.$.name$ = nil\n", args) + sw.Do("}\n", nil) + case types.Struct: + if g.isDirectlyAssignable(inMemberType, outMemberType) { + sw.Do("out.$.name$ = in.$.name$\n", args) + continue + } + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + case types.Alias: + if isDirectlyAssignable(inMemberType, outMemberType) { + if inMemberType == outMemberType { + sw.Do("out.$.name$ = in.$.name$\n", args) + } else { + sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) + } + } else { + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + default: + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + } +} + +func (g *genConversion) isFastConversion(inType, outType *types.Type) bool { + switch inType.Kind { + case types.Builtin: + return true + case types.Map, types.Slice, types.Pointer, types.Struct, types.Alias: + return g.isDirectlyAssignable(inType, outType) + default: + return false + } +} + +func (g *genConversion) isDirectlyAssignable(inType, outType *types.Type) bool { + return unwrapAlias(inType) == unwrapAlias(outType) +} + +func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = new($.Elem|raw$)\n", outType) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Elem == outType.Elem { + sw.Do("**out = **in\n", nil) + } else { + sw.Do("**out = $.|raw$(**in)\n", outType.Elem) + } + } else { + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) + sw.Do("if err := s.Convert(*in, *out, 0); err != nil {\n", nil) + } + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } +} + +func (g *genConversion) doAlias(inType, outType *types.Type, sw *generator.SnippetWriter) { + // TODO: Add support for aliases. + g.doUnknown(inType, outType, sw) +} + +func (g *genConversion) doUnknown(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", inType) +} + +func isDirectlyAssignable(inType, outType *types.Type) bool { + // TODO: This should maybe check for actual assignability between the two + // types, rather than superficial traits that happen to indicate it is + // assignable in the ways we currently use this code. + return inType.IsAssignable() && (inType.IsPrimitive() || isSamePackage(inType, outType)) +} + +func isSamePackage(inType, outType *types.Type) bool { + return inType.Name.Package == outType.Name.Package +} diff --git a/vendor/k8s.io/code-generator/cmd/conversion-gen/main.go b/vendor/k8s.io/code-generator/cmd/conversion-gen/main.go new file mode 100644 index 0000000000..698baa7db7 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/conversion-gen/main.go @@ -0,0 +1,77 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// conversion-gen is a tool for auto-generating Conversion functions. +// +// Given a list of input directories, it will scan for "peer" packages and +// generate functions that efficiently convert between same-name types in each +// package. For any pair of types that has a +// `Convert___To__ +// +// When generating for a package, individual types or fields of structs may opt +// out of Conversion generation by specifying a comment on the of the form: +// // +k8s:conversion-gen=false +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/conversion-gen/args" + "k8s.io/code-generator/cmd/conversion-gen/generators" + "k8s.io/code-generator/pkg/util" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of conversion-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go new file mode 100644 index 0000000000..789713012a --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go @@ -0,0 +1,54 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/deepcopy-gen/generators" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs generators.CustomArgs + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = (*generators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there + genericArgs.OutputFileBaseName = "deepcopy_generated" + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + pflag.CommandLine.StringSliceVar(&ca.BoundingDirs, "bounding-dirs", ca.BoundingDirs, + "Comma-separated list of import paths which bound the types for which deep-copies will be generated.") +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + _ = genericArgs.CustomArgs.(*generators.CustomArgs) + + if len(genericArgs.OutputFileBaseName) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go b/vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go new file mode 100644 index 0000000000..96fb298734 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go @@ -0,0 +1,85 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// deepcopy-gen is a tool for auto-generating DeepCopy functions. +// +// Given a list of input directories, it will generate functions that +// efficiently perform a full deep-copy of each type. For any type that +// offers a `.DeepCopy()` method, it will simply call that. Otherwise it will +// use standard value assignment whenever possible. If that is not possible it +// will try to call its own generated copy function for the type, if the type is +// within the allowed root packages. Failing that, it will fall back on +// `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting file will +// be stored in the same directory as the processed source package. +// +// Generation is governed by comment tags in the source. Any package may +// request DeepCopy generation by including a comment in the file-comments of +// one file, of the form: +// // +k8s:deepcopy-gen=package +// +// DeepCopy functions can be generated for individual types, rather than the +// entire package by specifying a comment on the type definion of the form: +// // +k8s:deepcopy-gen=true +// +// When generating for a whole package, individual types may opt out of +// DeepCopy generation by specifying a comment on the of the form: +// // +k8s:deepcopy-gen=false +// +// Note that registration is a whole-package option, and is not available for +// individual types. +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/deepcopy-gen/generators" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/deepcopy-gen/args" + "k8s.io/code-generator/pkg/util" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of deepcopy-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/defaulter-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/defaulter-gen/args/args.go new file mode 100644 index 0000000000..3c5a042c7c --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/defaulter-gen/args/args.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/defaulter-gen/generators" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs generators.CustomArgs + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = (*generators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there + genericArgs.OutputFileBaseName = "zz_generated.defaults" + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + pflag.CommandLine.StringSliceVar(&ca.ExtraPeerDirs, "extra-peer-dirs", ca.ExtraPeerDirs, + "Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.") +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + _ = genericArgs.CustomArgs.(*generators.CustomArgs) + + if len(genericArgs.OutputFileBaseName) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/defaulter-gen/main.go b/vendor/k8s.io/code-generator/cmd/defaulter-gen/main.go new file mode 100644 index 0000000000..40bb875e52 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/defaulter-gen/main.go @@ -0,0 +1,84 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// defaulter-gen is a tool for auto-generating Defaulter functions. +// +// Given a list of input directories, it will scan for top level types +// and generate efficient defaulters for an entire object from the sum +// of the SetDefault_* methods contained in the object tree. +// +// Generation is governed by comment tags in the source. Any package may +// request defaulter generation by including one or more comment tags at +// the package comment level: +// +// // +k8s:defaulter-gen= +// +// which will create defaulters for any type that contains the provided +// field name (if the type has defaulters). Any type may request explicit +// defaulting by providing the comment tag: +// +// // +k8s:defaulter-gen=true|false +// +// An existing defaulter method (`SetDefaults_TYPE`) can provide the +// comment tag: +// +// // +k8s:defaulter-gen=covers +// +// to indicate that the defaulter does not or should not call any nested +// defaulters. +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/defaulter-gen/generators" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/defaulter-gen/args" + "k8s.io/code-generator/pkg/util" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of defaulter-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore new file mode 100644 index 0000000000..0e9aa466bb --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore @@ -0,0 +1 @@ +go-to-protobuf diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS new file mode 100644 index 0000000000..05d4b2a657 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS @@ -0,0 +1,4 @@ +approvers: +- smarterclayton +reviewers: +- smarterclayton diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go new file mode 100644 index 0000000000..847a6a5a02 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go @@ -0,0 +1,39 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any +// existing IDL tags on the Go struct. +package main + +import ( + goflag "flag" + + flag "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/go-to-protobuf/protobuf" +) + +var g = protobuf.New() + +func init() { + g.BindFlags(flag.CommandLine) + goflag.Set("logtostderr", "true") + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) +} + +func main() { + flag.Parse() + protobuf.Run(g) +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go new file mode 100644 index 0000000000..5550732259 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go @@ -0,0 +1,349 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any +// existing IDL tags on the Go struct. +package protobuf + +import ( + "bytes" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/parser" + "k8s.io/gengo/types" + + flag "github.com/spf13/pflag" +) + +type Generator struct { + Common args.GeneratorArgs + APIMachineryPackages string + Packages string + OutputBase string + VendorOutputBase string + ProtoImport []string + Conditional string + Clean bool + OnlyIDL bool + KeepGogoproto bool + SkipGeneratedRewrite bool + DropEmbeddedFields string +} + +func New() *Generator { + sourceTree := args.DefaultSourceTree() + common := args.GeneratorArgs{ + OutputBase: sourceTree, + GoHeaderFilePath: filepath.Join(sourceTree, util.BoilerplatePath()), + } + defaultProtoImport := filepath.Join(sourceTree, "k8s.io", "kubernetes", "vendor", "github.com", "gogo", "protobuf", "protobuf") + cwd, err := os.Getwd() + if err != nil { + log.Fatalf("Cannot get current directory.") + } + return &Generator{ + Common: common, + OutputBase: sourceTree, + VendorOutputBase: filepath.Join(cwd, "vendor"), + ProtoImport: []string{defaultProtoImport}, + APIMachineryPackages: strings.Join([]string{ + `+k8s.io/apimachinery/pkg/util/intstr`, + `+k8s.io/apimachinery/pkg/api/resource`, + `+k8s.io/apimachinery/pkg/runtime/schema`, + `+k8s.io/apimachinery/pkg/runtime`, + `k8s.io/apimachinery/pkg/apis/meta/v1`, + `k8s.io/apimachinery/pkg/apis/meta/v1beta1`, + `k8s.io/apimachinery/pkg/apis/testapigroup/v1`, + }, ","), + Packages: "", + DropEmbeddedFields: "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta", + } +} + +func (g *Generator) BindFlags(flag *flag.FlagSet) { + flag.StringVarP(&g.Common.GoHeaderFilePath, "go-header-file", "h", g.Common.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.") + flag.BoolVar(&g.Common.VerifyOnly, "verify-only", g.Common.VerifyOnly, "If true, only verify existing output, do not write anything.") + flag.StringVarP(&g.Packages, "packages", "p", g.Packages, "comma-separated list of directories to get input types from. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") + flag.StringVar(&g.APIMachineryPackages, "apimachinery-packages", g.APIMachineryPackages, "comma-separated list of directories to get apimachinery input types from which are needed by any API. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") + flag.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/") + flag.StringVar(&g.VendorOutputBase, "vendor-output-base", g.VendorOutputBase, "The vendor/ directory to look for packages in; defaults to $PWD/vendor/.") + flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "The search path for the core protobuf .protos, required; defaults $GOPATH/src/k8s.io/kubernetes/vendor/github.com/gogo/protobuf/protobuf.") + flag.StringVar(&g.Conditional, "conditional", g.Conditional, "An optional Golang build tag condition to add to the generated Go code") + flag.BoolVar(&g.Clean, "clean", g.Clean, "If true, remove all generated files for the specified Packages.") + flag.BoolVar(&g.OnlyIDL, "only-idl", g.OnlyIDL, "If true, only generate the IDL for each package.") + flag.BoolVar(&g.KeepGogoproto, "keep-gogoproto", g.KeepGogoproto, "If true, the generated IDL will contain gogoprotobuf extensions which are normally removed") + flag.BoolVar(&g.SkipGeneratedRewrite, "skip-generated-rewrite", g.SkipGeneratedRewrite, "If true, skip fixing up the generated.pb.go file (debugging only).") + flag.StringVar(&g.DropEmbeddedFields, "drop-embedded-fields", g.DropEmbeddedFields, "Comma-delimited list of embedded Go types to omit from generated protobufs") +} + +func Run(g *Generator) { + if g.Common.VerifyOnly { + g.OnlyIDL = true + g.Clean = false + } + + b := parser.New() + b.AddBuildTags("proto") + + omitTypes := map[types.Name]struct{}{} + for _, t := range strings.Split(g.DropEmbeddedFields, ",") { + name := types.Name{} + if i := strings.LastIndex(t, "."); i != -1 { + name.Package, name.Name = t[:i], t[i+1:] + } else { + name.Name = t + } + if len(name.Name) == 0 { + log.Fatalf("--drop-embedded-types requires names in the form of [GOPACKAGE.]TYPENAME: %v", t) + } + omitTypes[name] = struct{}{} + } + + boilerplate, err := g.Common.LoadGoBoilerplate() + if err != nil { + log.Fatalf("Failed loading boilerplate (consider using the go-header-file flag): %v", err) + } + + protobufNames := NewProtobufNamer() + outputPackages := generator.Packages{} + nonOutputPackages := map[string]struct{}{} + + var packages []string + if len(g.APIMachineryPackages) != 0 { + packages = append(packages, strings.Split(g.APIMachineryPackages, ",")...) + } + if len(g.Packages) != 0 { + packages = append(packages, strings.Split(g.Packages, ",")...) + } + if len(packages) == 0 { + log.Fatalf("Both apimachinery-packages and packages are empty. At least one package must be specified.") + } + + for _, d := range packages { + generateAllTypes, outputPackage := true, true + switch { + case strings.HasPrefix(d, "+"): + d = d[1:] + generateAllTypes = false + case strings.HasPrefix(d, "-"): + d = d[1:] + outputPackage = false + } + name := protoSafePackage(d) + parts := strings.SplitN(d, "=", 2) + if len(parts) > 1 { + d = parts[0] + name = parts[1] + } + p := newProtobufPackage(d, name, generateAllTypes, omitTypes) + header := append([]byte{}, boilerplate...) + header = append(header, p.HeaderText...) + p.HeaderText = header + protobufNames.Add(p) + if outputPackage { + outputPackages = append(outputPackages, p) + } else { + nonOutputPackages[name] = struct{}{} + } + } + + if !g.Common.VerifyOnly { + for _, p := range outputPackages { + if err := p.(*protobufPackage).Clean(g.OutputBase); err != nil { + log.Fatalf("Unable to clean package %s: %v", p.Name(), err) + } + } + } + + if g.Clean { + return + } + + for _, p := range protobufNames.List() { + if err := b.AddDir(p.Path()); err != nil { + log.Fatalf("Unable to add directory %q: %v", p.Path(), err) + } + } + + c, err := generator.NewContext( + b, + namer.NameSystems{ + "public": namer.NewPublicNamer(3), + "proto": protobufNames, + }, + "public", + ) + if err != nil { + log.Fatalf("Failed making a context: %v", err) + } + + c.Verify = g.Common.VerifyOnly + c.FileTypes["protoidl"] = NewProtoFile() + + var vendoredOutputPackages, localOutputPackages generator.Packages + for _, p := range protobufNames.packages { + if _, ok := nonOutputPackages[p.Name()]; ok { + // if we're not outputting the package, don't include it in either package list + continue + } + p.Vendored = strings.Contains(c.Universe[p.PackagePath].SourcePath, "/vendor/") + if p.Vendored { + vendoredOutputPackages = append(vendoredOutputPackages, p) + } else { + localOutputPackages = append(localOutputPackages, p) + } + } + + if err := protobufNames.AssignTypesToPackages(c); err != nil { + log.Fatalf("Failed to identify Common types: %v", err) + } + + if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil { + log.Fatalf("Failed executing vendor generator: %v", err) + } + if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil { + log.Fatalf("Failed executing local generator: %v", err) + } + + if g.OnlyIDL { + return + } + + if _, err := exec.LookPath("protoc"); err != nil { + log.Fatalf("Unable to find 'protoc': %v", err) + } + + searchArgs := []string{"-I", ".", "-I", g.OutputBase} + if len(g.ProtoImport) != 0 { + for _, s := range g.ProtoImport { + searchArgs = append(searchArgs, "-I", s) + } + } + args := append(searchArgs, fmt.Sprintf("--gogo_out=%s", g.OutputBase)) + + buf := &bytes.Buffer{} + if len(g.Conditional) > 0 { + fmt.Fprintf(buf, "// +build %s\n\n", g.Conditional) + } + buf.Write(boilerplate) + + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + + path := filepath.Join(g.OutputBase, p.ImportPath()) + outputPath := filepath.Join(g.OutputBase, p.OutputPath()) + if p.Vendored { + path = filepath.Join(g.VendorOutputBase, p.ImportPath()) + outputPath = filepath.Join(g.VendorOutputBase, p.OutputPath()) + } + + // generate the gogoprotobuf protoc + cmd := exec.Command("protoc", append(args, path)...) + out, err := cmd.CombinedOutput() + if len(out) > 0 { + log.Printf(string(out)) + } + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Fatalf("Unable to generate protoc on %s: %v", p.PackageName, err) + } + + if g.SkipGeneratedRewrite { + continue + } + + // alter the generated protobuf file to remove the generated types (but leave the serializers) and rewrite the + // package statement to match the desired package name + if err := RewriteGeneratedGogoProtobufFile(outputPath, p.ExtractGeneratedType, p.OptionalTypeName, buf.Bytes()); err != nil { + log.Fatalf("Unable to rewrite generated %s: %v", outputPath, err) + } + + // sort imports + cmd = exec.Command("goimports", "-w", outputPath) + out, err = cmd.CombinedOutput() + if len(out) > 0 { + log.Printf(string(out)) + } + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Fatalf("Unable to rewrite imports for %s: %v", p.PackageName, err) + } + + // format and simplify the generated file + cmd = exec.Command("gofmt", "-s", "-w", outputPath) + out, err = cmd.CombinedOutput() + if len(out) > 0 { + log.Printf(string(out)) + } + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Fatalf("Unable to apply gofmt for %s: %v", p.PackageName, err) + } + } + + if g.SkipGeneratedRewrite { + return + } + + if !g.KeepGogoproto { + // generate, but do so without gogoprotobuf extensions + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + p.OmitGogo = true + } + if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil { + log.Fatalf("Failed executing vendor generator: %v", err) + } + if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil { + log.Fatalf("Failed executing local generator: %v", err) + } + } + + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + + if len(p.StructTags) == 0 { + continue + } + + pattern := filepath.Join(g.OutputBase, p.PackagePath, "*.go") + if p.Vendored { + pattern = filepath.Join(g.VendorOutputBase, p.PackagePath, "*.go") + } + files, err := filepath.Glob(pattern) + if err != nil { + log.Fatalf("Can't glob pattern %q: %v", pattern, err) + } + + for _, s := range files { + if strings.HasSuffix(s, "_test.go") { + continue + } + if err := RewriteTypesWithProtobufStructTags(s, p.StructTags); err != nil { + log.Fatalf("Unable to rewrite with struct tags %s: %v", s, err) + } + } + } +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go new file mode 100644 index 0000000000..1a9803dc88 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go @@ -0,0 +1,773 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "fmt" + "io" + "log" + "reflect" + "sort" + "strconv" + "strings" + + "k8s.io/klog" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// genProtoIDL produces a .proto IDL. +type genProtoIDL struct { + generator.DefaultGen + localPackage types.Name + localGoPackage types.Name + imports namer.ImportTracker + + generateAll bool + omitGogo bool + omitFieldTypes map[types.Name]struct{} +} + +func (g *genProtoIDL) PackageVars(c *generator.Context) []string { + if g.omitGogo { + return []string{ + fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name), + } + } + return []string{ + "option (gogoproto.marshaler_all) = true;", + "option (gogoproto.stable_marshaler_all) = true;", + "option (gogoproto.sizer_all) = true;", + "option (gogoproto.goproto_stringer_all) = false;", + "option (gogoproto.stringer_all) = true;", + "option (gogoproto.unmarshaler_all) = true;", + "option (gogoproto.goproto_unrecognized_all) = false;", + "option (gogoproto.goproto_enum_prefix_all) = false;", + "option (gogoproto.goproto_getters_all) = false;", + fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name), + } +} +func (g *genProtoIDL) Filename() string { return g.OptionalName + ".proto" } +func (g *genProtoIDL) FileType() string { return "protoidl" } +func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + // The local namer returns the correct protobuf name for a proto type + // in the context of a package + "local": localNamer{g.localPackage}, + } +} + +// Filter ignores types that are identified as not exportable. +func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool { + tagVals := types.ExtractCommentTags("+", t.CommentLines)["protobuf"] + if tagVals != nil { + if tagVals[0] == "false" { + // Type specified "false". + return false + } + if tagVals[0] == "true" { + // Type specified "true". + return true + } + klog.Fatalf(`Comment tag "protobuf" must be true or false, found: %q`, tagVals[0]) + } + if !g.generateAll { + // We're not generating everything. + return false + } + seen := map[*types.Type]bool{} + ok := isProtoable(seen, t) + return ok +} + +func isProtoable(seen map[*types.Type]bool, t *types.Type) bool { + if seen[t] { + // be optimistic in the case of type cycles. + return true + } + seen[t] = true + switch t.Kind { + case types.Builtin: + return true + case types.Alias: + return isProtoable(seen, t.Underlying) + case types.Slice, types.Pointer: + return isProtoable(seen, t.Elem) + case types.Map: + return isProtoable(seen, t.Key) && isProtoable(seen, t.Elem) + case types.Struct: + if len(t.Members) == 0 { + return true + } + for _, m := range t.Members { + if isProtoable(seen, m.Type) { + return true + } + } + return false + case types.Func, types.Chan: + return false + case types.DeclarationOf, types.Unknown, types.Unsupported: + return false + case types.Interface: + return false + default: + log.Printf("WARNING: type %q is not portable: %s", t.Kind, t.Name) + return false + } +} + +// isOptionalAlias should return true if the specified type has an underlying type +// (is an alias) of a map or slice and has the comment tag protobuf.nullable=true, +// indicating that the type should be nullable in protobuf. +func isOptionalAlias(t *types.Type) bool { + if t.Underlying == nil || (t.Underlying.Kind != types.Map && t.Underlying.Kind != types.Slice) { + return false + } + if extractBoolTagOrDie("protobuf.nullable", t.CommentLines) == false { + return false + } + return true +} + +func (g *genProtoIDL) Imports(c *generator.Context) (imports []string) { + lines := []string{} + // TODO: this could be expressed more cleanly + for _, line := range g.imports.ImportLines() { + if g.omitGogo && line == "github.com/gogo/protobuf/gogoproto/gogo.proto" { + continue + } + lines = append(lines, line) + } + return lines +} + +// GenerateType makes the body of a file implementing a set for type t. +func (g *genProtoIDL) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + b := bodyGen{ + locator: &protobufLocator{ + namer: c.Namers["proto"].(ProtobufFromGoNamer), + tracker: g.imports, + universe: c.Universe, + + localGoPackage: g.localGoPackage.Package, + }, + localPackage: g.localPackage, + + omitGogo: g.omitGogo, + omitFieldTypes: g.omitFieldTypes, + + t: t, + } + switch t.Kind { + case types.Alias: + return b.doAlias(sw) + case types.Struct: + return b.doStruct(sw) + default: + return b.unknown(sw) + } +} + +// ProtobufFromGoNamer finds the protobuf name of a type (and its package, and +// the package path) from its Go name. +type ProtobufFromGoNamer interface { + GoNameToProtoName(name types.Name) types.Name +} + +type ProtobufLocator interface { + ProtoTypeFor(t *types.Type) (*types.Type, error) + GoTypeForName(name types.Name) *types.Type + CastTypeName(name types.Name) string +} + +type protobufLocator struct { + namer ProtobufFromGoNamer + tracker namer.ImportTracker + universe types.Universe + + localGoPackage string +} + +// CastTypeName returns the cast type name of a Go type +// TODO: delegate to a new localgo namer? +func (p protobufLocator) CastTypeName(name types.Name) string { + if name.Package == p.localGoPackage { + return name.Name + } + return name.String() +} + +func (p protobufLocator) GoTypeForName(name types.Name) *types.Type { + if len(name.Package) == 0 { + name.Package = p.localGoPackage + } + return p.universe.Type(name) +} + +// ProtoTypeFor locates a Protobuf type for the provided Go type (if possible). +func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) { + switch { + // we've already converted the type, or it's a map + case t.Kind == types.Protobuf || t.Kind == types.Map: + p.tracker.AddType(t) + return t, nil + } + // it's a fundamental type + if t, ok := isFundamentalProtoType(t); ok { + p.tracker.AddType(t) + return t, nil + } + // it's a message + if t.Kind == types.Struct || isOptionalAlias(t) { + t := &types.Type{ + Name: p.namer.GoNameToProtoName(t.Name), + Kind: types.Protobuf, + + CommentLines: t.CommentLines, + } + p.tracker.AddType(t) + return t, nil + } + return nil, errUnrecognizedType +} + +type bodyGen struct { + locator ProtobufLocator + localPackage types.Name + omitGogo bool + omitFieldTypes map[types.Name]struct{} + + t *types.Type +} + +func (b bodyGen) unknown(sw *generator.SnippetWriter) error { + return fmt.Errorf("not sure how to generate: %#v", b.t) +} + +func (b bodyGen) doAlias(sw *generator.SnippetWriter) error { + if !isOptionalAlias(b.t) { + return nil + } + + var kind string + switch b.t.Underlying.Kind { + case types.Map: + kind = "map" + default: + kind = "slice" + } + optional := &types.Type{ + Name: b.t.Name, + Kind: types.Struct, + + CommentLines: b.t.CommentLines, + SecondClosestCommentLines: b.t.SecondClosestCommentLines, + Members: []types.Member{ + { + Name: "Items", + CommentLines: []string{fmt.Sprintf("items, if empty, will result in an empty %s\n", kind)}, + Type: b.t.Underlying, + }, + }, + } + nested := b + nested.t = optional + return nested.doStruct(sw) +} + +func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { + if len(b.t.Name.Name) == 0 { + return nil + } + if namer.IsPrivateGoName(b.t.Name.Name) { + return nil + } + + var alias *types.Type + var fields []protoField + options := []string{} + allOptions := types.ExtractCommentTags("+", b.t.CommentLines) + for k, v := range allOptions { + switch { + case strings.HasPrefix(k, "protobuf.options."): + key := strings.TrimPrefix(k, "protobuf.options.") + switch key { + case "marshal": + if v[0] == "false" { + if !b.omitGogo { + options = append(options, + "(gogoproto.marshaler) = false", + "(gogoproto.unmarshaler) = false", + "(gogoproto.sizer) = false", + ) + } + } + default: + if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") { + if key == "(gogoproto.goproto_stringer)" && v[0] == "false" { + options = append(options, "(gogoproto.stringer) = false") + } + options = append(options, fmt.Sprintf("%s = %s", key, v[0])) + } + } + // protobuf.as allows a type to have the same message contents as another Go type + case k == "protobuf.as": + fields = nil + if alias = b.locator.GoTypeForName(types.Name{Name: v[0]}); alias == nil { + return fmt.Errorf("type %v references alias %q which does not exist", b.t, v[0]) + } + // protobuf.embed instructs the generator to use the named type in this package + // as an embedded message. + case k == "protobuf.embed": + fields = []protoField{ + { + Tag: 1, + Name: v[0], + Type: &types.Type{ + Name: types.Name{ + Name: v[0], + Package: b.localPackage.Package, + Path: b.localPackage.Path, + }, + }, + }, + } + } + } + if alias == nil { + alias = b.t + } + + // If we don't explicitly embed anything, generate fields by traversing fields. + if fields == nil { + memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes) + if err != nil { + return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) + } + fields = memberFields + } + + out := sw.Out() + genComment(out, b.t.CommentLines, "") + sw.Do(`message $.Name.Name$ { +`, b.t) + + if len(options) > 0 { + sort.Sort(sort.StringSlice(options)) + for _, s := range options { + fmt.Fprintf(out, " option %s;\n", s) + } + fmt.Fprintln(out) + } + + for i, field := range fields { + genComment(out, field.CommentLines, " ") + fmt.Fprintf(out, " ") + switch { + case field.Map: + case field.Repeated: + fmt.Fprintf(out, "repeated ") + case field.Required: + fmt.Fprintf(out, "required ") + default: + fmt.Fprintf(out, "optional ") + } + sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field) + if len(field.Extras) > 0 { + extras := []string{} + for k, v := range field.Extras { + if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") { + continue + } + extras = append(extras, fmt.Sprintf("%s = %s", k, v)) + } + sort.Sort(sort.StringSlice(extras)) + if len(extras) > 0 { + fmt.Fprintf(out, " [") + fmt.Fprint(out, strings.Join(extras, ", ")) + fmt.Fprintf(out, "]") + } + } + fmt.Fprintf(out, ";\n") + if i != len(fields)-1 { + fmt.Fprintf(out, "\n") + } + } + fmt.Fprintf(out, "}\n\n") + return nil +} + +type protoField struct { + LocalPackage types.Name + + Tag int + Name string + Type *types.Type + Map bool + Repeated bool + Optional bool + Required bool + Nullable bool + Extras map[string]string + + CommentLines []string +} + +var ( + errUnrecognizedType = fmt.Errorf("did not recognize the provided type") +) + +func isFundamentalProtoType(t *types.Type) (*types.Type, bool) { + // TODO: when we enable proto3, also include other fundamental types in the google.protobuf package + // switch { + // case t.Kind == types.Struct && t.Name == types.Name{Package: "time", Name: "Time"}: + // return &types.Type{ + // Kind: types.Protobuf, + // Name: types.Name{Path: "google/protobuf/timestamp.proto", Package: "google.protobuf", Name: "Timestamp"}, + // }, true + // } + switch t.Kind { + case types.Slice: + if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { + return &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf}, true + } + case types.Builtin: + switch t.Name.Name { + case "string", "uint32", "int32", "uint64", "int64", "bool": + return &types.Type{Name: types.Name{Name: t.Name.Name}, Kind: types.Protobuf}, true + case "int": + return &types.Type{Name: types.Name{Name: "int64"}, Kind: types.Protobuf}, true + case "uint": + return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true + case "float64", "float": + return &types.Type{Name: types.Name{Name: "double"}, Kind: types.Protobuf}, true + case "float32": + return &types.Type{Name: types.Name{Name: "float"}, Kind: types.Protobuf}, true + case "uintptr": + return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true + } + // TODO: complex? + } + return t, false +} + +func memberTypeToProtobufField(locator ProtobufLocator, field *protoField, t *types.Type) error { + var err error + switch t.Kind { + case types.Protobuf: + field.Type, err = locator.ProtoTypeFor(t) + case types.Builtin: + field.Type, err = locator.ProtoTypeFor(t) + case types.Map: + valueField := &protoField{} + if err := memberTypeToProtobufField(locator, valueField, t.Elem); err != nil { + return err + } + keyField := &protoField{} + if err := memberTypeToProtobufField(locator, keyField, t.Key); err != nil { + return err + } + // All other protobuf types have kind types.Protobuf, so setting types.Map + // here would be very misleading. + field.Type = &types.Type{ + Kind: types.Protobuf, + Key: keyField.Type, + Elem: valueField.Type, + } + if !strings.HasPrefix(t.Name.Name, "map[") { + field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) + } + if k, ok := keyField.Extras["(gogoproto.casttype)"]; ok { + field.Extras["(gogoproto.castkey)"] = k + } + if v, ok := valueField.Extras["(gogoproto.casttype)"]; ok { + field.Extras["(gogoproto.castvalue)"] = v + } + field.Map = true + case types.Pointer: + if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { + return err + } + field.Nullable = true + case types.Alias: + if isOptionalAlias(t) { + field.Type, err = locator.ProtoTypeFor(t) + field.Nullable = true + } else { + if err := memberTypeToProtobufField(locator, field, t.Underlying); err != nil { + log.Printf("failed to alias: %s %s: err %v", t.Name, t.Underlying.Name, err) + return err + } + // If this is not an alias to a slice, cast to the alias + if !field.Repeated { + if field.Extras == nil { + field.Extras = make(map[string]string) + } + field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) + } + } + case types.Slice: + if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { + field.Type = &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf} + return nil + } + if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { + return err + } + field.Repeated = true + case types.Struct: + if len(t.Name.Name) == 0 { + return errUnrecognizedType + } + field.Type, err = locator.ProtoTypeFor(t) + field.Nullable = false + default: + return errUnrecognizedType + } + return err +} + +// protobufTagToField extracts information from an existing protobuf tag +func protobufTagToField(tag string, field *protoField, m types.Member, t *types.Type, localPackage types.Name) error { + if len(tag) == 0 || tag == "-" { + return nil + } + + // protobuf:"bytes,3,opt,name=Id,customtype=github.com/gogo/protobuf/test.Uuid" + parts := strings.Split(tag, ",") + if len(parts) < 3 { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments\n", m.Name, t.Name) + } + protoTag, err := strconv.Atoi(parts[1]) + if err != nil { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %v\n", m.Name, t.Name, parts[1], err) + } + field.Tag = protoTag + + // In general there is doesn't make sense to parse the protobuf tags to get the type, + // as all auto-generated once will have wire type "bytes", "varint" or "fixed64". + // However, sometimes we explicitly set them to have a custom serialization, e.g.: + // type Time struct { + // time.Time `protobuf:"Timestamp,1,req,name=time"` + // } + // to force the generator to use a given type (that we manually wrote serialization & + // deserialization methods for). + switch parts[0] { + case "varint", "fixed32", "fixed64", "bytes", "group": + default: + name := types.Name{} + if last := strings.LastIndex(parts[0], "."); last != -1 { + prefix := parts[0][:last] + name = types.Name{ + Name: parts[0][last+1:], + Package: prefix, + Path: strings.Replace(prefix, ".", "/", -1), + } + } else { + name = types.Name{ + Name: parts[0], + Package: localPackage.Package, + Path: localPackage.Path, + } + } + field.Type = &types.Type{ + Name: name, + Kind: types.Protobuf, + } + } + + protoExtra := make(map[string]string) + for i, extra := range parts[3:] { + parts := strings.SplitN(extra, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q\n", m.Name, t.Name, i+4, extra) + } + switch parts[0] { + case "name": + protoExtra[parts[0]] = parts[1] + case "casttype", "castkey", "castvalue": + parts[0] = fmt.Sprintf("(gogoproto.%s)", parts[0]) + protoExtra[parts[0]] = strconv.Quote(parts[1]) + } + } + + field.Extras = protoExtra + if name, ok := protoExtra["name"]; ok { + field.Name = name + delete(protoExtra, "name") + } + + return nil +} + +func membersToFields(locator ProtobufLocator, t *types.Type, localPackage types.Name, omitFieldTypes map[types.Name]struct{}) ([]protoField, error) { + fields := []protoField{} + + for _, m := range t.Members { + if namer.IsPrivateGoName(m.Name) { + // skip private fields + continue + } + if _, ok := omitFieldTypes[types.Name{Name: m.Type.Name.Name, Package: m.Type.Name.Package}]; ok { + continue + } + tags := reflect.StructTag(m.Tags) + field := protoField{ + LocalPackage: localPackage, + + Tag: -1, + Extras: make(map[string]string), + } + + protobufTag := tags.Get("protobuf") + if protobufTag == "-" { + continue + } + + if err := protobufTagToField(protobufTag, &field, m, t, localPackage); err != nil { + return nil, err + } + + // extract information from JSON field tag + if tag := tags.Get("json"); len(tag) > 0 { + parts := strings.Split(tag, ",") + if len(field.Name) == 0 && len(parts[0]) != 0 { + field.Name = parts[0] + } + if field.Tag == -1 && field.Name == "-" { + continue + } + } + + if field.Type == nil { + if err := memberTypeToProtobufField(locator, &field, m.Type); err != nil { + return nil, fmt.Errorf("unable to embed type %q as field %q in %q: %v", m.Type, field.Name, t.Name, err) + } + } + if len(field.Name) == 0 { + field.Name = namer.IL(m.Name) + } + + if field.Map && field.Repeated { + // maps cannot be repeated + field.Repeated = false + field.Nullable = true + } + + if !field.Nullable { + field.Extras["(gogoproto.nullable)"] = "false" + } + if (field.Type.Name.Name == "bytes" && field.Type.Name.Package == "") || (field.Repeated && field.Type.Name.Package == "" && namer.IsPrivateGoName(field.Type.Name.Name)) { + delete(field.Extras, "(gogoproto.nullable)") + } + if field.Name != m.Name { + field.Extras["(gogoproto.customname)"] = strconv.Quote(m.Name) + } + field.CommentLines = m.CommentLines + fields = append(fields, field) + } + + // assign tags + highest := 0 + byTag := make(map[int]*protoField) + // fields are in Go struct order, which we preserve + for i := range fields { + field := &fields[i] + tag := field.Tag + if tag != -1 { + if existing, ok := byTag[tag]; ok { + return nil, fmt.Errorf("field %q and %q both have tag %d", field.Name, existing.Name, tag) + } + byTag[tag] = field + } + if tag > highest { + highest = tag + } + } + // starting from the highest observed tag, assign new field tags + for i := range fields { + field := &fields[i] + if field.Tag != -1 { + continue + } + highest++ + field.Tag = highest + byTag[field.Tag] = field + } + return fields, nil +} + +func genComment(out io.Writer, lines []string, indent string) { + for { + l := len(lines) + if l == 0 || len(lines[l-1]) != 0 { + break + } + lines = lines[:l-1] + } + for _, c := range lines { + if len(c) == 0 { + fmt.Fprintf(out, "%s//\n", indent) // avoid trailing whitespace + continue + } + fmt.Fprintf(out, "%s// %s\n", indent, c) + } +} + +func formatProtoFile(source []byte) ([]byte, error) { + // TODO; Is there any protobuf formatter? + return source, nil +} + +func assembleProtoFile(w io.Writer, f *generator.File) { + w.Write(f.Header) + + fmt.Fprint(w, "syntax = 'proto2';\n\n") + + if len(f.PackageName) > 0 { + fmt.Fprintf(w, "package %s;\n\n", f.PackageName) + } + + if len(f.Imports) > 0 { + imports := []string{} + for i := range f.Imports { + imports = append(imports, i) + } + sort.Strings(imports) + for _, s := range imports { + fmt.Fprintf(w, "import %q;\n", s) + } + fmt.Fprint(w, "\n") + } + + if f.Vars.Len() > 0 { + fmt.Fprintf(w, "%s\n", f.Vars.String()) + } + + w.Write(f.Body.Bytes()) +} + +func NewProtoFile() *generator.DefaultFileType { + return &generator.DefaultFileType{ + Format: formatProtoFile, + Assemble: assembleProtoFile, + } +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go new file mode 100644 index 0000000000..08a991b155 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go @@ -0,0 +1,50 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +type ImportTracker struct { + namer.DefaultImportTracker +} + +func NewImportTracker(local types.Name, typesToAdd ...*types.Type) *ImportTracker { + tracker := namer.NewDefaultImportTracker(local) + tracker.IsInvalidType = func(t *types.Type) bool { return t.Kind != types.Protobuf } + tracker.LocalName = func(name types.Name) string { return name.Package } + tracker.PrintImport = func(path, name string) string { return path } + + tracker.AddTypes(typesToAdd...) + return &ImportTracker{ + DefaultImportTracker: tracker, + } +} + +// AddNullable ensures that support for the nullable Gogo-protobuf extension is added. +func (tracker *ImportTracker) AddNullable() { + tracker.AddType(&types.Type{ + Kind: types.Protobuf, + Name: types.Name{ + Name: "nullable", + Package: "gogoproto", + Path: "github.com/gogo/protobuf/gogoproto/gogo.proto", + }, + }) +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go new file mode 100644 index 0000000000..e3b21c6703 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go @@ -0,0 +1,208 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "fmt" + "reflect" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +type localNamer struct { + localPackage types.Name +} + +func (n localNamer) Name(t *types.Type) string { + if t.Key != nil && t.Elem != nil { + return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) + } + if len(n.localPackage.Package) != 0 && n.localPackage.Package == t.Name.Package { + return t.Name.Name + } + return t.Name.String() +} + +type protobufNamer struct { + packages []*protobufPackage + packagesByPath map[string]*protobufPackage +} + +func NewProtobufNamer() *protobufNamer { + return &protobufNamer{ + packagesByPath: make(map[string]*protobufPackage), + } +} + +func (n *protobufNamer) Name(t *types.Type) string { + if t.Kind == types.Map { + return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) + } + return t.Name.String() +} + +func (n *protobufNamer) List() []generator.Package { + packages := make([]generator.Package, 0, len(n.packages)) + for i := range n.packages { + packages = append(packages, n.packages[i]) + } + return packages +} + +func (n *protobufNamer) Add(p *protobufPackage) { + if _, ok := n.packagesByPath[p.PackagePath]; !ok { + n.packagesByPath[p.PackagePath] = p + n.packages = append(n.packages, p) + } +} + +func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name { + if p, ok := n.packagesByPath[name.Package]; ok { + return types.Name{ + Name: name.Name, + Package: p.PackageName, + Path: p.ImportPath(), + } + } + for _, p := range n.packages { + if _, ok := p.FilterTypes[name]; ok { + return types.Name{ + Name: name.Name, + Package: p.PackageName, + Path: p.ImportPath(), + } + } + } + return types.Name{Name: name.Name} +} + +func protoSafePackage(name string) string { + pkg := strings.Replace(name, "/", ".", -1) + return strings.Replace(pkg, "-", "_", -1) +} + +type typeNameSet map[types.Name]*protobufPackage + +// assignGoTypeToProtoPackage looks for Go and Protobuf types that are referenced by a type in +// a package. It will not recurse into protobuf types. +func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global typeNameSet, optional map[types.Name]struct{}) { + newT, isProto := isFundamentalProtoType(t) + if isProto { + t = newT + } + if otherP, ok := global[t.Name]; ok { + if _, ok := local[t.Name]; !ok { + p.Imports.AddType(&types.Type{ + Kind: types.Protobuf, + Name: otherP.ProtoTypeName(), + }) + } + return + } + if t.Name.Package == p.PackagePath { + // Associate types only to their own package + global[t.Name] = p + } + if _, ok := local[t.Name]; ok { + return + } + // don't recurse into existing proto types + if isProto { + p.Imports.AddType(t) + return + } + + local[t.Name] = p + for _, m := range t.Members { + if namer.IsPrivateGoName(m.Name) { + continue + } + field := &protoField{} + tag := reflect.StructTag(m.Tags).Get("protobuf") + if tag == "-" { + continue + } + if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil { + assignGoTypeToProtoPackage(p, field.Type, local, global, optional) + continue + } + assignGoTypeToProtoPackage(p, m.Type, local, global, optional) + } + // TODO: should methods be walked? + if t.Elem != nil { + assignGoTypeToProtoPackage(p, t.Elem, local, global, optional) + } + if t.Key != nil { + assignGoTypeToProtoPackage(p, t.Key, local, global, optional) + } + if t.Underlying != nil { + if t.Kind == types.Alias && isOptionalAlias(t) { + optional[t.Name] = struct{}{} + } + assignGoTypeToProtoPackage(p, t.Underlying, local, global, optional) + } +} + +// isTypeApplicableToProtobuf checks to see if a type is relevant for protobuf processing. +// Currently, it filters out functions and private types. +func isTypeApplicableToProtobuf(t *types.Type) bool { + // skip functions -- we don't care about them for protobuf + if t.Kind == types.Func || (t.Kind == types.DeclarationOf && t.Underlying.Kind == types.Func) { + return false + } + // skip private types + if namer.IsPrivateGoName(t.Name.Name) { + return false + } + + return true +} + +func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error { + global := make(typeNameSet) + for _, p := range n.packages { + local := make(typeNameSet) + optional := make(map[types.Name]struct{}) + p.Imports = NewImportTracker(p.ProtoTypeName()) + for _, t := range c.Order { + if t.Name.Package != p.PackagePath { + continue + } + if !isTypeApplicableToProtobuf(t) { + // skip types that we don't care about, like functions + continue + } + assignGoTypeToProtoPackage(p, t, local, global, optional) + } + p.FilterTypes = make(map[types.Name]struct{}) + p.LocalNames = make(map[string]struct{}) + p.OptionalTypeNames = make(map[string]struct{}) + for k, v := range local { + if v == p { + p.FilterTypes[k] = struct{}{} + p.LocalNames[k.Name] = struct{}{} + if _, ok := optional[k]; ok { + p.OptionalTypeNames[k.Name] = struct{}{} + } + } + } + } + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go new file mode 100644 index 0000000000..bed4c3e306 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go @@ -0,0 +1,215 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "fmt" + "go/ast" + "log" + "os" + "path/filepath" + "reflect" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/types" +) + +func newProtobufPackage(packagePath, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage { + pkg := &protobufPackage{ + DefaultPackage: generator.DefaultPackage{ + // The protobuf package name (foo.bar.baz) + PackageName: packageName, + // A path segment relative to the GOPATH root (foo/bar/baz) + PackagePath: packagePath, + HeaderText: []byte( + ` +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +`), + PackageDocumentation: []byte(fmt.Sprintf( + `// Package %s is an autogenerated protobuf IDL. +`, packageName)), + }, + GenerateAll: generateAll, + OmitFieldTypes: omitFieldTypes, + } + pkg.FilterFunc = pkg.filterFunc + pkg.GeneratorFunc = pkg.generatorFunc + return pkg +} + +// protobufPackage contains the protobuf implementation of Package. +type protobufPackage struct { + generator.DefaultPackage + + // If true, this package has been vendored into our source tree and thus can + // only be generated by changing the vendor tree. + Vendored bool + + // If true, generate protobuf serializations for all public types. + // If false, only generate protobuf serializations for structs that + // request serialization. + GenerateAll bool + + // A list of types to filter to; if not specified all types will be included. + FilterTypes map[types.Name]struct{} + + // If true, omit any gogoprotobuf extensions not defined as types. + OmitGogo bool + + // A list of field types that will be excluded from the output struct + OmitFieldTypes map[types.Name]struct{} + + // A list of names that this package exports + LocalNames map[string]struct{} + + // A list of type names in this package that will need marshaller rewriting + // to remove synthetic protobuf fields. + OptionalTypeNames map[string]struct{} + + // A list of struct tags to generate onto named struct fields + StructTags map[string]map[string]string + + // An import tracker for this package + Imports *ImportTracker +} + +func (p *protobufPackage) Clean(outputBase string) error { + for _, s := range []string{p.ImportPath(), p.OutputPath()} { + if err := os.Remove(filepath.Join(outputBase, s)); err != nil && !os.IsNotExist(err) { + return err + } + } + return nil +} + +func (p *protobufPackage) ProtoTypeName() types.Name { + return types.Name{ + Name: p.Path(), // the go path "foo/bar/baz" + Package: p.Name(), // the protobuf package "foo.bar.baz" + Path: p.ImportPath(), // the path of the import to get the proto + } +} + +func (p *protobufPackage) filterFunc(c *generator.Context, t *types.Type) bool { + switch t.Kind { + case types.Func, types.Chan: + return false + case types.Struct: + if t.Name.Name == "struct{}" { + return false + } + case types.Builtin: + return false + case types.Alias: + if !isOptionalAlias(t) { + return false + } + case types.Slice, types.Array, types.Map: + return false + case types.Pointer: + return false + } + if _, ok := isFundamentalProtoType(t); ok { + return false + } + _, ok := p.FilterTypes[t.Name] + return ok +} + +func (p *protobufPackage) HasGoType(name string) bool { + _, ok := p.LocalNames[name] + return ok +} + +func (p *protobufPackage) OptionalTypeName(name string) bool { + _, ok := p.OptionalTypeNames[name] + return ok +} + +func (p *protobufPackage) ExtractGeneratedType(t *ast.TypeSpec) bool { + if !p.HasGoType(t.Name.Name) { + return false + } + + switch s := t.Type.(type) { + case *ast.StructType: + for i, f := range s.Fields.List { + if len(f.Tag.Value) == 0 { + continue + } + tag := strings.Trim(f.Tag.Value, "`") + protobufTag := reflect.StructTag(tag).Get("protobuf") + if len(protobufTag) == 0 { + continue + } + if len(f.Names) > 1 { + log.Printf("WARNING: struct %s field %d %s: defined multiple names but single protobuf tag", t.Name.Name, i, f.Names[0].Name) + // TODO hard error? + } + if p.StructTags == nil { + p.StructTags = make(map[string]map[string]string) + } + m := p.StructTags[t.Name.Name] + if m == nil { + m = make(map[string]string) + p.StructTags[t.Name.Name] = m + } + m[f.Names[0].Name] = tag + } + default: + log.Printf("WARNING: unexpected Go AST type definition: %#v", t) + } + + return true +} + +func (p *protobufPackage) generatorFunc(c *generator.Context) []generator.Generator { + generators := []generator.Generator{} + + p.Imports.AddNullable() + + generators = append(generators, &genProtoIDL{ + DefaultGen: generator.DefaultGen{ + OptionalName: "generated", + }, + localPackage: types.Name{Package: p.PackageName, Path: p.PackagePath}, + localGoPackage: types.Name{Package: p.PackagePath, Name: p.GoPackageName()}, + imports: p.Imports, + generateAll: p.GenerateAll, + omitGogo: p.OmitGogo, + omitFieldTypes: p.OmitFieldTypes, + }) + return generators +} + +func (p *protobufPackage) GoPackageName() string { + return filepath.Base(p.PackagePath) +} + +func (p *protobufPackage) ImportPath() string { + return filepath.Join(p.PackagePath, "generated.proto") +} + +func (p *protobufPackage) OutputPath() string { + return filepath.Join(p.PackagePath, "generated.pb.go") +} + +var ( + _ = generator.Package(&protobufPackage{}) +) diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go new file mode 100644 index 0000000000..305b718edb --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go @@ -0,0 +1,452 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "bytes" + "errors" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/printer" + "go/token" + "io/ioutil" + "os" + "reflect" + "strings" + + customreflect "k8s.io/code-generator/third_party/forked/golang/reflect" +) + +func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error { + fset := token.NewFileSet() + src, err := ioutil.ReadFile(name) + if err != nil { + return err + } + file, err := parser.ParseFile(fset, name, src, parser.DeclarationErrors|parser.ParseComments) + if err != nil { + return err + } + + if err := rewriteFn(fset, file); err != nil { + return err + } + + b := &bytes.Buffer{} + b.Write(header) + if err := printer.Fprint(b, fset, file); err != nil { + return err + } + + body, err := format.Source(b.Bytes()) + if err != nil { + return err + } + + f, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer f.Close() + if _, err := f.Write(body); err != nil { + return err + } + return f.Close() +} + +// ExtractFunc extracts information from the provided TypeSpec and returns true if the type should be +// removed from the destination file. +type ExtractFunc func(*ast.TypeSpec) bool + +// OptionalFunc returns true if the provided local name is a type that has protobuf.nullable=true +// and should have its marshal functions adjusted to remove the 'Items' accessor. +type OptionalFunc func(name string) bool + +func RewriteGeneratedGogoProtobufFile(name string, extractFn ExtractFunc, optionalFn OptionalFunc, header []byte) error { + return rewriteFile(name, header, func(fset *token.FileSet, file *ast.File) error { + cmap := ast.NewCommentMap(fset, file, file.Comments) + + // transform methods that point to optional maps or slices + for _, d := range file.Decls { + rewriteOptionalMethods(d, optionalFn) + } + + // remove types that are already declared + decls := []ast.Decl{} + for _, d := range file.Decls { + if dropExistingTypeDeclarations(d, extractFn) { + continue + } + if dropEmptyImportDeclarations(d) { + continue + } + decls = append(decls, d) + } + file.Decls = decls + + // remove unmapped comments + file.Comments = cmap.Filter(file).Comments() + return nil + }) +} + +// rewriteOptionalMethods makes specific mutations to marshaller methods that belong to types identified +// as being "optional" (they may be nil on the wire). This allows protobuf to serialize a map or slice and +// properly discriminate between empty and nil (which is not possible in protobuf). +// TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181 +// has agreement +func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) { + switch t := decl.(type) { + case *ast.FuncDecl: + ident, ptr, ok := receiver(t) + if !ok { + return + } + + // correct initialization of the form `m.Field = &OptionalType{}` to + // `m.Field = OptionalType{}` + if t.Name.Name == "Unmarshal" { + ast.Walk(optionalAssignmentVisitor{fn: isOptional}, t.Body) + } + + if !isOptional(ident.Name) { + return + } + + switch t.Name.Name { + case "Unmarshal": + ast.Walk(&optionalItemsVisitor{}, t.Body) + case "MarshalTo", "Size", "String": + ast.Walk(&optionalItemsVisitor{}, t.Body) + fallthrough + case "Marshal": + // if the method has a pointer receiver, set it back to a normal receiver + if ptr { + t.Recv.List[0].Type = ident + } + } + } +} + +type optionalAssignmentVisitor struct { + fn OptionalFunc +} + +// Visit walks the provided node, transforming field initializations of the form +// m.Field = &OptionalType{} -> m.Field = OptionalType{} +func (v optionalAssignmentVisitor) Visit(n ast.Node) ast.Visitor { + switch t := n.(type) { + case *ast.AssignStmt: + if len(t.Lhs) == 1 && len(t.Rhs) == 1 { + if !isFieldSelector(t.Lhs[0], "m", "") { + return nil + } + unary, ok := t.Rhs[0].(*ast.UnaryExpr) + if !ok || unary.Op != token.AND { + return nil + } + composite, ok := unary.X.(*ast.CompositeLit) + if !ok || composite.Type == nil || len(composite.Elts) != 0 { + return nil + } + if ident, ok := composite.Type.(*ast.Ident); ok && v.fn(ident.Name) { + t.Rhs[0] = composite + } + } + return nil + } + return v +} + +type optionalItemsVisitor struct{} + +// Visit walks the provided node, looking for specific patterns to transform that match +// the effective outcome of turning struct{ map[x]y || []x } into map[x]y or []x. +func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor { + switch t := n.(type) { + case *ast.RangeStmt: + if isFieldSelector(t.X, "m", "Items") { + t.X = &ast.Ident{Name: "m"} + } + case *ast.AssignStmt: + if len(t.Lhs) == 1 && len(t.Rhs) == 1 { + switch lhs := t.Lhs[0].(type) { + case *ast.IndexExpr: + if isFieldSelector(lhs.X, "m", "Items") { + lhs.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + default: + if isFieldSelector(t.Lhs[0], "m", "Items") { + t.Lhs[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + switch rhs := t.Rhs[0].(type) { + case *ast.CallExpr: + if ident, ok := rhs.Fun.(*ast.Ident); ok && ident.Name == "append" { + ast.Walk(v, rhs) + if len(rhs.Args) > 0 { + switch arg := rhs.Args[0].(type) { + case *ast.Ident: + if arg.Name == "m" { + rhs.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + return nil + } + } + } + case *ast.IfStmt: + switch cond := t.Cond.(type) { + case *ast.BinaryExpr: + if cond.Op == token.EQL { + if isFieldSelector(cond.X, "m", "Items") && isIdent(cond.Y, "nil") { + cond.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + if t.Init != nil { + // Find form: + // if err := m[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { + // return err + // } + switch s := t.Init.(type) { + case *ast.AssignStmt: + if call, ok := s.Rhs[0].(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if x, ok := sel.X.(*ast.IndexExpr); ok { + // m[] -> (*m)[] + if sel2, ok := x.X.(*ast.SelectorExpr); ok { + if ident, ok := sel2.X.(*ast.Ident); ok && ident.Name == "m" { + x.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + // len(m.Items) -> len(*m) + if bin, ok := x.Index.(*ast.BinaryExpr); ok { + if call2, ok := bin.X.(*ast.CallExpr); ok && len(call2.Args) == 1 { + if isFieldSelector(call2.Args[0], "m", "Items") { + call2.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + } + } + } + } + } + case *ast.IndexExpr: + if isFieldSelector(t.X, "m", "Items") { + t.X = &ast.Ident{Name: "m"} + return nil + } + case *ast.CallExpr: + changed := false + for i := range t.Args { + if isFieldSelector(t.Args[i], "m", "Items") { + t.Args[i] = &ast.Ident{Name: "m"} + changed = true + } + } + if changed { + return nil + } + } + return v +} + +func isFieldSelector(n ast.Expr, name, field string) bool { + s, ok := n.(*ast.SelectorExpr) + if !ok || s.Sel == nil || (field != "" && s.Sel.Name != field) { + return false + } + return isIdent(s.X, name) +} + +func isIdent(n ast.Expr, value string) bool { + ident, ok := n.(*ast.Ident) + return ok && ident.Name == value +} + +func receiver(f *ast.FuncDecl) (ident *ast.Ident, pointer bool, ok bool) { + if f.Recv == nil || len(f.Recv.List) != 1 { + return nil, false, false + } + switch t := f.Recv.List[0].Type.(type) { + case *ast.StarExpr: + identity, ok := t.X.(*ast.Ident) + if !ok { + return nil, false, false + } + return identity, true, true + case *ast.Ident: + return t, false, true + } + return nil, false, false +} + +// dropExistingTypeDeclarations removes any type declaration for which extractFn returns true. The function +// returns true if the entire declaration should be dropped. +func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool { + switch t := decl.(type) { + case *ast.GenDecl: + if t.Tok != token.TYPE { + return false + } + specs := []ast.Spec{} + for _, s := range t.Specs { + switch spec := s.(type) { + case *ast.TypeSpec: + if extractFn(spec) { + continue + } + specs = append(specs, spec) + } + } + if len(specs) == 0 { + return true + } + t.Specs = specs + } + return false +} + +// dropEmptyImportDeclarations strips any generated but no-op imports from the generated code +// to prevent generation from being able to define side-effects. The function returns true +// if the entire declaration should be dropped. +func dropEmptyImportDeclarations(decl ast.Decl) bool { + switch t := decl.(type) { + case *ast.GenDecl: + if t.Tok != token.IMPORT { + return false + } + specs := []ast.Spec{} + for _, s := range t.Specs { + switch spec := s.(type) { + case *ast.ImportSpec: + if spec.Name != nil && spec.Name.Name == "_" { + continue + } + specs = append(specs, spec) + } + } + if len(specs) == 0 { + return true + } + t.Specs = specs + } + return false +} + +func RewriteTypesWithProtobufStructTags(name string, structTags map[string]map[string]string) error { + return rewriteFile(name, []byte{}, func(fset *token.FileSet, file *ast.File) error { + allErrs := []error{} + + // set any new struct tags + for _, d := range file.Decls { + if errs := updateStructTags(d, structTags, []string{"protobuf"}); len(errs) > 0 { + allErrs = append(allErrs, errs...) + } + } + + if len(allErrs) > 0 { + var s string + for _, err := range allErrs { + s += err.Error() + "\n" + } + return errors.New(s) + } + return nil + }) +} + +func updateStructTags(decl ast.Decl, structTags map[string]map[string]string, toCopy []string) []error { + var errs []error + t, ok := decl.(*ast.GenDecl) + if !ok { + return nil + } + if t.Tok != token.TYPE { + return nil + } + + for _, s := range t.Specs { + spec, ok := s.(*ast.TypeSpec) + if !ok { + continue + } + typeName := spec.Name.Name + fieldTags, ok := structTags[typeName] + if !ok { + continue + } + st, ok := spec.Type.(*ast.StructType) + if !ok { + continue + } + + for i := range st.Fields.List { + f := st.Fields.List[i] + var name string + if len(f.Names) == 0 { + switch t := f.Type.(type) { + case *ast.Ident: + name = t.Name + case *ast.SelectorExpr: + name = t.Sel.Name + default: + errs = append(errs, fmt.Errorf("unable to get name for tag from struct %q, field %#v", spec.Name.Name, t)) + continue + } + } else { + name = f.Names[0].Name + } + value, ok := fieldTags[name] + if !ok { + continue + } + var tags customreflect.StructTags + if f.Tag != nil { + oldTags, err := customreflect.ParseStructTags(strings.Trim(f.Tag.Value, "`")) + if err != nil { + errs = append(errs, fmt.Errorf("unable to read struct tag from struct %q, field %q: %v", spec.Name.Name, name, err)) + continue + } + tags = oldTags + } + for _, name := range toCopy { + // don't overwrite existing tags + if tags.Has(name) { + continue + } + // append new tags + if v := reflect.StructTag(value).Get(name); len(v) > 0 { + tags = append(tags, customreflect.StructTag{Name: name, Value: v}) + } + } + if len(tags) == 0 { + continue + } + if f.Tag == nil { + f.Tag = &ast.BasicLit{} + } + f.Tag.Value = tags.String() + } + } + return errs +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go new file mode 100644 index 0000000000..8e2a1917d0 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go @@ -0,0 +1,33 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if +// it exists, the value is boolean. If the tag did not exist, it returns +// false. +func extractBoolTagOrDie(key string, lines []string) bool { + val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) + if err != nil { + klog.Fatal(err) + } + return val +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go new file mode 100644 index 0000000000..6e5051dce1 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go @@ -0,0 +1,32 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package main defines the protoc-gen-gogo binary we use to generate our proto go files, +// as well as takes dependencies on the correct gogo/protobuf packages for godeps. +package main + +import ( + "github.com/gogo/protobuf/vanity/command" + + // dependencies that are required for our packages + _ "github.com/gogo/protobuf/gogoproto" + _ "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/sortkeys" +) + +func main() { + command.Write(command.Generate(command.Read())) +} diff --git a/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore b/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore new file mode 100644 index 0000000000..a5c47b66f8 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore @@ -0,0 +1 @@ +import-boss diff --git a/vendor/k8s.io/code-generator/cmd/import-boss/main.go b/vendor/k8s.io/code-generator/cmd/import-boss/main.go new file mode 100644 index 0000000000..c0f10c3a49 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/import-boss/main.go @@ -0,0 +1,90 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// import-boss enforces import restrictions in a given repository. +// +// When a directory is verified, import-boss looks for a file called +// ".import-restrictions". If this file is not found, parent directories will be +// recursively searched. +// +// If an ".import-restrictions" file is found, then all imports of the package +// are checked against each "rule" in the file. A rule consists of three parts: +// * A SelectorRegexp, to select the import paths that the rule applies to. +// * A list of AllowedPrefixes +// * A list of ForbiddenPrefixes +// An import is allowed if it matches at least one allowed prefix and does not +// match any forbidden prefix. An example file looks like this: +// +// { +// "Rules": [ +// { +// "SelectorRegexp": "k8s[.]io", +// "AllowedPrefixes": [ +// "k8s.io/gengo/examples", +// "k8s.io/kubernetes/third_party" +// ], +// "ForbiddenPrefixes": [ +// "k8s.io/kubernetes/pkg/third_party/deprecated" +// ] +// }, +// { +// "SelectorRegexp": "^unsafe$", +// "AllowedPrefixes": [ +// ], +// "ForbiddenPrefixes": [ +// "" +// ] +// } +// ] +// } +// +// Note the second block explicitly matches the unsafe package, and forbids it +// ("" is a prefix of everything). +package main + +import ( + "os" + "path/filepath" + + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/import-boss/generators" + + "k8s.io/klog" +) + +func main() { + klog.InitFlags(nil) + arguments := args.Default() + + // Override defaults. + arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + arguments.InputDirs = []string{ + "k8s.io/kubernetes/pkg/...", + "k8s.io/kubernetes/cmd/...", + "k8s.io/kubernetes/plugin/...", + } + + if err := arguments.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Errorf("Error: %v", err) + os.Exit(1) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/informer-gen/args/args.go new file mode 100644 index 0000000000..ba7f720917 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/args/args.go @@ -0,0 +1,77 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + "path" + + "github.com/spf13/pflag" + codegenutil "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs struct { + VersionedClientSetPackage string + InternalClientSetPackage string + ListersPackage string + SingleDirectory bool +} + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{ + SingleDirectory: false, + } + genericArgs.CustomArgs = customArgs + + if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 { + genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/informers") + customArgs.VersionedClientSetPackage = path.Join(pkg, "pkg/client/clientset/versioned") + customArgs.InternalClientSetPackage = path.Join(pkg, "pkg/client/clientset/internalversion") + customArgs.ListersPackage = path.Join(pkg, "pkg/client/listers") + } + + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&ca.InternalClientSetPackage, "internal-clientset-package", ca.InternalClientSetPackage, "the full package name for the internal clientset to use") + fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned clientset to use") + fs.StringVar(&ca.ListersPackage, "listers-package", ca.ListersPackage, "the full package name for the listers to use") + fs.BoolVar(&ca.SingleDirectory, "single-directory", ca.SingleDirectory, "if true, omit the intermediate \"internalversion\" and \"externalversions\" subdirectories") +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + customArgs := genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputPackagePath) == 0 { + return fmt.Errorf("output package cannot be empty") + } + if len(customArgs.VersionedClientSetPackage) == 0 { + return fmt.Errorf("versioned clientset package cannot be empty") + } + if len(customArgs.ListersPackage) == 0 { + return fmt.Errorf("listers package cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factory.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factory.go new file mode 100644 index 0000000000..62ae109a4a --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factory.go @@ -0,0 +1,258 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "path" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// factoryGenerator produces a file of listers for a given GroupVersion and +// type. +type factoryGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + groupVersions map[string]clientgentypes.GroupVersions + gvGoNames map[string]string + clientSetPackage string + internalInterfacesPackage string + filtered bool +} + +var _ generator.Generator = &factoryGenerator{} + +func (g *factoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *factoryGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *factoryGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *factoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + gvInterfaces := make(map[string]*types.Type) + gvNewFuncs := make(map[string]*types.Type) + for groupPkgName := range g.groupVersions { + gvInterfaces[groupPkgName] = c.Universe.Type(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "Interface"}) + gvNewFuncs[groupPkgName] = c.Universe.Function(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "New"}) + } + m := map[string]interface{}{ + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "groupVersions": g.groupVersions, + "gvInterfaces": gvInterfaces, + "gvNewFuncs": gvNewFuncs, + "gvGoNames": g.gvGoNames, + "interfacesNewInformerFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "NewInformerFunc"}), + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "informerFactoryInterface": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "clientSetInterface": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "reflectType": c.Universe.Type(reflectType), + "runtimeObject": c.Universe.Type(runtimeObject), + "schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource), + "syncMutex": c.Universe.Type(syncMutex), + "timeDuration": c.Universe.Type(timeDuration), + "namespaceAll": c.Universe.Type(metav1NamespaceAll), + "object": c.Universe.Type(metav1Object), + } + + sw.Do(sharedInformerFactoryStruct, m) + sw.Do(sharedInformerFactoryInterface, m) + + return sw.Error() +} + +var sharedInformerFactoryStruct = ` +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client {{.clientSetInterface|raw}} + namespace string + tweakListOptions {{.interfacesTweakListOptionsFunc|raw}} + lock {{.syncMutex|raw}} + defaultResync {{.timeDuration|raw}} + customResync map[{{.reflectType|raw}}]{{.timeDuration|raw}} + + informers map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}} + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[{{.reflectType|raw}}]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[{{.object|raw}}]{{.timeDuration|raw}}) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}, namespace string, tweakListOptions {{.interfacesTweakListOptionsFunc|raw}}) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}}), + startedInformers: make(map[{{.reflectType|raw}}]bool), + customResync: make(map[{{.reflectType|raw}}]{{.timeDuration|raw}}), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func()map[reflect.Type]cache.SharedIndexInformer{ + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj {{.runtimeObject|raw}}, newFunc {{.interfacesNewInformerFunc|raw}}) {{.cacheSharedIndexInformer|raw}} { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +` + +var sharedInformerFactoryInterface = ` +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + {{.informerFactoryInterface|raw}} + ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + {{$gvInterfaces := .gvInterfaces}} + {{$gvGoNames := .gvGoNames}} + {{range $groupName, $group := .groupVersions}}{{index $gvGoNames $groupName}}() {{index $gvInterfaces $groupName|raw}} + {{end}} +} + +{{$gvNewFuncs := .gvNewFuncs}} +{{$gvGoNames := .gvGoNames}} +{{range $groupPkgName, $group := .groupVersions}} +func (f *sharedInformerFactory) {{index $gvGoNames $groupPkgName}}() {{index $gvInterfaces $groupPkgName|raw}} { + return {{index $gvNewFuncs $groupPkgName|raw}}(f, f.namespace, f.tweakListOptions) +} +{{end}} +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factoryinterface.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factoryinterface.go new file mode 100644 index 0000000000..fc0668c5be --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/factoryinterface.go @@ -0,0 +1,90 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// factoryInterfaceGenerator produces a file of interfaces used to break a dependency cycle for +// informer registration +type factoryInterfaceGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + clientSetPackage string + filtered bool +} + +var _ generator.Generator = &factoryInterfaceGenerator{} + +func (g *factoryInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *factoryInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *factoryInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *factoryInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "clientSetPackage": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "runtimeObject": c.Universe.Type(runtimeObject), + "timeDuration": c.Universe.Type(timeDuration), + "v1ListOptions": c.Universe.Type(v1ListOptions), + } + + sw.Do(externalSharedInformerFactoryInterface, m) + + return sw.Error() +} + +var externalSharedInformerFactoryInterface = ` +// NewInformerFunc takes {{.clientSetPackage|raw}} and {{.timeDuration|raw}} to return a SharedIndexInformer. +type NewInformerFunc func({{.clientSetPackage|raw}}, {{.timeDuration|raw}}) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj {{.runtimeObject|raw}}, newFunc NewInformerFunc) {{.cacheSharedIndexInformer|raw}} +} + +// TweakListOptionsFunc is a function that transforms a {{.v1ListOptions|raw}}. +type TweakListOptionsFunc func(*{{.v1ListOptions|raw}}) +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/generic.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/generic.go new file mode 100644 index 0000000000..54632de053 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/generic.go @@ -0,0 +1,180 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "sort" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// genericGenerator generates the generic informer. +type genericGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + groupVersions map[string]clientgentypes.GroupVersions + groupGoNames map[string]string + typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type + filtered bool +} + +var _ generator.Generator = &genericGenerator{} + +func (g *genericGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *genericGenerator) Namers(c *generator.Context) namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + } +} + +func (g *genericGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + imports = append(imports, "fmt") + return +} + +type group struct { + GroupGoName string + Name string + Versions []*version +} + +type groupSort []group + +func (g groupSort) Len() int { return len(g) } +func (g groupSort) Less(i, j int) bool { return strings.ToLower(g[i].Name) < strings.ToLower(g[j].Name) } +func (g groupSort) Swap(i, j int) { g[i], g[j] = g[j], g[i] } + +type version struct { + Name string + GoName string + Resources []*types.Type +} + +type versionSort []*version + +func (v versionSort) Len() int { return len(v) } +func (v versionSort) Less(i, j int) bool { + return strings.ToLower(v[i].Name) < strings.ToLower(v[j].Name) +} +func (v versionSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +func (g *genericGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + groups := []group{} + schemeGVs := make(map[*version]*types.Type) + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + for groupPackageName, groupVersions := range g.groupVersions { + group := group{ + GroupGoName: g.groupGoNames[groupPackageName], + Name: groupVersions.Group.NonEmpty(), + Versions: []*version{}, + } + for _, v := range groupVersions.Versions { + gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v.Version} + version := &version{ + Name: v.Version.NonEmpty(), + GoName: namer.IC(v.Version.NonEmpty()), + Resources: orderer.OrderTypes(g.typesForGroupVersion[gv]), + } + schemeGVs[version] = c.Universe.Variable(types.Name{Package: g.typesForGroupVersion[gv][0].Name.Package, Name: "SchemeGroupVersion"}) + group.Versions = append(group.Versions, version) + } + sort.Sort(versionSort(group.Versions)) + groups = append(groups, group) + } + sort.Sort(groupSort(groups)) + + m := map[string]interface{}{ + "cacheGenericLister": c.Universe.Type(cacheGenericLister), + "cacheNewGenericLister": c.Universe.Function(cacheNewGenericLister), + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "groups": groups, + "schemeGVs": schemeGVs, + "schemaGroupResource": c.Universe.Type(schemaGroupResource), + "schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource), + } + + sw.Do(genericInformer, m) + sw.Do(forResource, m) + + return sw.Error() +} + +var genericInformer = ` +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() {{.cacheSharedIndexInformer|raw}} + Lister() {{.cacheGenericLister|raw}} +} + +type genericInformer struct { + informer {{.cacheSharedIndexInformer|raw}} + resource {{.schemaGroupResource|raw}} +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() {{.cacheSharedIndexInformer|raw}} { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() {{.cacheGenericLister|raw}} { + return {{.cacheNewGenericLister|raw}}(f.Informer().GetIndexer(), f.resource) +} +` + +var forResource = ` +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error) { + switch resource { + {{range $group := .groups -}}{{$GroupGoName := .GroupGoName -}} + {{range $version := .Versions -}} + // Group={{$group.Name}}, Version={{.Name}} + {{range .Resources -}} + case {{index $.schemeGVs $version|raw}}.WithResource("{{.|allLowercasePlural}}"): + return &genericInformer{resource: resource.GroupResource(), informer: f.{{$GroupGoName}}().{{$version.GoName}}().{{.|publicPlural}}().Informer()}, nil + {{end}} + {{end}} + {{end -}} + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/groupinterface.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/groupinterface.go new file mode 100644 index 0000000000..0bba93c4b2 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/groupinterface.go @@ -0,0 +1,118 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "path/filepath" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// groupInterfaceGenerator generates the per-group interface file. +type groupInterfaceGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + groupVersions clientgentypes.GroupVersions + filtered bool + internalInterfacesPackage string +} + +var _ generator.Generator = &groupInterfaceGenerator{} + +func (g *groupInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *groupInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *groupInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +type versionData struct { + Name string + Interface *types.Type + New *types.Type +} + +func (g *groupInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + versions := make([]versionData, 0, len(g.groupVersions.Versions)) + for _, version := range g.groupVersions.Versions { + gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version.Version} + versionPackage := filepath.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty())) + iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"}) + versions = append(versions, versionData{ + Name: namer.IC(version.Version.NonEmpty()), + Interface: iface, + New: c.Universe.Function(types.Name{Package: versionPackage, Name: "New"}), + }) + } + m := map[string]interface{}{ + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "versions": versions, + } + + sw.Do(groupTemplate, m) + + return sw.Error() +} + +var groupTemplate = ` +// Interface provides access to each of this group's versions. +type Interface interface { + $range .versions -$ + // $.Name$ provides access to shared informers for resources in $.Name$. + $.Name$() $.Interface|raw$ + $end$ +} + +type group struct { + factory $.interfacesSharedInformerFactory|raw$ + namespace string + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ +} + +// New returns a new Interface. +func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +$range .versions$ +// $.Name$ returns a new $.Interface|raw$. +func (g *group) $.Name$() $.Interface|raw$ { + return $.New|raw$(g.factory, g.namespace, g.tweakListOptions) +} +$end$ +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/informer.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/informer.go new file mode 100644 index 0000000000..9204d6215a --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/informer.go @@ -0,0 +1,186 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + + "k8s.io/klog" +) + +// informerGenerator produces a file of listers for a given GroupVersion and +// type. +type informerGenerator struct { + generator.DefaultGen + outputPackage string + groupPkgName string + groupVersion clientgentypes.GroupVersion + groupGoName string + typeToGenerate *types.Type + imports namer.ImportTracker + clientSetPackage string + listersPackage string + internalInterfacesPackage string +} + +var _ generator.Generator = &informerGenerator{} + +func (g *informerGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.typeToGenerate +} + +func (g *informerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *informerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + klog.V(5).Infof("processing type %v", t) + + listerPackage := fmt.Sprintf("%s/%s/%s", g.listersPackage, g.groupPkgName, strings.ToLower(g.groupVersion.Version.NonEmpty())) + clientSetInterface := c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}) + informerFor := "InformerFor" + + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + + m := map[string]interface{}{ + "apiScheme": c.Universe.Type(apiScheme), + "cacheIndexers": c.Universe.Type(cacheIndexers), + "cacheListWatch": c.Universe.Type(cacheListWatch), + "cacheMetaNamespaceIndexFunc": c.Universe.Function(cacheMetaNamespaceIndexFunc), + "cacheNamespaceIndex": c.Universe.Variable(cacheNamespaceIndex), + "cacheNewSharedIndexInformer": c.Universe.Function(cacheNewSharedIndexInformer), + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "clientSetInterface": clientSetInterface, + "group": namer.IC(g.groupGoName), + "informerFor": informerFor, + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "listOptions": c.Universe.Type(listOptions), + "lister": c.Universe.Type(types.Name{Package: listerPackage, Name: t.Name.Name + "Lister"}), + "namespaceAll": c.Universe.Type(metav1NamespaceAll), + "namespaced": !tags.NonNamespaced, + "newLister": c.Universe.Function(types.Name{Package: listerPackage, Name: "New" + t.Name.Name + "Lister"}), + "runtimeObject": c.Universe.Type(runtimeObject), + "timeDuration": c.Universe.Type(timeDuration), + "type": t, + "v1ListOptions": c.Universe.Type(v1ListOptions), + "version": namer.IC(g.groupVersion.Version.String()), + "watchInterface": c.Universe.Type(watchInterface), + } + + sw.Do(typeInformerInterface, m) + sw.Do(typeInformerStruct, m) + sw.Do(typeInformerPublicConstructor, m) + sw.Do(typeFilteredInformerPublicConstructor, m) + sw.Do(typeInformerConstructor, m) + sw.Do(typeInformerInformer, m) + sw.Do(typeInformerLister, m) + + return sw.Error() +} + +var typeInformerInterface = ` +// $.type|public$Informer provides access to a shared informer and lister for +// $.type|publicPlural$. +type $.type|public$Informer interface { + Informer() $.cacheSharedIndexInformer|raw$ + Lister() $.lister|raw$ +} +` + +var typeInformerStruct = ` +type $.type|private$Informer struct { + factory $.interfacesSharedInformerFactory|raw$ + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ + $if .namespaced$namespace string$end$ +} +` + +var typeInformerPublicConstructor = ` +// New$.type|public$Informer constructs a new informer for $.type|public$ type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func New$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$) $.cacheSharedIndexInformer|raw$ { + return NewFiltered$.type|public$Informer(client$if .namespaced$, namespace$end$, resyncPeriod, indexers, nil) +} +` + +var typeFilteredInformerPublicConstructor = ` +// NewFiltered$.type|public$Informer constructs a new informer for $.type|public$ type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFiltered$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) $.cacheSharedIndexInformer|raw$ { + return $.cacheNewSharedIndexInformer|raw$( + &$.cacheListWatch|raw${ + ListFunc: func(options $.v1ListOptions|raw$) ($.runtimeObject|raw$, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).List(options) + }, + WatchFunc: func(options $.v1ListOptions|raw$) ($.watchInterface|raw$, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).Watch(options) + }, + }, + &$.type|raw${}, + resyncPeriod, + indexers, + ) +} +` + +var typeInformerConstructor = ` +func (f *$.type|private$Informer) defaultInformer(client $.clientSetInterface|raw$, resyncPeriod $.timeDuration|raw$) $.cacheSharedIndexInformer|raw$ { + return NewFiltered$.type|public$Informer(client$if .namespaced$, f.namespace$end$, resyncPeriod, $.cacheIndexers|raw${$.cacheNamespaceIndex|raw$: $.cacheMetaNamespaceIndexFunc|raw$}, f.tweakListOptions) +} +` + +var typeInformerInformer = ` +func (f *$.type|private$Informer) Informer() $.cacheSharedIndexInformer|raw$ { + return f.factory.$.informerFor$(&$.type|raw${}, f.defaultInformer) +} +` + +var typeInformerLister = ` +func (f *$.type|private$Informer) Lister() $.lister|raw$ { + return $.newLister|raw$(f.Informer().GetIndexer()) +} +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/packages.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/packages.go new file mode 100644 index 0000000000..cfb91cebac --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/packages.go @@ -0,0 +1,352 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "path" + "path/filepath" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + informergenargs "k8s.io/code-generator/cmd/informer-gen/args" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + } +} + +// lowercaseSingularNamer implements Namer +type lowercaseSingularNamer struct{} + +// Name returns t's name in all lowercase. +func (n *lowercaseSingularNamer) Name(t *types.Type) string { + return strings.ToLower(t.Name.Name) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// objectMetaForPackage returns the type of ObjectMeta used by package p. +func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { + generatingForPackage := false + for _, t := range p.Types { + if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient { + continue + } + generatingForPackage = true + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return member.Type, isInternal(member), nil + } + } + } + if generatingForPackage { + return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path) + } + return nil, false, nil +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + return !strings.Contains(m.Tags, "json") +} + +func packageForInternalInterfaces(base string) string { + return filepath.Join(base, "internalinterfaces") +} + +func vendorless(p string) string { + if pos := strings.LastIndex(p, "/vendor/"); pos != -1 { + return p[pos+len("/vendor/"):] + } + return p +} + +// Packages makes the client package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + customArgs, ok := arguments.CustomArgs.(*informergenargs.CustomArgs) + if !ok { + klog.Fatalf("Wrong CustomArgs type: %T", arguments.CustomArgs) + } + + internalVersionPackagePath := filepath.Join(arguments.OutputPackagePath) + externalVersionPackagePath := filepath.Join(arguments.OutputPackagePath) + if !customArgs.SingleDirectory { + internalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "internalversion") + externalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "externalversions") + } + + var packageList generator.Packages + typesForGroupVersion := make(map[clientgentypes.GroupVersion][]*types.Type) + + externalGroupVersions := make(map[string]clientgentypes.GroupVersions) + internalGroupVersions := make(map[string]clientgentypes.GroupVersions) + groupGoNames := make(map[string]string) + for _, inputDir := range arguments.InputDirs { + p := context.Universe.Package(vendorless(inputDir)) + + objectMeta, internal, err := objectMetaForPackage(p) + if err != nil { + klog.Fatal(err) + } + if objectMeta == nil { + // no types in this package had genclient + continue + } + + var gv clientgentypes.GroupVersion + var targetGroupVersions map[string]clientgentypes.GroupVersions + + if internal { + lastSlash := strings.LastIndex(p.Path, "/") + if lastSlash == -1 { + klog.Fatalf("error constructing internal group version for package %q", p.Path) + } + gv.Group = clientgentypes.Group(p.Path[lastSlash+1:]) + targetGroupVersions = internalGroupVersions + } else { + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + targetGroupVersions = externalGroupVersions + } + groupPackageName := gv.Group.NonEmpty() + gvPackage := path.Clean(p.Path) + + // If there's a comment of the form "// +groupName=somegroup" or + // "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the + // group when generating. + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(override[0]) + } + + // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as + // the Go group identifier in CamelCase. It defaults + groupGoNames[groupPackageName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) + if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[groupPackageName] = namer.IC(override[0]) + } + + var typesToGenerate []*types.Type + for _, t := range p.Types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if !tags.GenerateClient || tags.NoVerbs || !tags.HasVerb("list") || !tags.HasVerb("watch") { + continue + } + + typesToGenerate = append(typesToGenerate, t) + + if _, ok := typesForGroupVersion[gv]; !ok { + typesForGroupVersion[gv] = []*types.Type{} + } + typesForGroupVersion[gv] = append(typesForGroupVersion[gv], t) + } + if len(typesToGenerate) == 0 { + continue + } + + groupVersionsEntry, ok := targetGroupVersions[groupPackageName] + if !ok { + groupVersionsEntry = clientgentypes.GroupVersions{ + PackageName: groupPackageName, + Group: gv.Group, + } + } + groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, clientgentypes.PackageVersion{Version: gv.Version, Package: gvPackage}) + targetGroupVersions[groupPackageName] = groupVersionsEntry + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesToGenerate = orderer.OrderTypes(typesToGenerate) + + if internal { + packageList = append(packageList, versionPackage(internalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.InternalClientSetPackage, customArgs.ListersPackage)) + } else { + packageList = append(packageList, versionPackage(externalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.VersionedClientSetPackage, customArgs.ListersPackage)) + } + } + + if len(externalGroupVersions) != 0 { + packageList = append(packageList, factoryInterfacePackage(externalVersionPackagePath, boilerplate, customArgs.VersionedClientSetPackage)) + packageList = append(packageList, factoryPackage(externalVersionPackagePath, boilerplate, groupGoNames, externalGroupVersions, customArgs.VersionedClientSetPackage, typesForGroupVersion)) + for _, gvs := range externalGroupVersions { + packageList = append(packageList, groupPackage(externalVersionPackagePath, gvs, boilerplate)) + } + } + + if len(internalGroupVersions) != 0 { + packageList = append(packageList, factoryInterfacePackage(internalVersionPackagePath, boilerplate, customArgs.InternalClientSetPackage)) + packageList = append(packageList, factoryPackage(internalVersionPackagePath, boilerplate, groupGoNames, internalGroupVersions, customArgs.InternalClientSetPackage, typesForGroupVersion)) + for _, gvs := range internalGroupVersions { + packageList = append(packageList, groupPackage(internalVersionPackagePath, gvs, boilerplate)) + } + } + + return packageList +} + +func factoryPackage(basePackage string, boilerplate []byte, groupGoNames map[string]string, groupVersions map[string]clientgentypes.GroupVersions, clientSetPackage string, typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type) generator.Package { + return &generator.DefaultPackage{ + PackageName: filepath.Base(basePackage), + PackagePath: basePackage, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &factoryGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "factory", + }, + outputPackage: basePackage, + imports: generator.NewImportTracker(), + groupVersions: groupVersions, + clientSetPackage: clientSetPackage, + internalInterfacesPackage: packageForInternalInterfaces(basePackage), + gvGoNames: groupGoNames, + }) + + generators = append(generators, &genericGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "generic", + }, + outputPackage: basePackage, + imports: generator.NewImportTracker(), + groupVersions: groupVersions, + typesForGroupVersion: typesForGroupVersion, + groupGoNames: groupGoNames, + }) + + return generators + }, + } +} + +func factoryInterfacePackage(basePackage string, boilerplate []byte, clientSetPackage string) generator.Package { + packagePath := packageForInternalInterfaces(basePackage) + + return &generator.DefaultPackage{ + PackageName: filepath.Base(packagePath), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &factoryInterfaceGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "factory_interfaces", + }, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + clientSetPackage: clientSetPackage, + }) + + return generators + }, + } +} + +func groupPackage(basePackage string, groupVersions clientgentypes.GroupVersions, boilerplate []byte) generator.Package { + packagePath := filepath.Join(basePackage, groupVersions.PackageName) + groupPkgName := strings.Split(string(groupVersions.Group), ".")[0] + + return &generator.DefaultPackage{ + PackageName: groupPkgName, + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &groupInterfaceGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "interface", + }, + outputPackage: packagePath, + groupVersions: groupVersions, + imports: generator.NewImportTracker(), + internalInterfacesPackage: packageForInternalInterfaces(basePackage), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + } +} + +func versionPackage(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, clientSetPackage, listersPackage string) generator.Package { + packagePath := filepath.Join(basePackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + + return &generator.DefaultPackage{ + PackageName: strings.ToLower(gv.Version.NonEmpty()), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &versionInterfaceGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "interface", + }, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + types: typesToGenerate, + internalInterfacesPackage: packageForInternalInterfaces(basePackage), + }) + + for _, t := range typesToGenerate { + generators = append(generators, &informerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(t.Name.Name), + }, + outputPackage: packagePath, + groupPkgName: groupPkgName, + groupVersion: gv, + groupGoName: groupGoName, + typeToGenerate: t, + imports: generator.NewImportTracker(), + clientSetPackage: clientSetPackage, + listersPackage: listersPackage, + internalInterfacesPackage: packageForInternalInterfaces(basePackage), + }) + } + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + } +} diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/tags.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/tags.go new file mode 100644 index 0000000000..d25d5b6304 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/tags.go @@ -0,0 +1,33 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if +// it exists, the value is boolean. If the tag did not exist, it returns +// false. +func extractBoolTagOrDie(key string, lines []string) bool { + val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) + if err != nil { + klog.Fatal(err) + } + return val +} diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/types.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/types.go new file mode 100644 index 0000000000..27d4bd51ab --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/types.go @@ -0,0 +1,42 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import "k8s.io/gengo/types" + +var ( + apiScheme = types.Name{Package: "k8s.io/kubernetes/pkg/api/legacyscheme", Name: "Scheme"} + cacheGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "GenericLister"} + cacheIndexers = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "Indexers"} + cacheListWatch = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "ListWatch"} + cacheMetaNamespaceIndexFunc = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "MetaNamespaceIndexFunc"} + cacheNamespaceIndex = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NamespaceIndex"} + cacheNewGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewGenericLister"} + cacheNewSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewSharedIndexInformer"} + cacheSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "SharedIndexInformer"} + listOptions = types.Name{Package: "k8s.io/kubernetes/pkg/apis/core", Name: "ListOptions"} + reflectType = types.Name{Package: "reflect", Name: "Type"} + runtimeObject = types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Object"} + schemaGroupResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupResource"} + schemaGroupVersionResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"} + syncMutex = types.Name{Package: "sync", Name: "Mutex"} + timeDuration = types.Name{Package: "time", Name: "Duration"} + v1ListOptions = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"} + metav1NamespaceAll = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "NamespaceAll"} + metav1Object = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "Object"} + watchInterface = types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"} +) diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/generators/versioninterface.go b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/versioninterface.go new file mode 100644 index 0000000000..f80350c5f6 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/generators/versioninterface.go @@ -0,0 +1,109 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// versionInterfaceGenerator generates the per-version interface file. +type versionInterfaceGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + types []*types.Type + filtered bool + internalInterfacesPackage string +} + +var _ generator.Generator = &versionInterfaceGenerator{} + +func (g *versionInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *versionInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *versionInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *versionInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + m := map[string]interface{}{ + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "types": g.types, + } + + sw.Do(versionTemplate, m) + for _, typeDef := range g.types { + tags, err := util.ParseClientGenTags(typeDef.SecondClosestCommentLines) + if err != nil { + return err + } + m["namespaced"] = !tags.NonNamespaced + m["type"] = typeDef + sw.Do(versionFuncTemplate, m) + } + + return sw.Error() +} + +var versionTemplate = ` +// Interface provides access to all the informers in this group version. +type Interface interface { + $range .types -$ + // $.|publicPlural$ returns a $.|public$Informer. + $.|publicPlural$() $.|public$Informer + $end$ +} + +type version struct { + factory $.interfacesSharedInformerFactory|raw$ + namespace string + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ +} + +// New returns a new Interface. +func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} +` + +var versionFuncTemplate = ` +// $.type|publicPlural$ returns a $.type|public$Informer. +func (v *version) $.type|publicPlural$() $.type|public$Informer { + return &$.type|private$Informer{factory: v.factory$if .namespaced$, namespace: v.namespace$end$, tweakListOptions: v.tweakListOptions} +} +` diff --git a/vendor/k8s.io/code-generator/cmd/informer-gen/main.go b/vendor/k8s.io/code-generator/cmd/informer-gen/main.go new file mode 100644 index 0000000000..14f3e923e6 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/informer-gen/main.go @@ -0,0 +1,63 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/informer-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/informer-gen/args" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move out of informer-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/informers/informers_generated" + customArgs.VersionedClientSetPackage = "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" + customArgs.InternalClientSetPackage = "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + customArgs.ListersPackage = "k8s.io/kubernetes/pkg/client/listers" + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/.import-restrictions b/vendor/k8s.io/code-generator/cmd/lister-gen/.import-restrictions new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/.import-restrictions @@ -0,0 +1 @@ +{} diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/lister-gen/args/args.go new file mode 100644 index 0000000000..34914ea8c9 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/args/args.go @@ -0,0 +1,56 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + "path" + + "github.com/spf13/pflag" + codegenutil "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs struct{} + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = customArgs + + if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 { + genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/listers") + } + + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + _ = genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputPackagePath) == 0 { + return fmt.Errorf("output package cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/generators/expansion.go b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/expansion.go new file mode 100644 index 0000000000..dd45d7749c --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/expansion.go @@ -0,0 +1,67 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "os" + "path/filepath" + "strings" + + "k8s.io/gengo/generator" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// expansionGenerator produces a file for a expansion interfaces. +type expansionGenerator struct { + generator.DefaultGen + packagePath string + types []*types.Type +} + +// We only want to call GenerateType() once per group. +func (g *expansionGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.types[0] +} + +func (g *expansionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + for _, t := range g.types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if _, err := os.Stat(filepath.Join(g.packagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) { + sw.Do(expansionInterfaceTemplate, t) + if !tags.NonNamespaced { + sw.Do(namespacedExpansionInterfaceTemplate, t) + } + } + } + return sw.Error() +} + +var expansionInterfaceTemplate = ` +// $.|public$ListerExpansion allows custom methods to be added to +// $.|public$Lister. +type $.|public$ListerExpansion interface {} +` + +var namespacedExpansionInterfaceTemplate = ` +// $.|public$NamespaceListerExpansion allows custom methods to be added to +// $.|public$NamespaceLister. +type $.|public$NamespaceListerExpansion interface {} +` diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/generators/lister.go b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/lister.go new file mode 100644 index 0000000000..c8ed5ad4d3 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/lister.go @@ -0,0 +1,371 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "path/filepath" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + + "k8s.io/klog" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + } +} + +// lowercaseSingularNamer implements Namer +type lowercaseSingularNamer struct{} + +// Name returns t's name in all lowercase. +func (n *lowercaseSingularNamer) Name(t *types.Type) string { + return strings.ToLower(t.Name.Name) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// Packages makes the client package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + var packageList generator.Packages + for _, inputDir := range arguments.InputDirs { + p := context.Universe.Package(inputDir) + + objectMeta, internal, err := objectMetaForPackage(p) + if err != nil { + klog.Fatal(err) + } + if objectMeta == nil { + // no types in this package had genclient + continue + } + + var gv clientgentypes.GroupVersion + var internalGVPkg string + + if internal { + lastSlash := strings.LastIndex(p.Path, "/") + if lastSlash == -1 { + klog.Fatalf("error constructing internal group version for package %q", p.Path) + } + gv.Group = clientgentypes.Group(p.Path[lastSlash+1:]) + internalGVPkg = p.Path + } else { + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + + internalGVPkg = strings.Join(parts[0:len(parts)-1], "/") + } + groupPackageName := strings.ToLower(gv.Group.NonEmpty()) + + // If there's a comment of the form "// +groupName=somegroup" or + // "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the + // group when generating. + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(strings.SplitN(override[0], ".", 2)[0]) + } + + var typesToGenerate []*types.Type + for _, t := range p.Types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if !tags.GenerateClient || !tags.HasVerb("list") || !tags.HasVerb("get") { + continue + } + typesToGenerate = append(typesToGenerate, t) + } + if len(typesToGenerate) == 0 { + continue + } + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesToGenerate = orderer.OrderTypes(typesToGenerate) + + packagePath := filepath.Join(arguments.OutputPackagePath, groupPackageName, strings.ToLower(gv.Version.NonEmpty())) + packageList = append(packageList, &generator.DefaultPackage{ + PackageName: strings.ToLower(gv.Version.NonEmpty()), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &expansionGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "expansion_generated", + }, + packagePath: filepath.Join(arguments.OutputBase, packagePath), + types: typesToGenerate, + }) + + for _, t := range typesToGenerate { + generators = append(generators, &listerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(t.Name.Name), + }, + outputPackage: arguments.OutputPackagePath, + groupVersion: gv, + internalGVPkg: internalGVPkg, + typeToGenerate: t, + imports: generator.NewImportTracker(), + objectMeta: objectMeta, + }) + } + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("get") + }, + }) + } + + return packageList +} + +// objectMetaForPackage returns the type of ObjectMeta used by package p. +func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { + generatingForPackage := false + for _, t := range p.Types { + // filter out types which dont have genclient. + if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient { + continue + } + generatingForPackage = true + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return member.Type, isInternal(member), nil + } + } + } + if generatingForPackage { + return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path) + } + return nil, false, nil +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + return !strings.Contains(m.Tags, "json") +} + +// listerGenerator produces a file of listers for a given GroupVersion and +// type. +type listerGenerator struct { + generator.DefaultGen + outputPackage string + groupVersion clientgentypes.GroupVersion + internalGVPkg string + typeToGenerate *types.Type + imports namer.ImportTracker + objectMeta *types.Type +} + +var _ generator.Generator = &listerGenerator{} + +func (g *listerGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.typeToGenerate +} + +func (g *listerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *listerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + imports = append(imports, "k8s.io/apimachinery/pkg/api/errors") + imports = append(imports, "k8s.io/apimachinery/pkg/labels") + // for Indexer + imports = append(imports, "k8s.io/client-go/tools/cache") + return +} + +func (g *listerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + klog.V(5).Infof("processing type %v", t) + m := map[string]interface{}{ + "Resource": c.Universe.Function(types.Name{Package: t.Name.Package, Name: "Resource"}), + "type": t, + "objectMeta": g.objectMeta, + } + + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + + if tags.NonNamespaced { + sw.Do(typeListerInterface_NonNamespaced, m) + } else { + sw.Do(typeListerInterface, m) + } + + sw.Do(typeListerStruct, m) + sw.Do(typeListerConstructor, m) + sw.Do(typeLister_List, m) + + if tags.NonNamespaced { + sw.Do(typeLister_NonNamespacedGet, m) + return sw.Error() + } + + sw.Do(typeLister_NamespaceLister, m) + sw.Do(namespaceListerInterface, m) + sw.Do(namespaceListerStruct, m) + sw.Do(namespaceLister_List, m) + sw.Do(namespaceLister_Get, m) + + return sw.Error() +} + +var typeListerInterface = ` +// $.type|public$Lister helps list $.type|publicPlural$. +type $.type|public$Lister interface { + // List lists all $.type|publicPlural$ in the indexer. + List(selector labels.Selector) (ret []*$.type|raw$, err error) + // $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$. + $.type|publicPlural$(namespace string) $.type|public$NamespaceLister + $.type|public$ListerExpansion +} +` + +var typeListerInterface_NonNamespaced = ` +// $.type|public$Lister helps list $.type|publicPlural$. +type $.type|public$Lister interface { + // List lists all $.type|publicPlural$ in the indexer. + List(selector labels.Selector) (ret []*$.type|raw$, err error) + // Get retrieves the $.type|public$ from the index for a given name. + Get(name string) (*$.type|raw$, error) + $.type|public$ListerExpansion +} +` + +var typeListerStruct = ` +// $.type|private$Lister implements the $.type|public$Lister interface. +type $.type|private$Lister struct { + indexer cache.Indexer +} +` + +var typeListerConstructor = ` +// New$.type|public$Lister returns a new $.type|public$Lister. +func New$.type|public$Lister(indexer cache.Indexer) $.type|public$Lister { + return &$.type|private$Lister{indexer: indexer} +} +` + +var typeLister_List = ` +// List lists all $.type|publicPlural$ in the indexer. +func (s *$.type|private$Lister) List(selector labels.Selector) (ret []*$.type|raw$, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*$.type|raw$)) + }) + return ret, err +} +` + +var typeLister_NamespaceLister = ` +// $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$. +func (s *$.type|private$Lister) $.type|publicPlural$(namespace string) $.type|public$NamespaceLister { + return $.type|private$NamespaceLister{indexer: s.indexer, namespace: namespace} +} +` + +var typeLister_NonNamespacedGet = ` +// Get retrieves the $.type|public$ from the index for a given name. +func (s *$.type|private$Lister) Get(name string) (*$.type|raw$, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound($.Resource|raw$("$.type|lowercaseSingular$"), name) + } + return obj.(*$.type|raw$), nil +} +` + +var namespaceListerInterface = ` +// $.type|public$NamespaceLister helps list and get $.type|publicPlural$. +type $.type|public$NamespaceLister interface { + // List lists all $.type|publicPlural$ in the indexer for a given namespace. + List(selector labels.Selector) (ret []*$.type|raw$, err error) + // Get retrieves the $.type|public$ from the indexer for a given namespace and name. + Get(name string) (*$.type|raw$, error) + $.type|public$NamespaceListerExpansion +} +` + +var namespaceListerStruct = ` +// $.type|private$NamespaceLister implements the $.type|public$NamespaceLister +// interface. +type $.type|private$NamespaceLister struct { + indexer cache.Indexer + namespace string +} +` + +var namespaceLister_List = ` +// List lists all $.type|publicPlural$ in the indexer for a given namespace. +func (s $.type|private$NamespaceLister) List(selector labels.Selector) (ret []*$.type|raw$, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*$.type|raw$)) + }) + return ret, err +} +` + +var namespaceLister_Get = ` +// Get retrieves the $.type|public$ from the indexer for a given namespace and name. +func (s $.type|private$NamespaceLister) Get(name string) (*$.type|raw$, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound($.Resource|raw$("$.type|lowercaseSingular$"), name) + } + return obj.(*$.type|raw$), nil +} +` diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/generators/tags.go b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/tags.go new file mode 100644 index 0000000000..d25d5b6304 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/generators/tags.go @@ -0,0 +1,33 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if +// it exists, the value is boolean. If the tag did not exist, it returns +// false. +func extractBoolTagOrDie(key string, lines []string) bool { + val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) + if err != nil { + klog.Fatal(err) + } + return val +} diff --git a/vendor/k8s.io/code-generator/cmd/lister-gen/main.go b/vendor/k8s.io/code-generator/cmd/lister-gen/main.go new file mode 100644 index 0000000000..aca16b2bda --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/lister-gen/main.go @@ -0,0 +1,60 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/lister-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/lister-gen/args" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of lister-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/listers" + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go new file mode 100644 index 0000000000..2e3ab084e2 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go @@ -0,0 +1,39 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package args + +import ( + "fmt" + + "k8s.io/gengo/args" +) + +// NewDefaults returns default arguments for the generator. +func NewDefaults() *args.GeneratorArgs { + genericArgs := args.Default().WithoutDefaultFlagParsing() + genericArgs.OutputFileBaseName = "zz_generated.register" + return genericArgs +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + if len(genericArgs.OutputFileBaseName) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go b/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go new file mode 100644 index 0000000000..5186e421f2 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go @@ -0,0 +1,137 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "os" + "path" + "strings" + + "k8s.io/klog" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{} +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// Packages makes packages to generate. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + packages := generator.Packages{} + for _, inputDir := range arguments.InputDirs { + pkg := context.Universe.Package(inputDir) + internal, err := isInternal(pkg) + if err != nil { + klog.V(5).Infof("skipping the generation of %s file, due to err %v", arguments.OutputFileBaseName, err) + continue + } + if internal { + klog.V(5).Infof("skipping the generation of %s file because %s package contains internal types, note that internal types don't have \"json\" tags", arguments.OutputFileBaseName, pkg.Name) + continue + } + registerFileName := "register.go" + searchPath := path.Join(args.DefaultSourceTree(), inputDir, registerFileName) + if _, err := os.Stat(path.Join(searchPath)); err == nil { + klog.V(5).Infof("skipping the generation of %s file because %s already exists in the path %s", arguments.OutputFileBaseName, registerFileName, searchPath) + continue + } else if err != nil && !os.IsNotExist(err) { + klog.Fatalf("an error %v has occurred while checking if %s exists", err, registerFileName) + } + + gv := clientgentypes.GroupVersion{} + { + pathParts := strings.Split(pkg.Path, "/") + if len(pathParts) < 2 { + klog.Errorf("the path of the package must contain the group name and the version, path = %s", pkg.Path) + continue + } + gv.Group = clientgentypes.Group(pathParts[len(pathParts)-2]) + gv.Version = clientgentypes.Version(pathParts[len(pathParts)-1]) + + // if there is a comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", + // extract the fully qualified API group name from it and overwrite the group inferred from the package path + if override := types.ExtractCommentTags("+", pkg.DocComments)["groupName"]; override != nil { + groupName := override[0] + klog.V(5).Infof("overriding the group name with = %s", groupName) + gv.Group = clientgentypes.Group(groupName) + } + } + + typesToRegister := []*types.Type{} + for _, t := range pkg.Types { + klog.V(5).Infof("considering type = %s", t.Name.String()) + for _, typeMember := range t.Members { + if typeMember.Name == "TypeMeta" && typeMember.Embedded == true { + typesToRegister = append(typesToRegister, t) + } + } + } + + packages = append(packages, + &generator.DefaultPackage{ + PackageName: pkg.Name, + PackagePath: pkg.Path, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + ®isterExternalGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: arguments.OutputFileBaseName, + }, + gv: gv, + typesToGenerate: typesToRegister, + outputPackage: pkg.Path, + imports: generator.NewImportTracker(), + }, + } + }, + }) + } + + return packages +} + +// isInternal determines whether the given package +// contains the internal types or not +func isInternal(p *types.Package) (bool, error) { + for _, t := range p.Types { + for _, member := range t.Members { + if member.Name == "TypeMeta" { + return !strings.Contains(member.Tags, "json"), nil + } + } + } + return false, fmt.Errorf("unable to find TypeMeta for any types in package %s", p.Path) +} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go b/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go new file mode 100644 index 0000000000..c831c575d6 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go @@ -0,0 +1,117 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "io" + "sort" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +type registerExternalGenerator struct { + generator.DefaultGen + outputPackage string + gv clientgentypes.GroupVersion + typesToGenerate []*types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = ®isterExternalGenerator{} + +func (g *registerExternalGenerator) Filter(_ *generator.Context, _ *types.Type) bool { + return false +} + +func (g *registerExternalGenerator) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +func (g *registerExternalGenerator) Namers(_ *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *registerExternalGenerator) Finalize(context *generator.Context, w io.Writer) error { + typesToGenerateOnlyNames := make([]string, len(g.typesToGenerate)) + for index, typeToGenerate := range g.typesToGenerate { + typesToGenerateOnlyNames[index] = typeToGenerate.Name.Name + } + + // sort the list of types to register, so that the generator produces stable output + sort.Strings(typesToGenerateOnlyNames) + + sw := generator.NewSnippetWriter(w, context, "$", "$") + m := map[string]interface{}{ + "groupName": g.gv.Group, + "version": g.gv.Version, + "types": typesToGenerateOnlyNames, + "addToGroupVersion": context.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}), + "groupVersion": context.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GroupVersion"}), + } + sw.Do(registerExternalTypesTemplate, m) + return sw.Error() +} + +var registerExternalTypesTemplate = ` +// GroupName specifies the group name used to register the objects. +const GroupName = "$.groupName$" + +// GroupVersion specifies the group and the version used to register the objects. +var GroupVersion = $.groupVersion|raw${Group: GroupName, Version: "$.version$"} + +// SchemeGroupVersion is group version used to register these objects +// Deprecated: use GroupVersion instead. +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "$.version$"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + // Depreciated: use Install instead + AddToScheme = localSchemeBuilder.AddToScheme + Install = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + $range .types -$ + &$.${}, + $end$ + ) + // AddToGroupVersion allows the serialization of client types like ListOptions. + $.addToGroupVersion|raw$(scheme, SchemeGroupVersion) + return nil +} +` diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/main.go b/vendor/k8s.io/code-generator/cmd/register-gen/main.go new file mode 100644 index 0000000000..30a175d8d6 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/register-gen/main.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + "k8s.io/klog" + + generatorargs "k8s.io/code-generator/cmd/register-gen/args" + "k8s.io/code-generator/cmd/register-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" +) + +func main() { + klog.InitFlags(nil) + genericArgs := generatorargs.NewDefaults() + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + + pflag.Parse() + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/set-gen/.gitignore b/vendor/k8s.io/code-generator/cmd/set-gen/.gitignore new file mode 100644 index 0000000000..ffe6458c96 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/set-gen/.gitignore @@ -0,0 +1 @@ +set-gen diff --git a/vendor/k8s.io/code-generator/cmd/set-gen/main.go b/vendor/k8s.io/code-generator/cmd/set-gen/main.go new file mode 100644 index 0000000000..45694d4f33 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/set-gen/main.go @@ -0,0 +1,56 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// set-gen is an example usage of gengo. +// +// Structs in the input directories with the below line in their comments will +// have sets generated for them. +// // +genset +// +// Any builtin type referenced anywhere in the input directories will have a +// set generated for it. +package main + +import ( + "os" + "path/filepath" + + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/gengo/examples/set-gen/generators" + + "k8s.io/klog" +) + +func main() { + klog.InitFlags(nil) + arguments := args.Default() + + // Override defaults. + arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + arguments.InputDirs = []string{"k8s.io/kubernetes/pkg/util/sets/types"} + arguments.OutputPackagePath = "k8s.io/apimachinery/pkg/util/sets" + + if err := arguments.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Errorf("Error: %v", err) + os.Exit(1) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/code-of-conduct.md b/vendor/k8s.io/code-generator/code-of-conduct.md new file mode 100644 index 0000000000..0d15c00cf3 --- /dev/null +++ b/vendor/k8s.io/code-generator/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/k8s.io/code-generator/generate-groups.sh b/vendor/k8s.io/code-generator/generate-groups.sh new file mode 100755 index 0000000000..d8531a8d9d --- /dev/null +++ b/vendor/k8s.io/code-generator/generate-groups.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# generate-groups generates everything for a project with external types only, e.g. a project based +# on CustomResourceDefinitions. + +if [ "$#" -lt 4 ] || [ "${1}" == "--help" ]; then + cat < ... + + the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all". + the output package name (e.g. github.com/example/project/pkg/generated). + the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis). + the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative + to . + ... arbitrary flags passed to all generator binaries. + + +Examples: + $(basename $0) all github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" + $(basename $0) deepcopy,client github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" +EOF + exit 0 +fi + +GENS="$1" +OUTPUT_PKG="$2" +APIS_PKG="$3" +GROUPS_WITH_VERSIONS="$4" +shift 4 + +( + # To support running this script from anywhere, we have to first cd into this directory + # so we can install the tools. + cd $(dirname "${0}") + go install ${GOFLAGS:-} ./cmd/{defaulter-gen,client-gen,lister-gen,informer-gen,deepcopy-gen} +) + +function codegen::join() { local IFS="$1"; shift; echo "$*"; } + +# enumerate group versions +FQ_APIS=() # e.g. k8s.io/api/apps/v1 +for GVs in ${GROUPS_WITH_VERSIONS}; do + IFS=: read G Vs <<<"${GVs}" + + # enumerate versions + for V in ${Vs//,/ }; do + FQ_APIS+=(${APIS_PKG}/${G}/${V}) + done +done + +if [ "${GENS}" = "all" ] || grep -qw "deepcopy" <<<"${GENS}"; then + echo "Generating deepcopy funcs" + ${GOPATH}/bin/deepcopy-gen --input-dirs $(codegen::join , "${FQ_APIS[@]}") -O zz_generated.deepcopy --bounding-dirs ${APIS_PKG} "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "client" <<<"${GENS}"; then + echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}" + ${GOPATH}/bin/client-gen --clientset-name ${CLIENTSET_NAME_VERSIONED:-versioned} --input-base "" --input $(codegen::join , "${FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset} "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "lister" <<<"${GENS}"; then + echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers" + ${GOPATH}/bin/lister-gen --input-dirs $(codegen::join , "${FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/listers "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "informer" <<<"${GENS}"; then + echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers" + ${GOPATH}/bin/informer-gen \ + --input-dirs $(codegen::join , "${FQ_APIS[@]}") \ + --versioned-clientset-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}/${CLIENTSET_NAME_VERSIONED:-versioned} \ + --listers-package ${OUTPUT_PKG}/listers \ + --output-package ${OUTPUT_PKG}/informers \ + "$@" +fi diff --git a/vendor/k8s.io/code-generator/generate-internal-groups.sh b/vendor/k8s.io/code-generator/generate-internal-groups.sh new file mode 100755 index 0000000000..6849ed9437 --- /dev/null +++ b/vendor/k8s.io/code-generator/generate-internal-groups.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# generate-internal-groups generates everything for a project with internal types, e.g. an +# user-provided API server based on k8s.io/apiserver. + +if [ "$#" -lt 5 ] || [ "${1}" == "--help" ]; then + cat < ... + + the generators comma separated to run (deepcopy,defaulter,conversion,client,lister,informer) or "all". + the output package name (e.g. github.com/example/project/pkg/generated). + the internal types dir (e.g. github.com/example/project/pkg/apis). + the external types dir (e.g. github.com/example/project/pkg/apis or githubcom/example/apis). + the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative + to . + ... arbitrary flags passed to all generator binaries. + +Examples: + $(basename $0) all github.com/example/project/pkg/client github.com/example/project/pkg/apis github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" + $(basename $0) deepcopy,defaulter,conversion github.com/example/project/pkg/client github.com/example/project/pkg/apis github.com/example/project/apis "foo:v1 bar:v1alpha1,v1beta1" +EOF + exit 0 +fi + +GENS="$1" +OUTPUT_PKG="$2" +INT_APIS_PKG="$3" +EXT_APIS_PKG="$4" +GROUPS_WITH_VERSIONS="$5" +shift 5 + +go install ${GOFLAGS:-} ./$(dirname "${0}")/cmd/{defaulter-gen,conversion-gen,client-gen,lister-gen,informer-gen,deepcopy-gen} +function codegen::join() { local IFS="$1"; shift; echo "$*"; } + +# enumerate group versions +ALL_FQ_APIS=() # e.g. k8s.io/kubernetes/pkg/apis/apps k8s.io/api/apps/v1 +INT_FQ_APIS=() # e.g. k8s.io/kubernetes/pkg/apis/apps +EXT_FQ_APIS=() # e.g. k8s.io/api/apps/v1 +for GVs in ${GROUPS_WITH_VERSIONS}; do + IFS=: read G Vs <<<"${GVs}" + + if [ -n "${INT_APIS_PKG}" ]; then + ALL_FQ_APIS+=("${INT_APIS_PKG}/${G}") + INT_FQ_APIS+=("${INT_APIS_PKG}/${G}") + fi + + # enumerate versions + for V in ${Vs//,/ }; do + ALL_FQ_APIS+=("${EXT_APIS_PKG}/${G}/${V}") + EXT_FQ_APIS+=("${EXT_APIS_PKG}/${G}/${V}") + done +done + +if [ "${GENS}" = "all" ] || grep -qw "deepcopy" <<<"${GENS}"; then + echo "Generating deepcopy funcs" + ${GOPATH}/bin/deepcopy-gen --input-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") -O zz_generated.deepcopy --bounding-dirs ${INT_APIS_PKG},${EXT_APIS_PKG} "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "defaulter" <<<"${GENS}"; then + echo "Generating defaulters" + ${GOPATH}/bin/defaulter-gen --input-dirs $(codegen::join , "${EXT_FQ_APIS[@]}") -O zz_generated.defaults "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "conversion" <<<"${GENS}"; then + echo "Generating conversions" + ${GOPATH}/bin/conversion-gen --input-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") -O zz_generated.conversion "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "client" <<<"${GENS}"; then + echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}" + if [ -n "${INT_APIS_PKG}" ]; then + ${GOPATH}/bin/client-gen --clientset-name ${CLIENTSET_NAME_INTERNAL:-internalversion} --input-base "" --input $(codegen::join , $(printf '%s/ ' "${INT_FQ_APIS[@]}")) --output-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset} "$@" + fi + ${GOPATH}/bin/client-gen --clientset-name ${CLIENTSET_NAME_VERSIONED:-versioned} --input-base "" --input $(codegen::join , "${EXT_FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset} "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "lister" <<<"${GENS}"; then + echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers" + ${GOPATH}/bin/lister-gen --input-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/listers "$@" +fi + +if [ "${GENS}" = "all" ] || grep -qw "informer" <<<"${GENS}"; then + echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers" + ${GOPATH}/bin/informer-gen \ + --input-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") \ + --versioned-clientset-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}/${CLIENTSET_NAME_VERSIONED:-versioned} \ + --internal-clientset-package ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}/${CLIENTSET_NAME_INTERNAL:-internalversion} \ + --listers-package ${OUTPUT_PKG}/listers \ + --output-package ${OUTPUT_PKG}/informers \ + "$@" +fi diff --git a/vendor/k8s.io/code-generator/hack/boilerplate.go.txt b/vendor/k8s.io/code-generator/hack/boilerplate.go.txt new file mode 100644 index 0000000000..b7c650da47 --- /dev/null +++ b/vendor/k8s.io/code-generator/hack/boilerplate.go.txt @@ -0,0 +1,16 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + diff --git a/vendor/k8s.io/code-generator/hack/update-codegen.sh b/vendor/k8s.io/code-generator/hack/update-codegen.sh new file mode 100755 index 0000000000..2a14fe5277 --- /dev/null +++ b/vendor/k8s.io/code-generator/hack/update-codegen.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# generate the code with: +# - --output-base because this script should also be able to run inside the vendor dir of +# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir +# instead of the $GOPATH directly. For normal projects this can be dropped. +$(dirname ${BASH_SOURCE})/../generate-internal-groups.sh all \ + k8s.io/code-generator/_examples/apiserver k8s.io/code-generator/_examples/apiserver/apis k8s.io/code-generator/_examples/apiserver/apis \ + "example:v1 example2:v1" \ + --output-base "$(dirname ${BASH_SOURCE})/../../.." +$(dirname ${BASH_SOURCE})/../generate-groups.sh all \ + k8s.io/code-generator/_examples/crd k8s.io/code-generator/_examples/crd/apis \ + "example:v1 example2:v1" \ + --output-base "$(dirname ${BASH_SOURCE})/../../.." + $(dirname ${BASH_SOURCE})/../generate-groups.sh all \ + k8s.io/code-generator/_examples/MixedCase k8s.io/code-generator/_examples/MixedCase/apis \ + "example:v1" \ + --output-base "$(dirname ${BASH_SOURCE})/../../.." diff --git a/vendor/k8s.io/code-generator/hack/verify-codegen.sh b/vendor/k8s.io/code-generator/hack/verify-codegen.sh new file mode 100755 index 0000000000..497f2a484c --- /dev/null +++ b/vendor/k8s.io/code-generator/hack/verify-codegen.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. +SCRIPT_BASE=${SCRIPT_ROOT}/../.. + +DIFFROOT="${SCRIPT_ROOT}/_examples" +TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/_examples" +_tmp="${SCRIPT_ROOT}/_tmp" + +cleanup() { + rm -rf "${_tmp}" +} +trap "cleanup" EXIT SIGINT + +cleanup + +mkdir -p "${TMP_DIFFROOT}" +cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" + +"${SCRIPT_ROOT}/hack/update-codegen.sh" +echo "diffing ${DIFFROOT} against freshly generated codegen" +ret=0 +diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? +cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" +if [[ $ret -eq 0 ]] +then + echo "${DIFFROOT} up to date." +else + echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" + exit 1 +fi + +# smoke test +echo "Smoke testing _example by compiling..." +go build ./${SCRIPT_ROOT}/_examples/crd/... +go build ./${SCRIPT_ROOT}/_examples/apiserver/... +go build ./${SCRIPT_ROOT}/_examples/MixedCase/... diff --git a/vendor/k8s.io/code-generator/pkg/util/build.go b/vendor/k8s.io/code-generator/pkg/util/build.go new file mode 100644 index 0000000000..6ea8f52ee0 --- /dev/null +++ b/vendor/k8s.io/code-generator/pkg/util/build.go @@ -0,0 +1,61 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + gobuild "go/build" + "path" + "path/filepath" + "reflect" + "strings" +) + +type empty struct{} + +// CurrentPackage returns the go package of the current directory, or "" if it cannot +// be derived from the GOPATH. +func CurrentPackage() string { + for _, root := range gobuild.Default.SrcDirs() { + if pkg, ok := hasSubdir(root, "."); ok { + return pkg + } + } + return "" +} + +func hasSubdir(root, dir string) (rel string, ok bool) { + // ensure a tailing separator to properly compare on word-boundaries + const sep = string(filepath.Separator) + root = filepath.Clean(root) + if !strings.HasSuffix(root, sep) { + root += sep + } + + // check whether root dir starts with root + dir = filepath.Clean(dir) + if !strings.HasPrefix(dir, root) { + return "", false + } + + // cut off root + return filepath.ToSlash(dir[len(root):]), true +} + +// BoilerplatePath uses the boilerplate in code-generator by calculating the relative path to it. +func BoilerplatePath() string { + return path.Join(reflect.TypeOf(empty{}).PkgPath(), "/../../hack/boilerplate.go.txt") +} diff --git a/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go b/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go new file mode 100644 index 0000000000..67957ee33e --- /dev/null +++ b/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go @@ -0,0 +1,91 @@ +//This package is copied from Go library reflect/type.go. +//The struct tag library provides no way to extract the list of struct tags, only +//a specific tag +package reflect + +import ( + "fmt" + + "strconv" + "strings" +) + +type StructTag struct { + Name string + Value string +} + +func (t StructTag) String() string { + return fmt.Sprintf("%s:%q", t.Name, t.Value) +} + +type StructTags []StructTag + +func (tags StructTags) String() string { + s := make([]string, 0, len(tags)) + for _, tag := range tags { + s = append(s, tag.String()) + } + return "`" + strings.Join(s, " ") + "`" +} + +func (tags StructTags) Has(name string) bool { + for i := range tags { + if tags[i].Name == name { + return true + } + } + return false +} + +// ParseStructTags returns the full set of fields in a struct tag in the order they appear in +// the struct tag. +func ParseStructTags(tag string) (StructTags, error) { + tags := StructTags{} + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + break + } + name := string(tag[:i]) + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + break + } + qvalue := string(tag[:i+1]) + tag = tag[i+1:] + + value, err := strconv.Unquote(qvalue) + if err != nil { + return nil, err + } + tags = append(tags, StructTag{Name: name, Value: value}) + } + return tags, nil +} diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go b/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go new file mode 100644 index 0000000000..7e3bc6b4b1 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go @@ -0,0 +1,828 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "bytes" + "fmt" + "io" + "path/filepath" + "reflect" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// CustomArgs is used tby the go2idl framework to pass args specific to this +// generator. +type CustomArgs struct { + ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions. +} + +// These are the comment tags that carry parameters for defaulter generation. +const tagName = "k8s:defaulter-gen" +const intputTagName = "k8s:defaulter-gen-input" + +func extractTag(comments []string) []string { + return types.ExtractCommentTags("+", comments)[tagName] +} + +func extractInputTag(comments []string) []string { + return types.ExtractCommentTags("+", comments)[intputTagName] +} + +func checkTag(comments []string, require ...string) bool { + values := types.ExtractCommentTags("+", comments)[tagName] + if len(require) == 0 { + return len(values) == 1 && values[0] == "" + } + return reflect.DeepEqual(values, require) +} + +func defaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +func objectDefaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetObjectDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(1), + "raw": namer.NewRawNamer("", nil), + "defaultfn": defaultFnNamer(), + "objectdefaultfn": objectDefaultFnNamer(), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// defaults holds the declared defaulting functions for a given type (all defaulting functions +// are expected to be func(1)) +type defaults struct { + // object is the defaulter function for a top level type (typically one with TypeMeta) that + // invokes all child defaulters. May be nil if the object defaulter has not yet been generated. + object *types.Type + // base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all + // child defaults - the base defaulter alone is insufficient to default a type + base *types.Type + // additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be + // included in the Object defaulter. + additional []*types.Type +} + +// All of the types in conversions map are of type "DeclarationOf" with +// the underlying type being "Func". +type defaulterFuncMap map[*types.Type]defaults + +// Returns all manually-defined defaulting functions in the package. +func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) { + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + for _, f := range pkg.Functions { + if f.Underlying == nil || f.Underlying.Kind != types.Func { + klog.Errorf("Malformed function: %#v", f) + continue + } + if f.Underlying.Signature == nil { + klog.Errorf("Function without signature: %#v", f) + continue + } + signature := f.Underlying.Signature + // Check whether the function is defaulting function. + // Note that all of them have signature: + // object: func SetObjectDefaults_inType(*inType) + // base: func SetDefaults_inType(*inType) + // additional: func SetDefaults_inType_Qualifier(*inType) + if signature.Receiver != nil { + continue + } + if len(signature.Parameters) != 1 { + continue + } + if len(signature.Results) != 0 { + continue + } + inType := signature.Parameters[0] + if inType.Kind != types.Pointer { + continue + } + // Check if this is the primary defaulter. + args := defaultingArgsFromType(inType.Elem) + sw.Do("$.inType|defaultfn$", args) + switch { + case f.Name.Name == buffer.String(): + key := inType.Elem + // We might scan the same package twice, and that's OK. + v, ok := manualMap[key] + if ok && v.base != nil && v.base.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) + } + v.base = f + manualMap[key] = v + klog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name) + // Is one of the additional defaulters - a top level defaulter on a type that is + // also invoked. + case strings.HasPrefix(f.Name.Name, buffer.String()+"_"): + key := inType.Elem + v, ok := manualMap[key] + if ok { + exists := false + for _, existing := range v.additional { + if existing.Name == f.Name { + exists = true + break + } + } + if exists { + continue + } + } + v.additional = append(v.additional, f) + manualMap[key] = v + klog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name) + } + buffer.Reset() + sw.Do("$.inType|objectdefaultfn$", args) + if f.Name.Name == buffer.String() { + key := inType.Elem + // We might scan the same package twice, and that's OK. + v, ok := manualMap[key] + if ok && v.base != nil && v.base.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) + } + v.object = f + manualMap[key] = v + klog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name) + } + buffer.Reset() + } +} + +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + packages := generator.Packages{} + header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) + + // Accumulate pre-existing default functions. + // TODO: This is too ad-hoc. We need a better way. + existingDefaulters := defaulterFuncMap{} + + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + // We are generating defaults only for packages that are explicitly + // passed as InputDir. + for _, i := range context.Inputs { + klog.V(5).Infof("considering pkg %q", i) + pkg := context.Universe[i] + if pkg == nil { + // If the input had no Go files, for example. + continue + } + // typesPkg is where the types that needs defaulter are defined. + // Sometimes it is different from pkg. For example, kubernetes core/v1 + // types are defined in vendor/k8s.io/api/core/v1, while pkg is at + // pkg/api/v1. + typesPkg := pkg + + // Add defaulting functions. + getManualDefaultingFunctions(context, pkg, existingDefaulters) + + var peerPkgs []string + if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok { + for _, pkg := range customArgs.ExtraPeerDirs { + if i := strings.Index(pkg, "/vendor/"); i != -1 { + pkg = pkg[i+len("/vendor/"):] + } + peerPkgs = append(peerPkgs, pkg) + } + } + // Make sure our peer-packages are added and fully parsed. + for _, pp := range peerPkgs { + context.AddDir(pp) + getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters) + } + + typesWith := extractTag(pkg.Comments) + shouldCreateObjectDefaulterFn := func(t *types.Type) bool { + if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil { + // A default generator is defined + klog.V(5).Infof(" an object defaulter already exists as %s", defaults.base.Name) + return false + } + // opt-out + if checkTag(t.SecondClosestCommentLines, "false") { + return false + } + // opt-in + if checkTag(t.SecondClosestCommentLines, "true") { + return true + } + // For every k8s:defaulter-gen tag at the package level, interpret the value as a + // field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation + // for any type with any of the matching field names. Provides a more useful package + // level defaulting than global (because we only need defaulters on a subset of objects - + // usually those with TypeMeta). + if t.Kind == types.Struct && len(typesWith) > 0 { + for _, field := range t.Members { + for _, s := range typesWith { + if field.Name == s { + return true + } + } + } + } + return false + } + + // if the types are not in the same package where the defaulter functions to be generated + inputTags := extractInputTag(pkg.Comments) + if len(inputTags) > 1 { + panic(fmt.Sprintf("there could only be one input tag, got %#v", inputTags)) + } + if len(inputTags) == 1 { + var err error + typesPkg, err = context.AddDirectory(filepath.Join(pkg.Path, inputTags[0])) + if err != nil { + klog.Fatalf("cannot import package %s", inputTags[0]) + } + // update context.Order to the latest context.Universe + orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)} + context.Order = orderer.OrderUniverse(context.Universe) + } + + newDefaulters := defaulterFuncMap{} + for _, t := range typesPkg.Types { + if !shouldCreateObjectDefaulterFn(t) { + continue + } + if namer.IsPrivateGoName(t.Name.Name) { + // We won't be able to convert to a private type. + klog.V(5).Infof(" found a type %v, but it is a private name", t) + continue + } + + // create a synthetic type we can use during generation + newDefaulters[t] = defaults{} + } + + // only generate defaulters for objects that actually have defined defaulters + // prevents empty defaulters from being registered + for { + promoted := 0 + for t, d := range newDefaulters { + if d.object != nil { + continue + } + if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil { + args := defaultingArgsFromType(t) + sw.Do("$.inType|objectdefaultfn$", args) + newDefaulters[t] = defaults{ + object: &types.Type{ + Name: types.Name{ + Package: pkg.Path, + Name: buffer.String(), + }, + Kind: types.Func, + }, + } + buffer.Reset() + promoted++ + } + } + if promoted != 0 { + continue + } + + // prune any types that were not used + for t, d := range newDefaulters { + if d.object == nil { + klog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name) + delete(newDefaulters, t) + } + } + break + } + + if len(newDefaulters) == 0 { + klog.V(5).Infof("no defaulters in package %s", pkg.Name) + } + + path := pkg.Path + // if the source path is within a /vendor/ directory (for example, + // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow + // generation to output to the proper relative path (under vendor). + // Otherwise, the generator will create the file in the wrong location + // in the output directory. + // TODO: build a more fundamental concept in gengo for dealing with modifications + // to vendored packages. + if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) { + expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase) + if strings.Contains(expandedPath, "/vendor/") { + path = expandedPath + } + } + + packages = append(packages, + &generator.DefaultPackage{ + PackageName: filepath.Base(pkg.Path), + PackagePath: path, + HeaderText: header, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenDefaulter(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs), + } + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == typesPkg.Path + }, + }) + } + return packages +} + +// callTreeForType contains fields necessary to build a tree for types. +type callTreeForType struct { + existingDefaulters defaulterFuncMap + newDefaulters defaulterFuncMap + currentlyBuildingTypes map[*types.Type]bool +} + +func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType { + return &callTreeForType{ + existingDefaulters: existingDefaulters, + newDefaulters: newDefaulters, + currentlyBuildingTypes: make(map[*types.Type]bool), + } +} + +// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem, +// slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree +// can be used to generate a Go function that invokes each nested function on the appropriate type. The return +// value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be +// invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should +// contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters +// that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil, +// this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for +// list types that call empty defaulters. +func (c *callTreeForType) build(t *types.Type, root bool) *callNode { + parent := &callNode{} + + if root { + // the root node is always a pointer + parent.elem = true + } + + defaults, _ := c.existingDefaulters[t] + newDefaults, generated := c.newDefaulters[t] + switch { + case !root && generated && newDefaults.object != nil: + parent.call = append(parent.call, newDefaults.object) + // if we will be generating the defaulter, it by definition is a covering + // defaulter, so we halt recursion + klog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name) + return parent + + case defaults.object != nil: + // object defaulters are always covering + parent.call = append(parent.call, defaults.object) + return parent + + case defaults.base != nil: + parent.call = append(parent.call, defaults.base) + // if the base function indicates it "covers" (it already includes defaulters) + // we can halt recursion + if checkTag(defaults.base.CommentLines, "covers") { + klog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name) + return parent + } + } + + // base has been added already, now add any additional defaulters defined for this object + parent.call = append(parent.call, defaults.additional...) + + // if the type already exists, don't build the tree for it and don't generate anything. + // This is used to avoid recursion for nested recursive types. + if c.currentlyBuildingTypes[t] { + return nil + } + // if type doesn't exist, mark it as existing + c.currentlyBuildingTypes[t] = true + + defer func() { + // The type will now acts as a parent, not a nested recursive type. + // We can now build the tree for it safely. + c.currentlyBuildingTypes[t] = false + }() + + switch t.Kind { + case types.Pointer: + if child := c.build(t.Elem, false); child != nil { + child.elem = true + parent.children = append(parent.children, *child) + } + case types.Slice, types.Array: + if child := c.build(t.Elem, false); child != nil { + child.index = true + if t.Elem.Kind == types.Pointer { + child.elem = true + } + parent.children = append(parent.children, *child) + } + case types.Map: + if child := c.build(t.Elem, false); child != nil { + child.key = true + parent.children = append(parent.children, *child) + } + case types.Struct: + for _, field := range t.Members { + name := field.Name + if len(name) == 0 { + if field.Type.Kind == types.Pointer { + name = field.Type.Elem.Name.Name + } else { + name = field.Type.Name.Name + } + } + if child := c.build(field.Type, false); child != nil { + child.field = name + parent.children = append(parent.children, *child) + } + } + case types.Alias: + if child := c.build(t.Underlying, false); child != nil { + parent.children = append(parent.children, *child) + } + } + if len(parent.children) == 0 && len(parent.call) == 0 { + //klog.V(6).Infof("decided type %s needs no generation", t.Name) + return nil + } + return parent +} + +const ( + runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" + conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" +) + +// genDefaulter produces a file with a autogenerated conversions. +type genDefaulter struct { + generator.DefaultGen + typesPackage string + outputPackage string + peerPackages []string + newDefaulters defaulterFuncMap + existingDefaulters defaulterFuncMap + imports namer.ImportTracker + typesForInit []*types.Type +} + +func NewGenDefaulter(sanitizedName, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { + return &genDefaulter{ + DefaultGen: generator.DefaultGen{ + OptionalName: sanitizedName, + }, + typesPackage: typesPackage, + outputPackage: outputPackage, + peerPackages: peerPkgs, + newDefaulters: newDefaulters, + existingDefaulters: existingDefaulters, + imports: generator.NewImportTracker(), + typesForInit: make([]*types.Type, 0), + } +} + +func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genDefaulter) isOtherPackage(pkg string) bool { + if pkg == g.outputPackage { + return false + } + if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) { + return false + } + return true +} + +func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool { + defaults, ok := g.newDefaulters[t] + if !ok || defaults.object == nil { + return false + } + g.typesForInit = append(g.typesForInit, t) + return true +} + +func (g *genDefaulter) Imports(c *generator.Context) (imports []string) { + var importLines []string + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"}) + schemePtr := &types.Type{ + Kind: types.Pointer, + Elem: scheme, + } + sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil) + sw.Do("// Public to allow building arbitrary schemes.\n", nil) + sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil) + sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr) + for _, t := range g.typesForInit { + args := defaultingArgsFromType(t) + sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args) + } + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + return sw.Error() +} + +func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + if _, ok := g.newDefaulters[t]; !ok { + return nil + } + + klog.V(5).Infof("generating for type %v", t) + + callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true) + if callTree == nil { + klog.V(5).Infof(" no defaulters defined") + return nil + } + i := 0 + callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) { + if len(current.call) == 0 { + return + } + path := callPath(append(ancestors, current)) + klog.V(5).Infof(" %d: %s", i, path) + i++ + }) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + g.generateDefaulter(t, callTree, sw) + return sw.Error() +} + +func defaultingArgsFromType(inType *types.Type) generator.Args { + return generator.Args{ + "inType": inType, + } +} + +func (g *genDefaulter) generateDefaulter(inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) { + sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType)) + callTree.WriteMethod("in", 0, nil, sw) + sw.Do("}\n\n", nil) +} + +// callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents +// how in Go code an access would be performed. For example, if a defaulting function exists on a container +// lifecycle hook, to invoke that defaulter correctly would require this Go code: +// +// for i := range pod.Spec.Containers { +// o := &pod.Spec.Containers[i] +// if o.LifecycleHook != nil { +// SetDefaults_LifecycleHook(o.LifecycleHook) +// } +// } +// +// That would be represented by a call tree like: +// +// callNode +// field: "Spec" +// children: +// - field: "Containers" +// children: +// - index: true +// children: +// - field: "LifecycleHook" +// elem: true +// call: +// - SetDefaults_LifecycleHook +// +// which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over +// that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on +// the pointer to that field). +type callNode struct { + // field is the name of the Go member to access + field string + // key is true if this is a map and we must range over the key and values + key bool + // index is true if this is a slice and we must range over the slice values + index bool + // elem is true if the previous elements refer to a pointer (typically just field) + elem bool + + // call is all of the functions that must be invoked on this particular node, in order + call []*types.Type + // children is the child call nodes that must also be traversed + children []callNode +} + +// CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents +// of this node to the root of the tree - will be empty at the root. +type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode) + +func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) { + n.visitInOrder(nil, fn) +} + +func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) { + fn(ancestors, n) + ancestors = append(ancestors, n) + for i := range n.children { + n.children[i].visitInOrder(ancestors, fn) + } +} + +var ( + indexVariables = "ijklmnop" + localVariables = "abcdefgh" +) + +// varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes +// of this depth in a function. It uses canonical Go loop variables for the first 7 levels +// and then resorts to uglier prefixes. +func varsForDepth(depth int) (index, local string) { + if depth > len(indexVariables) { + index = fmt.Sprintf("i%d", depth) + } else { + index = indexVariables[depth : depth+1] + } + if depth > len(localVariables) { + local = fmt.Sprintf("local%d", depth) + } else { + local = localVariables[depth : depth+1] + } + return +} + +// writeCalls generates a list of function calls based on the calls field for the provided variable +// name and pointer. +func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) { + accessor := varName + if !isVarPointer { + accessor = "&" + accessor + } + for _, fn := range n.call { + sw.Do("$.fn|raw$($.var$)\n", generator.Args{ + "fn": fn, + "var": accessor, + }) + } +} + +// WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary +// to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree. +// Depth is used to generate local variables at the proper depth. +func (n *callNode) WriteMethod(varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) { + // if len(n.call) > 0 { + // sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil) + // } + + if len(n.field) > 0 { + varName = varName + "." + n.field + } + + index, local := varsForDepth(depth) + vars := generator.Args{ + "index": index, + "local": local, + "var": varName, + } + + isPointer := n.elem && !n.index + if isPointer && len(ancestors) > 0 { + sw.Do("if $.var$ != nil {\n", vars) + } + + switch { + case n.index: + sw.Do("for $.index$ := range $.var$ {\n", vars) + if n.elem { + sw.Do("$.local$ := $.var$[$.index$]\n", vars) + } else { + sw.Do("$.local$ := &$.var$[$.index$]\n", vars) + } + + n.writeCalls(local, true, sw) + for i := range n.children { + n.children[i].WriteMethod(local, depth+1, append(ancestors, n), sw) + } + sw.Do("}\n", nil) + case n.key: + default: + n.writeCalls(varName, isPointer, sw) + for i := range n.children { + n.children[i].WriteMethod(varName, depth, append(ancestors, n), sw) + } + } + + if isPointer && len(ancestors) > 0 { + sw.Do("}\n", nil) + } +} + +type callPath []*callNode + +// String prints a representation of a callPath that roughly approximates what a Go accessor +// would look like. Used for debugging only. +func (path callPath) String() string { + if len(path) == 0 { + return "" + } + var parts []string + for _, p := range path { + last := len(parts) - 1 + switch { + case p.elem: + if len(parts) > 0 { + parts[last] = "*" + parts[last] + } else { + parts = append(parts, "*") + } + case p.index: + if len(parts) > 0 { + parts[last] = parts[last] + "[i]" + } else { + parts = append(parts, "[i]") + } + case p.key: + if len(parts) > 0 { + parts[last] = parts[last] + "[key]" + } else { + parts = append(parts, "[key]") + } + default: + if len(p.field) > 0 { + parts = append(parts, p.field) + } else { + parts = append(parts, "") + } + } + } + var calls []string + for _, fn := range path[len(path)-1].call { + calls = append(calls, fn.Name.String()) + } + if len(calls) == 0 { + calls = append(calls, "") + } + + return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ") +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/BUILD b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/BUILD new file mode 100644 index 0000000000..e8a08011f3 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/BUILD @@ -0,0 +1,102 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = [ + "balanced_resource_allocation.go", + "image_locality.go", + "interpod_affinity.go", + "least_requested.go", + "metadata.go", + "most_requested.go", + "node_affinity.go", + "node_label.go", + "node_prefer_avoid_pods.go", + "reduce.go", + "requested_to_capacity_ratio.go", + "resource_allocation.go", + "resource_limits.go", + "selector_spreading.go", + "taint_toleration.go", + "test_util.go", + ], + importpath = "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities", + deps = [ + "//pkg/apis/core/v1/helper:go_default_library", + "//pkg/features:go_default_library", + "//pkg/scheduler/algorithm:go_default_library", + "//pkg/scheduler/algorithm/predicates:go_default_library", + "//pkg/scheduler/algorithm/priorities/util:go_default_library", + "//pkg/scheduler/api:go_default_library", + "//pkg/scheduler/cache:go_default_library", + "//pkg/util/node:go_default_library", + "//pkg/util/parsers:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "balanced_resource_allocation_test.go", + "image_locality_test.go", + "interpod_affinity_test.go", + "least_requested_test.go", + "main_test.go", + "metadata_test.go", + "most_requested_test.go", + "node_affinity_test.go", + "node_label_test.go", + "node_prefer_avoid_pods_test.go", + "requested_to_capacity_ratio_test.go", + "resource_limits_test.go", + "selector_spreading_test.go", + "taint_toleration_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//pkg/features:go_default_library", + "//pkg/kubelet/apis:go_default_library", + "//pkg/scheduler/algorithm/priorities/util:go_default_library", + "//pkg/scheduler/api:go_default_library", + "//pkg/scheduler/cache:go_default_library", + "//pkg/scheduler/testing:go_default_library", + "//pkg/util/parsers:go_default_library", + "//staging/src/k8s.io/api/apps/v1:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//pkg/scheduler/algorithm/priorities/util:all-srcs", + ], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/balanced_resource_allocation.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/balanced_resource_allocation.go new file mode 100644 index 0000000000..c77dd399d5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/balanced_resource_allocation.go @@ -0,0 +1,77 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "math" + + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +var ( + balancedResourcePriority = &ResourceAllocationPriority{"BalancedResourceAllocation", balancedResourceScorer} + + // BalancedResourceAllocationMap favors nodes with balanced resource usage rate. + // BalancedResourceAllocationMap should **NOT** be used alone, and **MUST** be used together + // with LeastRequestedPriority. It calculates the difference between the cpu and memory fraction + // of capacity, and prioritizes the host based on how close the two metrics are to each other. + // Detail: score = 10 - variance(cpuFraction,memoryFraction,volumeFraction)*10. The algorithm is partly inspired by: + // "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced + // Resource Utilization" + BalancedResourceAllocationMap = balancedResourcePriority.PriorityMap +) + +func balancedResourceScorer(requested, allocable *schedulercache.Resource, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 { + cpuFraction := fractionOfCapacity(requested.MilliCPU, allocable.MilliCPU) + memoryFraction := fractionOfCapacity(requested.Memory, allocable.Memory) + // This to find a node which has most balanced CPU, memory and volume usage. + if includeVolumes && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && allocatableVolumes > 0 { + volumeFraction := float64(requestedVolumes) / float64(allocatableVolumes) + if cpuFraction >= 1 || memoryFraction >= 1 || volumeFraction >= 1 { + // if requested >= capacity, the corresponding host should never be preferred. + return 0 + } + // Compute variance for all the three fractions. + mean := (cpuFraction + memoryFraction + volumeFraction) / float64(3) + variance := float64((((cpuFraction - mean) * (cpuFraction - mean)) + ((memoryFraction - mean) * (memoryFraction - mean)) + ((volumeFraction - mean) * (volumeFraction - mean))) / float64(3)) + // Since the variance is between positive fractions, it will be positive fraction. 1-variance lets the + // score to be higher for node which has least variance and multiplying it with 10 provides the scaling + // factor needed. + return int64((1 - variance) * float64(schedulerapi.MaxPriority)) + } + + if cpuFraction >= 1 || memoryFraction >= 1 { + // if requested >= capacity, the corresponding host should never be preferred. + return 0 + } + // Upper and lower boundary of difference between cpuFraction and memoryFraction are -1 and 1 + // respectively. Multiplying the absolute value of the difference by 10 scales the value to + // 0-10 with 0 representing well balanced allocation and 10 poorly balanced. Subtracting it from + // 10 leads to the score which also scales from 0 to 10 while 10 representing well balanced. + diff := math.Abs(cpuFraction - memoryFraction) + return int64((1 - diff) * float64(schedulerapi.MaxPriority)) +} + +func fractionOfCapacity(requested, capacity int64) float64 { + if capacity == 0 { + return 1 + } + return float64(requested) / float64(capacity) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/image_locality.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/image_locality.go new file mode 100644 index 0000000000..041e52d4fc --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/image_locality.go @@ -0,0 +1,109 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + "strings" + + "k8s.io/api/core/v1" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" + "k8s.io/kubernetes/pkg/util/parsers" +) + +// The two thresholds are used as bounds for the image score range. They correspond to a reasonable size range for +// container images compressed and stored in registries; 90%ile of images on dockerhub drops into this range. +const ( + mb int64 = 1024 * 1024 + minThreshold int64 = 23 * mb + maxThreshold int64 = 1000 * mb +) + +// ImageLocalityPriorityMap is a priority function that favors nodes that already have requested pod container's images. +// It will detect whether the requested images are present on a node, and then calculate a score ranging from 0 to 10 +// based on the total size of those images. +// - If none of the images are present, this node will be given the lowest priority. +// - If some of the images are present on a node, the larger their sizes' sum, the higher the node's priority. +func ImageLocalityPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + + var score int + if priorityMeta, ok := meta.(*priorityMetadata); ok { + score = calculatePriority(sumImageScores(nodeInfo, pod.Spec.Containers, priorityMeta.totalNumNodes)) + } else { + // if we are not able to parse priority meta data, skip this priority + score = 0 + } + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: score, + }, nil +} + +// calculatePriority returns the priority of a node. Given the sumScores of requested images on the node, the node's +// priority is obtained by scaling the maximum priority value with a ratio proportional to the sumScores. +func calculatePriority(sumScores int64) int { + if sumScores < minThreshold { + sumScores = minThreshold + } else if sumScores > maxThreshold { + sumScores = maxThreshold + } + + return int(int64(schedulerapi.MaxPriority) * (sumScores - minThreshold) / (maxThreshold - minThreshold)) +} + +// sumImageScores returns the sum of image scores of all the containers that are already on the node. +// Each image receives a raw score of its size, scaled by scaledImageScore. The raw scores are later used to calculate +// the final score. Note that the init containers are not considered for it's rare for users to deploy huge init containers. +func sumImageScores(nodeInfo *schedulercache.NodeInfo, containers []v1.Container, totalNumNodes int) int64 { + var sum int64 + imageStates := nodeInfo.ImageStates() + + for _, container := range containers { + if state, ok := imageStates[normalizedImageName(container.Image)]; ok { + sum += scaledImageScore(state, totalNumNodes) + } + } + + return sum +} + +// scaledImageScore returns an adaptively scaled score for the given state of an image. +// The size of the image is used as the base score, scaled by a factor which considers how much nodes the image has "spread" to. +// This heuristic aims to mitigate the undesirable "node heating problem", i.e., pods get assigned to the same or +// a few nodes due to image locality. +func scaledImageScore(imageState *schedulercache.ImageStateSummary, totalNumNodes int) int64 { + spread := float64(imageState.NumNodes) / float64(totalNumNodes) + return int64(float64(imageState.Size) * spread) +} + +// normalizedImageName returns the CRI compliant name for a given image. +// TODO: cover the corner cases of missed matches, e.g, +// 1. Using Docker as runtime and docker.io/library/test:tag in pod spec, but only test:tag will present in node status +// 2. Using the implicit registry, i.e., test:tag or library/test:tag in pod spec but only docker.io/library/test:tag +// in node status; note that if users consistently use one registry format, this should not happen. +func normalizedImageName(name string) string { + if strings.LastIndex(name, ":") <= strings.LastIndex(name, "/") { + name = name + ":" + parsers.DefaultImageTag + } + return name +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/interpod_affinity.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/interpod_affinity.go new file mode 100644 index 0000000000..32cf27c83b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/interpod_affinity.go @@ -0,0 +1,241 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "context" + "sync" + + "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/workqueue" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates" + priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" + + "k8s.io/klog" +) + +// InterPodAffinity contains information to calculate inter pod affinity. +type InterPodAffinity struct { + info predicates.NodeInfo + nodeLister algorithm.NodeLister + podLister algorithm.PodLister + hardPodAffinityWeight int32 +} + +// NewInterPodAffinityPriority creates an InterPodAffinity. +func NewInterPodAffinityPriority( + info predicates.NodeInfo, + nodeLister algorithm.NodeLister, + podLister algorithm.PodLister, + hardPodAffinityWeight int32) algorithm.PriorityFunction { + interPodAffinity := &InterPodAffinity{ + info: info, + nodeLister: nodeLister, + podLister: podLister, + hardPodAffinityWeight: hardPodAffinityWeight, + } + return interPodAffinity.CalculateInterPodAffinityPriority +} + +type podAffinityPriorityMap struct { + sync.Mutex + + // nodes contain all nodes that should be considered + nodes []*v1.Node + // counts store the mapping from node name to so-far computed score of + // the node. + counts map[string]float64 + // The first error that we faced. + firstError error +} + +func newPodAffinityPriorityMap(nodes []*v1.Node) *podAffinityPriorityMap { + return &podAffinityPriorityMap{ + nodes: nodes, + counts: make(map[string]float64, len(nodes)), + } +} + +func (p *podAffinityPriorityMap) setError(err error) { + p.Lock() + defer p.Unlock() + if p.firstError == nil { + p.firstError = err + } +} + +func (p *podAffinityPriorityMap) processTerm(term *v1.PodAffinityTerm, podDefiningAffinityTerm, podToCheck *v1.Pod, fixedNode *v1.Node, weight float64) { + namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(podDefiningAffinityTerm, term) + selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector) + if err != nil { + p.setError(err) + return + } + match := priorityutil.PodMatchesTermsNamespaceAndSelector(podToCheck, namespaces, selector) + if match { + func() { + p.Lock() + defer p.Unlock() + for _, node := range p.nodes { + if priorityutil.NodesHaveSameTopologyKey(node, fixedNode, term.TopologyKey) { + p.counts[node.Name] += weight + } + } + }() + } +} + +func (p *podAffinityPriorityMap) processTerms(terms []v1.WeightedPodAffinityTerm, podDefiningAffinityTerm, podToCheck *v1.Pod, fixedNode *v1.Node, multiplier int) { + for i := range terms { + term := &terms[i] + p.processTerm(&term.PodAffinityTerm, podDefiningAffinityTerm, podToCheck, fixedNode, float64(term.Weight*int32(multiplier))) + } +} + +// CalculateInterPodAffinityPriority compute a sum by iterating through the elements of weightedPodAffinityTerm and adding +// "weight" to the sum if the corresponding PodAffinityTerm is satisfied for +// that node; the node(s) with the highest sum are the most preferred. +// Symmetry need to be considered for preferredDuringSchedulingIgnoredDuringExecution from podAffinity & podAntiAffinity, +// symmetry need to be considered for hard requirements from podAffinity +func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { + affinity := pod.Spec.Affinity + hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil + hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil + + allNodeNames := make([]string, 0, len(nodeNameToInfo)) + for name := range nodeNameToInfo { + allNodeNames = append(allNodeNames, name) + } + + // convert the topology key based weights to the node name based weights + var maxCount float64 + var minCount float64 + // priorityMap stores the mapping from node name to so-far computed score of + // the node. + pm := newPodAffinityPriorityMap(nodes) + + processPod := func(existingPod *v1.Pod) error { + existingPodNode, err := ipa.info.GetNodeInfo(existingPod.Spec.NodeName) + if err != nil { + if apierrors.IsNotFound(err) { + klog.Errorf("Node not found, %v", existingPod.Spec.NodeName) + return nil + } + return err + } + existingPodAffinity := existingPod.Spec.Affinity + existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil + existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil + + if hasAffinityConstraints { + // For every soft pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of `s node by the term`s weight. + terms := affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution + pm.processTerms(terms, pod, existingPod, existingPodNode, 1) + } + if hasAntiAffinityConstraints { + // For every soft pod anti-affinity term of , if matches the term, + // decrement for every node in the cluster with the same + // value as that of `s node by the term`s weight. + terms := affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution + pm.processTerms(terms, pod, existingPod, existingPodNode, -1) + } + + if existingHasAffinityConstraints { + // For every hard pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of 's node by the constant + if ipa.hardPodAffinityWeight > 0 { + terms := existingPodAffinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution + // TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution. + //if len(existingPodAffinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 { + // terms = append(terms, existingPodAffinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution...) + //} + for _, term := range terms { + pm.processTerm(&term, existingPod, pod, existingPodNode, float64(ipa.hardPodAffinityWeight)) + } + } + // For every soft pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of 's node by the term's weight. + terms := existingPodAffinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution + pm.processTerms(terms, existingPod, pod, existingPodNode, 1) + } + if existingHasAntiAffinityConstraints { + // For every soft pod anti-affinity term of , if matches the term, + // decrement for every node in the cluster with the same + // value as that of 's node by the term's weight. + terms := existingPodAffinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution + pm.processTerms(terms, existingPod, pod, existingPodNode, -1) + } + return nil + } + processNode := func(i int) { + nodeInfo := nodeNameToInfo[allNodeNames[i]] + if nodeInfo.Node() != nil { + if hasAffinityConstraints || hasAntiAffinityConstraints { + // We need to process all the nodes. + for _, existingPod := range nodeInfo.Pods() { + if err := processPod(existingPod); err != nil { + pm.setError(err) + } + } + } else { + // The pod doesn't have any constraints - we need to check only existing + // ones that have some. + for _, existingPod := range nodeInfo.PodsWithAffinity() { + if err := processPod(existingPod); err != nil { + pm.setError(err) + } + } + } + } + } + workqueue.ParallelizeUntil(context.TODO(), 16, len(allNodeNames), processNode) + if pm.firstError != nil { + return nil, pm.firstError + } + + for _, node := range nodes { + if pm.counts[node.Name] > maxCount { + maxCount = pm.counts[node.Name] + } + if pm.counts[node.Name] < minCount { + minCount = pm.counts[node.Name] + } + } + + // calculate final priority score for each node + result := make(schedulerapi.HostPriorityList, 0, len(nodes)) + for _, node := range nodes { + fScore := float64(0) + if (maxCount - minCount) > 0 { + fScore = float64(schedulerapi.MaxPriority) * ((pm.counts[node.Name] - minCount) / (maxCount - minCount)) + } + result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: int(fScore)}) + if klog.V(10) { + klog.Infof("%v -> %v: InterPodAffinityPriority, Score: (%d)", pod.Name, node.Name, int(fScore)) + } + } + return result, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/least_requested.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/least_requested.go new file mode 100644 index 0000000000..d691810896 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/least_requested.go @@ -0,0 +1,53 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +var ( + leastResourcePriority = &ResourceAllocationPriority{"LeastResourceAllocation", leastResourceScorer} + + // LeastRequestedPriorityMap is a priority function that favors nodes with fewer requested resources. + // It calculates the percentage of memory and CPU requested by pods scheduled on the node, and + // prioritizes based on the minimum of the average of the fraction of requested to capacity. + // + // Details: + // (cpu((capacity-sum(requested))*10/capacity) + memory((capacity-sum(requested))*10/capacity))/2 + LeastRequestedPriorityMap = leastResourcePriority.PriorityMap +) + +func leastResourceScorer(requested, allocable *schedulercache.Resource, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 { + return (leastRequestedScore(requested.MilliCPU, allocable.MilliCPU) + + leastRequestedScore(requested.Memory, allocable.Memory)) / 2 +} + +// The unused capacity is calculated on a scale of 0-10 +// 0 being the lowest priority and 10 being the highest. +// The more unused resources the higher the score is. +func leastRequestedScore(requested, capacity int64) int64 { + if capacity == 0 { + return 0 + } + if requested > capacity { + return 0 + } + + return ((capacity - requested) * int64(schedulerapi.MaxPriority)) / capacity +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/metadata.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/metadata.go new file mode 100644 index 0000000000..0771cdca83 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/metadata.go @@ -0,0 +1,115 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// PriorityMetadataFactory is a factory to produce PriorityMetadata. +type PriorityMetadataFactory struct { + serviceLister algorithm.ServiceLister + controllerLister algorithm.ControllerLister + replicaSetLister algorithm.ReplicaSetLister + statefulSetLister algorithm.StatefulSetLister +} + +// NewPriorityMetadataFactory creates a PriorityMetadataFactory. +func NewPriorityMetadataFactory(serviceLister algorithm.ServiceLister, controllerLister algorithm.ControllerLister, replicaSetLister algorithm.ReplicaSetLister, statefulSetLister algorithm.StatefulSetLister) algorithm.PriorityMetadataProducer { + factory := &PriorityMetadataFactory{ + serviceLister: serviceLister, + controllerLister: controllerLister, + replicaSetLister: replicaSetLister, + statefulSetLister: statefulSetLister, + } + return factory.PriorityMetadata +} + +// priorityMetadata is a type that is passed as metadata for priority functions +type priorityMetadata struct { + nonZeroRequest *schedulercache.Resource + podTolerations []v1.Toleration + affinity *v1.Affinity + podSelectors []labels.Selector + controllerRef *metav1.OwnerReference + podFirstServiceSelector labels.Selector + totalNumNodes int +} + +// PriorityMetadata is a PriorityMetadataProducer. Node info can be nil. +func (pmf *PriorityMetadataFactory) PriorityMetadata(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo) interface{} { + // If we cannot compute metadata, just return nil + if pod == nil { + return nil + } + return &priorityMetadata{ + nonZeroRequest: getNonZeroRequests(pod), + podTolerations: getAllTolerationPreferNoSchedule(pod.Spec.Tolerations), + affinity: pod.Spec.Affinity, + podSelectors: getSelectors(pod, pmf.serviceLister, pmf.controllerLister, pmf.replicaSetLister, pmf.statefulSetLister), + controllerRef: metav1.GetControllerOf(pod), + podFirstServiceSelector: getFirstServiceSelector(pod, pmf.serviceLister), + totalNumNodes: len(nodeNameToInfo), + } +} + +// getFirstServiceSelector returns one selector of services the given pod. +func getFirstServiceSelector(pod *v1.Pod, sl algorithm.ServiceLister) (firstServiceSelector labels.Selector) { + if services, err := sl.GetPodServices(pod); err == nil && len(services) > 0 { + return labels.SelectorFromSet(services[0].Spec.Selector) + } + return nil +} + +// getSelectors returns selectors of services, RCs and RSs matching the given pod. +func getSelectors(pod *v1.Pod, sl algorithm.ServiceLister, cl algorithm.ControllerLister, rsl algorithm.ReplicaSetLister, ssl algorithm.StatefulSetLister) []labels.Selector { + var selectors []labels.Selector + + if services, err := sl.GetPodServices(pod); err == nil { + for _, service := range services { + selectors = append(selectors, labels.SelectorFromSet(service.Spec.Selector)) + } + } + + if rcs, err := cl.GetPodControllers(pod); err == nil { + for _, rc := range rcs { + selectors = append(selectors, labels.SelectorFromSet(rc.Spec.Selector)) + } + } + + if rss, err := rsl.GetPodReplicaSets(pod); err == nil { + for _, rs := range rss { + if selector, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector); err == nil { + selectors = append(selectors, selector) + } + } + } + + if sss, err := ssl.GetPodStatefulSets(pod); err == nil { + for _, ss := range sss { + if selector, err := metav1.LabelSelectorAsSelector(ss.Spec.Selector); err == nil { + selectors = append(selectors, selector) + } + } + } + + return selectors +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/most_requested.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/most_requested.go new file mode 100644 index 0000000000..f1cc7c6ad5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/most_requested.go @@ -0,0 +1,55 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +var ( + mostResourcePriority = &ResourceAllocationPriority{"MostResourceAllocation", mostResourceScorer} + + // MostRequestedPriorityMap is a priority function that favors nodes with most requested resources. + // It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes + // based on the maximum of the average of the fraction of requested to capacity. + // Details: (cpu(10 * sum(requested) / capacity) + memory(10 * sum(requested) / capacity)) / 2 + MostRequestedPriorityMap = mostResourcePriority.PriorityMap +) + +func mostResourceScorer(requested, allocable *schedulercache.Resource, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 { + return (mostRequestedScore(requested.MilliCPU, allocable.MilliCPU) + + mostRequestedScore(requested.Memory, allocable.Memory)) / 2 +} + +// The used capacity is calculated on a scale of 0-10 +// 0 being the lowest priority and 10 being the highest. +// The more resources are used the higher the score is. This function +// is almost a reversed version of least_requested_priority.calculateUnusedScore +// (10 - calculateUnusedScore). The main difference is in rounding. It was added to +// keep the final formula clean and not to modify the widely used (by users +// in their default scheduling policies) calculateUsedScore. +func mostRequestedScore(requested, capacity int64) int64 { + if capacity == 0 { + return 0 + } + if requested > capacity { + return 0 + } + + return (requested * schedulerapi.MaxPriority) / capacity +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_affinity.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_affinity.go new file mode 100644 index 0000000000..e274e17092 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_affinity.go @@ -0,0 +1,77 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// CalculateNodeAffinityPriorityMap prioritizes nodes according to node affinity scheduling preferences +// indicated in PreferredDuringSchedulingIgnoredDuringExecution. Each time a node match a preferredSchedulingTerm, +// it will a get an add of preferredSchedulingTerm.Weight. Thus, the more preferredSchedulingTerms +// the node satisfies and the more the preferredSchedulingTerm that is satisfied weights, the higher +// score the node gets. +func CalculateNodeAffinityPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + + // default is the podspec. + affinity := pod.Spec.Affinity + if priorityMeta, ok := meta.(*priorityMetadata); ok { + // We were able to parse metadata, use affinity from there. + affinity = priorityMeta.affinity + } + + var count int32 + // A nil element of PreferredDuringSchedulingIgnoredDuringExecution matches no objects. + // An element of PreferredDuringSchedulingIgnoredDuringExecution that refers to an + // empty PreferredSchedulingTerm matches all objects. + if affinity != nil && affinity.NodeAffinity != nil && affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { + // Match PreferredDuringSchedulingIgnoredDuringExecution term by term. + for i := range affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution { + preferredSchedulingTerm := &affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution[i] + if preferredSchedulingTerm.Weight == 0 { + continue + } + + // TODO: Avoid computing it for all nodes if this becomes a performance problem. + nodeSelector, err := v1helper.NodeSelectorRequirementsAsSelector(preferredSchedulingTerm.Preference.MatchExpressions) + if err != nil { + return schedulerapi.HostPriority{}, err + } + if nodeSelector.Matches(labels.Set(node.Labels)) { + count += preferredSchedulingTerm.Weight + } + } + } + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: int(count), + }, nil +} + +// CalculateNodeAffinityPriorityReduce is a reduce function for node affinity priority calculation. +var CalculateNodeAffinityPriorityReduce = NormalizeReduce(schedulerapi.MaxPriority, false) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_label.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_label.go new file mode 100644 index 0000000000..82505f788a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_label.go @@ -0,0 +1,62 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// NodeLabelPrioritizer contains information to calculate node label priority. +type NodeLabelPrioritizer struct { + label string + presence bool +} + +// NewNodeLabelPriority creates a NodeLabelPrioritizer. +func NewNodeLabelPriority(label string, presence bool) (algorithm.PriorityMapFunction, algorithm.PriorityReduceFunction) { + labelPrioritizer := &NodeLabelPrioritizer{ + label: label, + presence: presence, + } + return labelPrioritizer.CalculateNodeLabelPriorityMap, nil +} + +// CalculateNodeLabelPriorityMap checks whether a particular label exists on a node or not, regardless of its value. +// If presence is true, prioritizes nodes that have the specified label, regardless of value. +// If presence is false, prioritizes nodes that do not have the specified label. +func (n *NodeLabelPrioritizer) CalculateNodeLabelPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + + exists := labels.Set(node.Labels).Has(n.label) + score := 0 + if (exists && n.presence) || (!exists && !n.presence) { + score = schedulerapi.MaxPriority + } + return schedulerapi.HostPriority{ + Host: node.Name, + Score: score, + }, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_prefer_avoid_pods.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_prefer_avoid_pods.go new file mode 100644 index 0000000000..810face510 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/node_prefer_avoid_pods.go @@ -0,0 +1,67 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// CalculateNodePreferAvoidPodsPriorityMap priorities nodes according to the node annotation +// "scheduler.alpha.kubernetes.io/preferAvoidPods". +func CalculateNodePreferAvoidPodsPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + var controllerRef *metav1.OwnerReference + if priorityMeta, ok := meta.(*priorityMetadata); ok { + controllerRef = priorityMeta.controllerRef + } else { + // We couldn't parse metadata - fallback to the podspec. + controllerRef = metav1.GetControllerOf(pod) + } + + if controllerRef != nil { + // Ignore pods that are owned by other controller than ReplicationController + // or ReplicaSet. + if controllerRef.Kind != "ReplicationController" && controllerRef.Kind != "ReplicaSet" { + controllerRef = nil + } + } + if controllerRef == nil { + return schedulerapi.HostPriority{Host: node.Name, Score: schedulerapi.MaxPriority}, nil + } + + avoids, err := v1helper.GetAvoidPodsFromNodeAnnotations(node.Annotations) + if err != nil { + // If we cannot get annotation, assume it's schedulable there. + return schedulerapi.HostPriority{Host: node.Name, Score: schedulerapi.MaxPriority}, nil + } + for i := range avoids.PreferAvoidPods { + avoid := &avoids.PreferAvoidPods[i] + if avoid.PodSignature.PodController.Kind == controllerRef.Kind && avoid.PodSignature.PodController.UID == controllerRef.UID { + return schedulerapi.HostPriority{Host: node.Name, Score: 0}, nil + } + } + return schedulerapi.HostPriority{Host: node.Name, Score: schedulerapi.MaxPriority}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/reduce.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/reduce.go new file mode 100644 index 0000000000..6a6a7427f1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/reduce.go @@ -0,0 +1,64 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "k8s.io/api/core/v1" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// NormalizeReduce generates a PriorityReduceFunction that can normalize the result +// scores to [0, maxPriority]. If reverse is set to true, it reverses the scores by +// subtracting it from maxPriority. +func NormalizeReduce(maxPriority int, reverse bool) algorithm.PriorityReduceFunction { + return func( + _ *v1.Pod, + _ interface{}, + _ map[string]*schedulercache.NodeInfo, + result schedulerapi.HostPriorityList) error { + + var maxCount int + for i := range result { + if result[i].Score > maxCount { + maxCount = result[i].Score + } + } + + if maxCount == 0 { + if reverse { + for i := range result { + result[i].Score = maxPriority + } + } + return nil + } + + for i := range result { + score := result[i].Score + + score = maxPriority * score / maxCount + if reverse { + score = maxPriority - score + } + + result[i].Score = score + } + return nil + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/requested_to_capacity_ratio.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/requested_to_capacity_ratio.go new file mode 100644 index 0000000000..a6ac7a837e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/requested_to_capacity_ratio.go @@ -0,0 +1,141 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// FunctionShape represents shape of scoring function. +// For safety use NewFunctionShape which performs precondition checks for struct creation. +type FunctionShape []FunctionShapePoint + +// FunctionShapePoint represents single point in scoring function shape. +type FunctionShapePoint struct { + // Utilization is function argument. + Utilization int64 + // Score is function value. + Score int64 +} + +var ( + // give priority to least utilized nodes by default + defaultFunctionShape, _ = NewFunctionShape([]FunctionShapePoint{{0, 10}, {100, 0}}) +) + +const ( + minUtilization = 0 + maxUtilization = 100 + minScore = 0 + maxScore = schedulerapi.MaxPriority +) + +// NewFunctionShape creates instance of FunctionShape in a safe way performing all +// necessary sanity checks. +func NewFunctionShape(points []FunctionShapePoint) (FunctionShape, error) { + + n := len(points) + + if n == 0 { + return nil, fmt.Errorf("at least one point must be specified") + } + + for i := 1; i < n; i++ { + if points[i-1].Utilization >= points[i].Utilization { + return nil, fmt.Errorf("utilization values must be sorted. Utilization[%d]==%d >= Utilization[%d]==%d", i-1, points[i-1].Utilization, i, points[i].Utilization) + } + } + + for i, point := range points { + if point.Utilization < minUtilization { + return nil, fmt.Errorf("utilization values must not be less than %d. Utilization[%d]==%d", minUtilization, i, point.Utilization) + } + if point.Utilization > maxUtilization { + return nil, fmt.Errorf("utilization values must not be greater than %d. Utilization[%d]==%d", maxUtilization, i, point.Utilization) + } + if point.Score < minScore { + return nil, fmt.Errorf("score values must not be less than %d. Score[%d]==%d", minScore, i, point.Score) + } + if point.Score > maxScore { + return nil, fmt.Errorf("score valuses not be greater than %d. Score[%d]==%d", maxScore, i, point.Score) + } + } + + // We make defensive copy so we make no assumption if array passed as argument is not changed afterwards + pointsCopy := make(FunctionShape, n) + copy(pointsCopy, points) + return pointsCopy, nil +} + +// RequestedToCapacityRatioResourceAllocationPriorityDefault creates a requestedToCapacity based +// ResourceAllocationPriority using default resource scoring function shape. +// The default function assigns 1.0 to resource when all capacity is available +// and 0.0 when requested amount is equal to capacity. +func RequestedToCapacityRatioResourceAllocationPriorityDefault() *ResourceAllocationPriority { + return RequestedToCapacityRatioResourceAllocationPriority(defaultFunctionShape) +} + +// RequestedToCapacityRatioResourceAllocationPriority creates a requestedToCapacity based +// ResourceAllocationPriority using provided resource scoring function shape. +func RequestedToCapacityRatioResourceAllocationPriority(scoringFunctionShape FunctionShape) *ResourceAllocationPriority { + return &ResourceAllocationPriority{"RequestedToCapacityRatioResourceAllocationPriority", buildRequestedToCapacityRatioScorerFunction(scoringFunctionShape)} +} + +func buildRequestedToCapacityRatioScorerFunction(scoringFunctionShape FunctionShape) func(*schedulercache.Resource, *schedulercache.Resource, bool, int, int) int64 { + rawScoringFunction := buildBrokenLinearFunction(scoringFunctionShape) + + resourceScoringFunction := func(requested, capacity int64) int64 { + if capacity == 0 || requested > capacity { + return rawScoringFunction(maxUtilization) + } + + return rawScoringFunction(maxUtilization - (capacity-requested)*maxUtilization/capacity) + } + + return func(requested, allocable *schedulercache.Resource, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 { + cpuScore := resourceScoringFunction(requested.MilliCPU, allocable.MilliCPU) + memoryScore := resourceScoringFunction(requested.Memory, allocable.Memory) + return (cpuScore + memoryScore) / 2 + } +} + +// Creates a function which is built using linear segments. Segments are defined via shape array. +// Shape[i].Utilization slice represents points on "utilization" axis where different segments meet. +// Shape[i].Score represents function values at meeting points. +// +// function f(p) is defined as: +// shape[0].Score for p < f[0].Utilization +// shape[i].Score for p == shape[i].Utilization +// shape[n-1].Score for p > shape[n-1].Utilization +// and linear between points (p < shape[i].Utilization) +func buildBrokenLinearFunction(shape FunctionShape) func(int64) int64 { + n := len(shape) + return func(p int64) int64 { + for i := 0; i < n; i++ { + if p <= shape[i].Utilization { + if i == 0 { + return shape[0].Score + } + return shape[i-1].Score + (shape[i].Score-shape[i-1].Score)*(p-shape[i-1].Utilization)/(shape[i].Utilization-shape[i-1].Utilization) + } + } + return shape[n-1].Score + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_allocation.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_allocation.go new file mode 100644 index 0000000000..027eabae5f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_allocation.go @@ -0,0 +1,103 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/klog" + "k8s.io/kubernetes/pkg/features" + priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// ResourceAllocationPriority contains information to calculate resource allocation priority. +type ResourceAllocationPriority struct { + Name string + scorer func(requested, allocable *schedulercache.Resource, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 +} + +// PriorityMap priorities nodes according to the resource allocations on the node. +// It will use `scorer` function to calculate the score. +func (r *ResourceAllocationPriority) PriorityMap( + pod *v1.Pod, + meta interface{}, + nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + allocatable := nodeInfo.AllocatableResource() + + var requested schedulercache.Resource + if priorityMeta, ok := meta.(*priorityMetadata); ok { + requested = *priorityMeta.nonZeroRequest + } else { + // We couldn't parse metadata - fallback to computing it. + requested = *getNonZeroRequests(pod) + } + + requested.MilliCPU += nodeInfo.NonZeroRequest().MilliCPU + requested.Memory += nodeInfo.NonZeroRequest().Memory + var score int64 + // Check if the pod has volumes and this could be added to scorer function for balanced resource allocation. + if len(pod.Spec.Volumes) >= 0 && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && nodeInfo.TransientInfo != nil { + score = r.scorer(&requested, &allocatable, true, nodeInfo.TransientInfo.TransNodeInfo.RequestedVolumes, nodeInfo.TransientInfo.TransNodeInfo.AllocatableVolumesCount) + } else { + score = r.scorer(&requested, &allocatable, false, 0, 0) + } + + if klog.V(10) { + if len(pod.Spec.Volumes) >= 0 && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && nodeInfo.TransientInfo != nil { + klog.Infof( + "%v -> %v: %v, capacity %d millicores %d memory bytes, %d volumes, total request %d millicores %d memory bytes %d volumes, score %d", + pod.Name, node.Name, r.Name, + allocatable.MilliCPU, allocatable.Memory, nodeInfo.TransientInfo.TransNodeInfo.AllocatableVolumesCount, + requested.MilliCPU, requested.Memory, + nodeInfo.TransientInfo.TransNodeInfo.RequestedVolumes, + score, + ) + } else { + klog.Infof( + "%v -> %v: %v, capacity %d millicores %d memory bytes, total request %d millicores %d memory bytes, score %d", + pod.Name, node.Name, r.Name, + allocatable.MilliCPU, allocatable.Memory, + requested.MilliCPU, requested.Memory, + score, + ) + } + } + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: int(score), + }, nil +} + +func getNonZeroRequests(pod *v1.Pod) *schedulercache.Resource { + result := &schedulercache.Resource{} + for i := range pod.Spec.Containers { + container := &pod.Spec.Containers[i] + cpu, memory := priorityutil.GetNonzeroRequests(&container.Resources.Requests) + result.MilliCPU += cpu + result.Memory += memory + } + return result +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_limits.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_limits.go new file mode 100644 index 0000000000..82b803cbf7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/resource_limits.go @@ -0,0 +1,99 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" + + "k8s.io/klog" +) + +// ResourceLimitsPriorityMap is a priority function that increases score of input node by 1 if the node satisfies +// input pod's resource limits. In detail, this priority function works as follows: If a node does not publish its +// allocatable resources (cpu and memory both), the node score is not affected. If a pod does not specify +// its cpu and memory limits both, the node score is not affected. If one or both of cpu and memory limits +// of the pod are satisfied, the node is assigned a score of 1. +// Rationale of choosing the lowest score of 1 is that this is mainly selected to break ties between nodes that have +// same scores assigned by one of least and most requested priority functions. +func ResourceLimitsPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + + allocatableResources := nodeInfo.AllocatableResource() + + // compute pod limits + podLimits := getResourceLimits(pod) + + cpuScore := computeScore(podLimits.MilliCPU, allocatableResources.MilliCPU) + memScore := computeScore(podLimits.Memory, allocatableResources.Memory) + + score := int(0) + if cpuScore == 1 || memScore == 1 { + score = 1 + } + + if klog.V(10) { + // We explicitly don't do klog.V(10).Infof() to avoid computing all the parameters if this is + // not logged. There is visible performance gain from it. + klog.Infof( + "%v -> %v: Resource Limits Priority, allocatable %d millicores %d memory bytes, pod limits %d millicores %d memory bytes, score %d", + pod.Name, node.Name, + allocatableResources.MilliCPU, allocatableResources.Memory, + podLimits.MilliCPU, podLimits.Memory, + score, + ) + } + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: score, + }, nil +} + +// computeScore returns 1 if limit value is less than or equal to allocatable +// value, otherwise it returns 0. +func computeScore(limit, allocatable int64) int64 { + if limit != 0 && allocatable != 0 && limit <= allocatable { + return 1 + } + return 0 +} + +// getResourceLimits computes resource limits for input pod. +// The reason to create this new function is to be consistent with other +// priority functions because most or perhaps all priority functions work +// with schedulercache.Resource. +// TODO: cache it as part of metadata passed to priority functions. +func getResourceLimits(pod *v1.Pod) *schedulercache.Resource { + result := &schedulercache.Resource{} + for _, container := range pod.Spec.Containers { + result.Add(container.Resources.Limits) + } + + // take max_resource(sum_pod, any_init_container) + for _, container := range pod.Spec.InitContainers { + result.SetMaxResource(container.Resources.Limits) + } + + return result +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/selector_spreading.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/selector_spreading.go new file mode 100644 index 0000000000..1371d765a5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/selector_spreading.go @@ -0,0 +1,281 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" + utilnode "k8s.io/kubernetes/pkg/util/node" + + "k8s.io/klog" +) + +// When zone information is present, give 2/3 of the weighting to zone spreading, 1/3 to node spreading +// TODO: Any way to justify this weighting? +const zoneWeighting float64 = 2.0 / 3.0 + +// SelectorSpread contains information to calculate selector spread priority. +type SelectorSpread struct { + serviceLister algorithm.ServiceLister + controllerLister algorithm.ControllerLister + replicaSetLister algorithm.ReplicaSetLister + statefulSetLister algorithm.StatefulSetLister +} + +// NewSelectorSpreadPriority creates a SelectorSpread. +func NewSelectorSpreadPriority( + serviceLister algorithm.ServiceLister, + controllerLister algorithm.ControllerLister, + replicaSetLister algorithm.ReplicaSetLister, + statefulSetLister algorithm.StatefulSetLister) (algorithm.PriorityMapFunction, algorithm.PriorityReduceFunction) { + selectorSpread := &SelectorSpread{ + serviceLister: serviceLister, + controllerLister: controllerLister, + replicaSetLister: replicaSetLister, + statefulSetLister: statefulSetLister, + } + return selectorSpread.CalculateSpreadPriorityMap, selectorSpread.CalculateSpreadPriorityReduce +} + +// CalculateSpreadPriorityMap spreads pods across hosts, considering pods +// belonging to the same service,RC,RS or StatefulSet. +// When a pod is scheduled, it looks for services, RCs,RSs and StatefulSets that match the pod, +// then finds existing pods that match those selectors. +// It favors nodes that have fewer existing matching pods. +// i.e. it pushes the scheduler towards a node where there's the smallest number of +// pods which match the same service, RC,RSs or StatefulSets selectors as the pod being scheduled. +func (s *SelectorSpread) CalculateSpreadPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + var selectors []labels.Selector + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + + priorityMeta, ok := meta.(*priorityMetadata) + if ok { + selectors = priorityMeta.podSelectors + } else { + selectors = getSelectors(pod, s.serviceLister, s.controllerLister, s.replicaSetLister, s.statefulSetLister) + } + + if len(selectors) == 0 { + return schedulerapi.HostPriority{ + Host: node.Name, + Score: int(0), + }, nil + } + + count := int(0) + for _, nodePod := range nodeInfo.Pods() { + if pod.Namespace != nodePod.Namespace { + continue + } + // When we are replacing a failed pod, we often see the previous + // deleted version while scheduling the replacement. + // Ignore the previous deleted version for spreading purposes + // (it can still be considered for resource restrictions etc.) + if nodePod.DeletionTimestamp != nil { + klog.V(4).Infof("skipping pending-deleted pod: %s/%s", nodePod.Namespace, nodePod.Name) + continue + } + for _, selector := range selectors { + if selector.Matches(labels.Set(nodePod.ObjectMeta.Labels)) { + count++ + break + } + } + } + return schedulerapi.HostPriority{ + Host: node.Name, + Score: int(count), + }, nil +} + +// CalculateSpreadPriorityReduce calculates the source of each node +// based on the number of existing matching pods on the node +// where zone information is included on the nodes, it favors nodes +// in zones with fewer existing matching pods. +func (s *SelectorSpread) CalculateSpreadPriorityReduce(pod *v1.Pod, meta interface{}, nodeNameToInfo map[string]*schedulercache.NodeInfo, result schedulerapi.HostPriorityList) error { + countsByZone := make(map[string]int, 10) + maxCountByZone := int(0) + maxCountByNodeName := int(0) + + for i := range result { + if result[i].Score > maxCountByNodeName { + maxCountByNodeName = result[i].Score + } + zoneID := utilnode.GetZoneKey(nodeNameToInfo[result[i].Host].Node()) + if zoneID == "" { + continue + } + countsByZone[zoneID] += result[i].Score + } + + for zoneID := range countsByZone { + if countsByZone[zoneID] > maxCountByZone { + maxCountByZone = countsByZone[zoneID] + } + } + + haveZones := len(countsByZone) != 0 + + maxCountByNodeNameFloat64 := float64(maxCountByNodeName) + maxCountByZoneFloat64 := float64(maxCountByZone) + MaxPriorityFloat64 := float64(schedulerapi.MaxPriority) + + for i := range result { + // initializing to the default/max node score of maxPriority + fScore := MaxPriorityFloat64 + if maxCountByNodeName > 0 { + fScore = MaxPriorityFloat64 * (float64(maxCountByNodeName-result[i].Score) / maxCountByNodeNameFloat64) + } + // If there is zone information present, incorporate it + if haveZones { + zoneID := utilnode.GetZoneKey(nodeNameToInfo[result[i].Host].Node()) + if zoneID != "" { + zoneScore := MaxPriorityFloat64 + if maxCountByZone > 0 { + zoneScore = MaxPriorityFloat64 * (float64(maxCountByZone-countsByZone[zoneID]) / maxCountByZoneFloat64) + } + fScore = (fScore * (1.0 - zoneWeighting)) + (zoneWeighting * zoneScore) + } + } + result[i].Score = int(fScore) + if klog.V(10) { + klog.Infof( + "%v -> %v: SelectorSpreadPriority, Score: (%d)", pod.Name, result[i].Host, int(fScore), + ) + } + } + return nil +} + +// ServiceAntiAffinity contains information to calculate service anti-affinity priority. +type ServiceAntiAffinity struct { + podLister algorithm.PodLister + serviceLister algorithm.ServiceLister + label string +} + +// NewServiceAntiAffinityPriority creates a ServiceAntiAffinity. +func NewServiceAntiAffinityPriority(podLister algorithm.PodLister, serviceLister algorithm.ServiceLister, label string) (algorithm.PriorityMapFunction, algorithm.PriorityReduceFunction) { + antiAffinity := &ServiceAntiAffinity{ + podLister: podLister, + serviceLister: serviceLister, + label: label, + } + return antiAffinity.CalculateAntiAffinityPriorityMap, antiAffinity.CalculateAntiAffinityPriorityReduce +} + +// Classifies nodes into ones with labels and without labels. +func (s *ServiceAntiAffinity) getNodeClassificationByLabels(nodes []*v1.Node) (map[string]string, []string) { + labeledNodes := map[string]string{} + nonLabeledNodes := []string{} + for _, node := range nodes { + if labels.Set(node.Labels).Has(s.label) { + label := labels.Set(node.Labels).Get(s.label) + labeledNodes[node.Name] = label + } else { + nonLabeledNodes = append(nonLabeledNodes, node.Name) + } + } + return labeledNodes, nonLabeledNodes +} + +// filteredPod get pods based on namespace and selector +func filteredPod(namespace string, selector labels.Selector, nodeInfo *schedulercache.NodeInfo) (pods []*v1.Pod) { + if nodeInfo.Pods() == nil || len(nodeInfo.Pods()) == 0 || selector == nil { + return []*v1.Pod{} + } + for _, pod := range nodeInfo.Pods() { + // Ignore pods being deleted for spreading purposes + // Similar to how it is done for SelectorSpreadPriority + if namespace == pod.Namespace && pod.DeletionTimestamp == nil && selector.Matches(labels.Set(pod.Labels)) { + pods = append(pods, pod) + } + } + return +} + +// CalculateAntiAffinityPriorityMap spreads pods by minimizing the number of pods belonging to the same service +// on given machine +func (s *ServiceAntiAffinity) CalculateAntiAffinityPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + var firstServiceSelector labels.Selector + + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + priorityMeta, ok := meta.(*priorityMetadata) + if ok { + firstServiceSelector = priorityMeta.podFirstServiceSelector + } else { + firstServiceSelector = getFirstServiceSelector(pod, s.serviceLister) + } + //pods matched namespace,selector on current node + matchedPodsOfNode := filteredPod(pod.Namespace, firstServiceSelector, nodeInfo) + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: int(len(matchedPodsOfNode)), + }, nil +} + +// CalculateAntiAffinityPriorityReduce computes each node score with the same value for a particular label. +// The label to be considered is provided to the struct (ServiceAntiAffinity). +func (s *ServiceAntiAffinity) CalculateAntiAffinityPriorityReduce(pod *v1.Pod, meta interface{}, nodeNameToInfo map[string]*schedulercache.NodeInfo, result schedulerapi.HostPriorityList) error { + var numServicePods int + var label string + podCounts := map[string]int{} + labelNodesStatus := map[string]string{} + maxPriorityFloat64 := float64(schedulerapi.MaxPriority) + + for _, hostPriority := range result { + numServicePods += hostPriority.Score + if !labels.Set(nodeNameToInfo[hostPriority.Host].Node().Labels).Has(s.label) { + continue + } + label = labels.Set(nodeNameToInfo[hostPriority.Host].Node().Labels).Get(s.label) + labelNodesStatus[hostPriority.Host] = label + podCounts[label] += hostPriority.Score + } + + //score int - scale of 0-maxPriority + // 0 being the lowest priority and maxPriority being the highest + for i, hostPriority := range result { + label, ok := labelNodesStatus[hostPriority.Host] + if !ok { + result[i].Host = hostPriority.Host + result[i].Score = int(0) + continue + } + // initializing to the default/max node score of maxPriority + fScore := maxPriorityFloat64 + if numServicePods > 0 { + fScore = maxPriorityFloat64 * (float64(numServicePods-podCounts[label]) / float64(numServicePods)) + } + result[i].Host = hostPriority.Host + result[i].Score = int(fScore) + } + + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/taint_toleration.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/taint_toleration.go new file mode 100644 index 0000000000..5790a4b091 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/taint_toleration.go @@ -0,0 +1,76 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "fmt" + + "k8s.io/api/core/v1" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +// CountIntolerableTaintsPreferNoSchedule gives the count of intolerable taints of a pod with effect PreferNoSchedule +func countIntolerableTaintsPreferNoSchedule(taints []v1.Taint, tolerations []v1.Toleration) (intolerableTaints int) { + for _, taint := range taints { + // check only on taints that have effect PreferNoSchedule + if taint.Effect != v1.TaintEffectPreferNoSchedule { + continue + } + + if !v1helper.TolerationsTolerateTaint(tolerations, &taint) { + intolerableTaints++ + } + } + return +} + +// getAllTolerationEffectPreferNoSchedule gets the list of all Tolerations with Effect PreferNoSchedule or with no effect. +func getAllTolerationPreferNoSchedule(tolerations []v1.Toleration) (tolerationList []v1.Toleration) { + for _, toleration := range tolerations { + // Empty effect means all effects which includes PreferNoSchedule, so we need to collect it as well. + if len(toleration.Effect) == 0 || toleration.Effect == v1.TaintEffectPreferNoSchedule { + tolerationList = append(tolerationList, toleration) + } + } + return +} + +// ComputeTaintTolerationPriorityMap prepares the priority list for all the nodes based on the number of intolerable taints on the node +func ComputeTaintTolerationPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { + node := nodeInfo.Node() + if node == nil { + return schedulerapi.HostPriority{}, fmt.Errorf("node not found") + } + // To hold all the tolerations with Effect PreferNoSchedule + var tolerationsPreferNoSchedule []v1.Toleration + if priorityMeta, ok := meta.(*priorityMetadata); ok { + tolerationsPreferNoSchedule = priorityMeta.podTolerations + + } else { + tolerationsPreferNoSchedule = getAllTolerationPreferNoSchedule(pod.Spec.Tolerations) + } + + return schedulerapi.HostPriority{ + Host: node.Name, + Score: countIntolerableTaintsPreferNoSchedule(node.Spec.Taints, tolerationsPreferNoSchedule), + }, nil +} + +// ComputeTaintTolerationPriorityReduce calculates the source of each node based on the number of intolerable taints on the node +var ComputeTaintTolerationPriorityReduce = NormalizeReduce(schedulerapi.MaxPriority, true) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/test_util.go b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/test_util.go new file mode 100644 index 0000000000..da85c6b391 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/test_util.go @@ -0,0 +1,61 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package priorities + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/scheduler/algorithm" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" + schedulercache "k8s.io/kubernetes/pkg/scheduler/cache" +) + +func makeNode(node string, milliCPU, memory int64) *v1.Node { + return &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: node}, + Status: v1.NodeStatus{ + Capacity: v1.ResourceList{ + v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), + }, + Allocatable: v1.ResourceList{ + v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), + }, + }, + } +} + +func priorityFunction(mapFn algorithm.PriorityMapFunction, reduceFn algorithm.PriorityReduceFunction, metaData interface{}) algorithm.PriorityFunction { + return func(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { + result := make(schedulerapi.HostPriorityList, 0, len(nodes)) + for i := range nodes { + hostResult, err := mapFn(pod, metaData, nodeNameToInfo[nodes[i].Name]) + if err != nil { + return nil, err + } + result = append(result, hostResult) + } + if reduceFn != nil { + if err := reduceFn(pod, metaData, nodeNameToInfo, result); err != nil { + return nil, err + } + } + return result, nil + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/util/node/BUILD b/vendor/k8s.io/kubernetes/pkg/util/node/BUILD new file mode 100644 index 0000000000..7e1696cefe --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/util/node/BUILD @@ -0,0 +1,47 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = ["node.go"], + importpath = "k8s.io/kubernetes/pkg/util/node", + deps = [ + "//pkg/kubelet/apis:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["node_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/kubelet/apis:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kubernetes/pkg/util/node/node.go b/vendor/k8s.io/kubernetes/pkg/util/node/node.go new file mode 100644 index 0000000000..ff50385515 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/util/node/node.go @@ -0,0 +1,203 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package node + +import ( + "encoding/json" + "fmt" + "net" + "os" + "strings" + "time" + + "k8s.io/klog" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/strategicpatch" + clientset "k8s.io/client-go/kubernetes" + v1core "k8s.io/client-go/kubernetes/typed/core/v1" + kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" +) + +const ( + // NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive + // on the node it is (was) running. + NodeUnreachablePodReason = "NodeLost" + // NodeUnreachablePodMessage is the message on a pod when its state cannot be confirmed as kubelet is unresponsive + // on the node it is (was) running. + NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive" +) + +// GetHostname returns OS's hostname if 'hostnameOverride' is empty; otherwise, return 'hostnameOverride'. +func GetHostname(hostnameOverride string) (string, error) { + hostName := hostnameOverride + if len(hostName) == 0 { + nodeName, err := os.Hostname() + if err != nil { + return "", fmt.Errorf("couldn't determine hostname: %v", err) + } + hostName = nodeName + } + + // Trim whitespaces first to avoid getting an empty hostname + // For linux, the hostname is read from file /proc/sys/kernel/hostname directly + hostName = strings.TrimSpace(hostName) + if len(hostName) == 0 { + return "", fmt.Errorf("empty hostname is invalid") + } + return strings.ToLower(hostName), nil +} + +// GetPreferredNodeAddress returns the address of the provided node, using the provided preference order. +// If none of the preferred address types are found, an error is returned. +func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddressType) (string, error) { + for _, addressType := range preferredAddressTypes { + for _, address := range node.Status.Addresses { + if address.Type == addressType { + return address.Address, nil + } + } + } + return "", fmt.Errorf("no preferred addresses found; known addresses: %v", node.Status.Addresses) +} + +// GetNodeHostIP returns the provided node's IP, based on the priority: +// 1. NodeInternalIP +// 2. NodeExternalIP +func GetNodeHostIP(node *v1.Node) (net.IP, error) { + addresses := node.Status.Addresses + addressMap := make(map[v1.NodeAddressType][]v1.NodeAddress) + for i := range addresses { + addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i]) + } + if addresses, ok := addressMap[v1.NodeInternalIP]; ok { + return net.ParseIP(addresses[0].Address), nil + } + if addresses, ok := addressMap[v1.NodeExternalIP]; ok { + return net.ParseIP(addresses[0].Address), nil + } + return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses) +} + +// GetNodeIP returns the ip of node with the provided hostname +func GetNodeIP(client clientset.Interface, hostname string) net.IP { + var nodeIP net.IP + node, err := client.CoreV1().Nodes().Get(hostname, metav1.GetOptions{}) + if err != nil { + klog.Warningf("Failed to retrieve node info: %v", err) + return nil + } + nodeIP, err = GetNodeHostIP(node) + if err != nil { + klog.Warningf("Failed to retrieve node IP: %v", err) + return nil + } + return nodeIP +} + +// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone; +// it returns empty-string for no zone. +func GetZoneKey(node *v1.Node) string { + labels := node.Labels + if labels == nil { + return "" + } + + region, _ := labels[kubeletapis.LabelZoneRegion] + failureDomain, _ := labels[kubeletapis.LabelZoneFailureDomain] + + if region == "" && failureDomain == "" { + return "" + } + + // We include the null character just in case region or failureDomain has a colon + // (We do assume there's no null characters in a region or failureDomain) + // As a nice side-benefit, the null character is not printed by fmt.Print or glog + return region + ":\x00:" + failureDomain +} + +// SetNodeCondition updates specific node condition with patch operation. +func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.NodeCondition) error { + generatePatch := func(condition v1.NodeCondition) ([]byte, error) { + raw, err := json.Marshal(&[]v1.NodeCondition{condition}) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil + } + condition.LastHeartbeatTime = metav1.NewTime(time.Now()) + patch, err := generatePatch(condition) + if err != nil { + return nil + } + _, err = c.CoreV1().Nodes().PatchStatus(string(node), patch) + return err +} + +// PatchNodeCIDR patches the specified node's CIDR to the given value. +func PatchNodeCIDR(c clientset.Interface, node types.NodeName, cidr string) error { + raw, err := json.Marshal(cidr) + if err != nil { + return fmt.Errorf("failed to json.Marshal CIDR: %v", err) + } + + patchBytes := []byte(fmt.Sprintf(`{"spec":{"podCIDR":%s}}`, raw)) + + if _, err := c.CoreV1().Nodes().Patch(string(node), types.StrategicMergePatchType, patchBytes); err != nil { + return fmt.Errorf("failed to patch node CIDR: %v", err) + } + return nil +} + +// PatchNodeStatus patches node status. +func PatchNodeStatus(c v1core.CoreV1Interface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, []byte, error) { + patchBytes, err := preparePatchBytesforNodeStatus(nodeName, oldNode, newNode) + if err != nil { + return nil, nil, err + } + + updatedNode, err := c.Nodes().Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status") + if err != nil { + return nil, nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err) + } + return updatedNode, patchBytes, nil +} + +func preparePatchBytesforNodeStatus(nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) ([]byte, error) { + oldData, err := json.Marshal(oldNode) + if err != nil { + return nil, fmt.Errorf("failed to Marshal oldData for node %q: %v", nodeName, err) + } + + // Reset spec to make sure only patch for Status or ObjectMeta is generated. + // Note that we don't reset ObjectMeta here, because: + // 1. This aligns with Nodes().UpdateStatus(). + // 2. Some component does use this to update node annotations. + newNode.Spec = oldNode.Spec + newData, err := json.Marshal(newNode) + if err != nil { + return nil, fmt.Errorf("failed to Marshal newData for node %q: %v", nodeName, err) + } + + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{}) + if err != nil { + return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for node %q: %v", nodeName, err) + } + return patchBytes, nil +}