mirror of
https://github.com/containous/traefik.git
synced 2024-12-22 13:34:03 +03:00
Custom resource definition
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
cfaf47c8a2
commit
4c060a78cc
232
Gopkg.lock
generated
232
Gopkg.lock
generated
@ -135,21 +135,6 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "a3fa4a771d87bda2514a90a157e1fed1b6897d2e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:975b8fd9f8bf97cfdbc6a6af823172e4315b8e0b1d99f7651472f4fe9ff61cbe"
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "8a290539e2e8629dbc4e6bad948158f790ec31f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8098cd40cd09879efbf12e33bcd51ead4a66006ac802cd563a66c4f3373b9727"
|
||||
name = "github.com/PuerkitoBio/urlesc"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e3fc14e683e391975da7c151bd49b968977a6d83244dda5d0a5d0f171a1c23fd"
|
||||
name = "github.com/Shopify/sarama"
|
||||
@ -642,16 +627,6 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8731ec88b62435bdf4c35484309e6b7afd2e9caac8b0bb5661844d7d9ef70a64"
|
||||
name = "github.com/emicklei/go-restful"
|
||||
packages = [
|
||||
".",
|
||||
"log",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6f26e34204ddad638d25456c6443c2763aa38954558226722c253e08e9f491fa"
|
||||
name = "github.com/exoscale/egoscale"
|
||||
@ -829,34 +804,6 @@
|
||||
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e90c60f901104f83cdcad5961d752541a0cd6a0bd996d7fd920bfe8f8c39f241"
|
||||
name = "github.com/go-openapi/jsonpointer"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:98abd61947ff5c7c6fcfec5473d02a4821ed3a2dd99a4fbfdb7925b0dd745546"
|
||||
name = "github.com/go-openapi/jsonreference"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9a247af322a3c4780ad9ba3517f517d93925dee18a7e420209f786f5110b1a28"
|
||||
name = "github.com/go-openapi/spec"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4f5899c71c18d685e67cb365438b433f9d3e0c39f4c865f3d4fe80459b12ffd7"
|
||||
name = "github.com/go-openapi/swag"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:00f1b1d722a012f54670ecc09ee92557d7314bfd9152a085ce91933c1c14b026"
|
||||
name = "github.com/go-resty/resty"
|
||||
@ -1072,14 +1019,6 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "19f2c401e122352c047a84d6584dd51e2fb8fcc4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b7f860847a1d71f925ba9385ed95f1ebc0abfeb418a78e219ab61f48fdfeffad"
|
||||
name = "github.com/howeyc/gopass"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:45e66b20393507035c6a7d15bef5ffe8faf5b083621c1284d9824cc052776de5"
|
||||
name = "github.com/huandu/xstrings"
|
||||
@ -1141,12 +1080,12 @@
|
||||
revision = "72f9bd7c4e0c2a40055ab3d0f09654f730cce982"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:63d8b364f0768ffda64b8e6e15c10535f3431e3c69d051dbb37f467ada02df98"
|
||||
digest = "1:4e903242fe176238aaa469f59d7035f5abf2aa9acfefb8964ddd203651b574e9"
|
||||
name = "github.com/json-iterator/go"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "28452fcdec4e44348d2af0d91d1e9e38da3a9e0a"
|
||||
version = "1.0.5"
|
||||
revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29"
|
||||
version = "v1.1.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8b3234b10eacd5edea45bf0c13a585b608749da23f94aaf29b46d9ef8a8babf4"
|
||||
@ -1253,17 +1192,6 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "c1c17f74874f2a5ea48bfb06b5459d4ef2689749"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f9d15bd15966e80ec044ed83df29c267b87fbf646765939ee37e48287061e71b"
|
||||
name = "github.com/mailru/easyjson"
|
||||
packages = [
|
||||
"buffer",
|
||||
"jlexer",
|
||||
"jwriter",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4953945f4fdc12cb7aa0263710534fb64b35a85e4047570fdf1cb03284055f0d"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
@ -1365,6 +1293,22 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "63d60e9d0dbc60cf9164e6510889b0db6683d98c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f"
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||
version = "1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c6aca19413b13dc59c220ad7430329e2ec454cc310bc6d8de2c7e2b93c18a0f6"
|
||||
name = "github.com/modern-go/reflect2"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7bb97a5f80a2429fa605e176e16cf682cbb5ac681f421a06efb4e3b8efae6e5f"
|
||||
name = "github.com/mvdan/xurls"
|
||||
@ -1929,25 +1873,18 @@
|
||||
revision = "fff93fa7cd278d84afc205751523809c464168ab"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6333c67358d261e0b96d6777a10f08ca074e2348a6c99d9dc1cebd0cf3736cb2"
|
||||
digest = "1:ca9ebfc1200ca7423d9778dba9cdd463704753541c99dc4896f15e0b8b2bf1e8"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"cases",
|
||||
"internal",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"runes",
|
||||
"secure/bidirule",
|
||||
"secure/precis",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
"width",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "4ee4af566555f5fbe026368b75596286a312663a"
|
||||
@ -1959,6 +1896,27 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "8be79e1e0910c292df4e79c241bb7e8f7e725959"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e46d8e20161401a9cf8765dfa428494a3492a0b56fe114156b7da792bf41ba78"
|
||||
name = "golang.org/x/tools"
|
||||
packages = [
|
||||
"go/ast/astutil",
|
||||
"go/gcexportdata",
|
||||
"go/internal/cgo",
|
||||
"go/internal/gcimporter",
|
||||
"go/internal/packagesdriver",
|
||||
"go/packages",
|
||||
"go/types/typeutil",
|
||||
"imports",
|
||||
"internal/fastwalk",
|
||||
"internal/gopathwalk",
|
||||
"internal/module",
|
||||
"internal/semver",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "589c23e65e65055d47b9ad4a99723bc389136265"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:da32ebe70dd3ec97d2df26281b08b18d05c2f12491ae79f389813f6c8d3006b3"
|
||||
@ -2105,7 +2063,7 @@
|
||||
revision = "53feefa2559fb8dfa8d81baad31be332c97d6c77"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:85cc1b1a331f54ffd419ccd435426ee992603d4ba463b51790a312b59d1a09dc"
|
||||
digest = "1:b1c6723e934087c2fa159e1c6a309c3c5c0b9a7d209c2ba6028f21240ebe7606"
|
||||
name = "k8s.io/api"
|
||||
packages = [
|
||||
"admissionregistration/v1alpha1",
|
||||
@ -2132,17 +2090,18 @@
|
||||
"rbac/v1alpha1",
|
||||
"rbac/v1beta1",
|
||||
"scheduling/v1alpha1",
|
||||
"scheduling/v1beta1",
|
||||
"settings/v1alpha1",
|
||||
"storage/v1",
|
||||
"storage/v1alpha1",
|
||||
"storage/v1beta1",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "af4bc157c3a209798fc897f6d4aaaaeb6c2e0d6a"
|
||||
version = "kubernetes-1.9.0"
|
||||
revision = "e86510ea3fe79b17eda7b8b3bb5cf8811d3af968"
|
||||
version = "kubernetes-1.11.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4f4489c97d0f170a24dbb98fd47e904bae80abe7ece29f337a28cbc5470877b1"
|
||||
digest = "1:1fa62171c3cf8abf9933ec87c1a00881f8f086a5928b2a8481c469ab67cb4104"
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/errors",
|
||||
@ -2151,7 +2110,7 @@
|
||||
"pkg/apis/meta/internalversion",
|
||||
"pkg/apis/meta/v1",
|
||||
"pkg/apis/meta/v1/unstructured",
|
||||
"pkg/apis/meta/v1alpha1",
|
||||
"pkg/apis/meta/v1beta1",
|
||||
"pkg/conversion",
|
||||
"pkg/conversion/queryparams",
|
||||
"pkg/fields",
|
||||
@ -2173,26 +2132,30 @@
|
||||
"pkg/util/framer",
|
||||
"pkg/util/intstr",
|
||||
"pkg/util/json",
|
||||
"pkg/util/mergepatch",
|
||||
"pkg/util/net",
|
||||
"pkg/util/runtime",
|
||||
"pkg/util/sets",
|
||||
"pkg/util/strategicpatch",
|
||||
"pkg/util/validation",
|
||||
"pkg/util/validation/field",
|
||||
"pkg/util/wait",
|
||||
"pkg/util/yaml",
|
||||
"pkg/version",
|
||||
"pkg/watch",
|
||||
"third_party/forked/golang/json",
|
||||
"third_party/forked/golang/reflect",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "180eddb345a5be3a157cea1c624700ad5bd27b8f"
|
||||
version = "kubernetes-1.9.0"
|
||||
revision = "1525e4dadd2df06debdeb27ee24ac7db5b6413b1"
|
||||
version = "kubernetes-1.11.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:38c77bd3136157819bfeec7a3ce19b94a15f013f34499becb6ef3fdc206c660b"
|
||||
digest = "1:b557d722202c63ce865634b8adc42b7d283b7d71bd52c7becf525abc04b8bed9"
|
||||
name = "k8s.io/client-go"
|
||||
packages = [
|
||||
"discovery",
|
||||
"discovery/fake",
|
||||
"informers",
|
||||
"informers/admissionregistration",
|
||||
"informers/admissionregistration/v1alpha1",
|
||||
@ -2227,6 +2190,7 @@
|
||||
"informers/rbac/v1beta1",
|
||||
"informers/scheduling",
|
||||
"informers/scheduling/v1alpha1",
|
||||
"informers/scheduling/v1beta1",
|
||||
"informers/settings",
|
||||
"informers/settings/v1alpha1",
|
||||
"informers/storage",
|
||||
@ -2259,6 +2223,7 @@
|
||||
"kubernetes/typed/rbac/v1alpha1",
|
||||
"kubernetes/typed/rbac/v1beta1",
|
||||
"kubernetes/typed/scheduling/v1alpha1",
|
||||
"kubernetes/typed/scheduling/v1beta1",
|
||||
"kubernetes/typed/settings/v1alpha1",
|
||||
"kubernetes/typed/storage/v1",
|
||||
"kubernetes/typed/storage/v1alpha1",
|
||||
@ -2283,13 +2248,19 @@
|
||||
"listers/rbac/v1alpha1",
|
||||
"listers/rbac/v1beta1",
|
||||
"listers/scheduling/v1alpha1",
|
||||
"listers/scheduling/v1beta1",
|
||||
"listers/settings/v1alpha1",
|
||||
"listers/storage/v1",
|
||||
"listers/storage/v1alpha1",
|
||||
"listers/storage/v1beta1",
|
||||
"pkg/apis/clientauthentication",
|
||||
"pkg/apis/clientauthentication/v1alpha1",
|
||||
"pkg/apis/clientauthentication/v1beta1",
|
||||
"pkg/version",
|
||||
"plugin/pkg/client/auth/exec",
|
||||
"rest",
|
||||
"rest/watch",
|
||||
"testing",
|
||||
"tools/auth",
|
||||
"tools/cache",
|
||||
"tools/clientcmd",
|
||||
@ -2302,21 +2273,76 @@
|
||||
"transport",
|
||||
"util/buffer",
|
||||
"util/cert",
|
||||
"util/connrotation",
|
||||
"util/flowcontrol",
|
||||
"util/homedir",
|
||||
"util/integer",
|
||||
"util/retry",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "78700dec6369ba22221b72770783300f143df150"
|
||||
version = "v6.0.0"
|
||||
revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65"
|
||||
version = "v8.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7320216e50843bfc1092d20b535a20683abc967e0eba38441c85c3265da10a34"
|
||||
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 = "f8cba74510f397bac80157a6c4ccb0ffbc31b9d0"
|
||||
version = "kubernetes-1.11.7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f5487c07872bdb7c40ffe629430b2fa815f9eca0d2c02bb9e866962eb38a0e70"
|
||||
name = "k8s.io/kube-openapi"
|
||||
packages = ["pkg/common"]
|
||||
digest = "1:61024ed77a53ac618effed55043bf6a9afbdeb64136bd6a5b0c992d4c0363766"
|
||||
name = "k8s.io/gengo"
|
||||
packages = [
|
||||
"args",
|
||||
"examples/deepcopy-gen/generators",
|
||||
"examples/defaulter-gen/generators",
|
||||
"examples/set-gen/sets",
|
||||
"generator",
|
||||
"namer",
|
||||
"parser",
|
||||
"types",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "275e2ce91dec4c05a4094a7b1daee5560b555ac9"
|
||||
revision = "0689ccc1d7d65d9dd1bedcc3b0b1ed7df91ba266"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c263611800c3a97991dbcf9d3bc4de390f6224aaa8ca0a7226a9d734f65a416a"
|
||||
name = "k8s.io/klog"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:03a96603922fc1f6895ae083e1e16d943b55ef0656b56965351bd87e7d90485f"
|
||||
name = "k8s.io/kube-openapi"
|
||||
packages = ["pkg/util/proto"]
|
||||
pruneopts = "NUT"
|
||||
revision = "15615b16d372105f0c69ff47dfe7402926a65aaa"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
@ -2453,7 +2479,6 @@
|
||||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer",
|
||||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer",
|
||||
"gopkg.in/fsnotify.v1",
|
||||
"gopkg.in/yaml.v2",
|
||||
"k8s.io/api/core/v1",
|
||||
"k8s.io/api/extensions/v1beta1",
|
||||
"k8s.io/apimachinery/pkg/api/errors",
|
||||
@ -2461,14 +2486,25 @@
|
||||
"k8s.io/apimachinery/pkg/labels",
|
||||
"k8s.io/apimachinery/pkg/runtime",
|
||||
"k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer",
|
||||
"k8s.io/apimachinery/pkg/types",
|
||||
"k8s.io/apimachinery/pkg/util/intstr",
|
||||
"k8s.io/apimachinery/pkg/watch",
|
||||
"k8s.io/client-go/discovery",
|
||||
"k8s.io/client-go/discovery/fake",
|
||||
"k8s.io/client-go/informers",
|
||||
"k8s.io/client-go/kubernetes",
|
||||
"k8s.io/client-go/kubernetes/scheme",
|
||||
"k8s.io/client-go/rest",
|
||||
"k8s.io/client-go/testing",
|
||||
"k8s.io/client-go/tools/cache",
|
||||
"k8s.io/client-go/tools/clientcmd",
|
||||
"k8s.io/client-go/util/flowcontrol",
|
||||
"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",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
26
Gopkg.toml
26
Gopkg.toml
@ -19,10 +19,22 @@
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
required = [
|
||||
"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/lister-gen",
|
||||
"k8s.io/code-generator/cmd/informer-gen",
|
||||
]
|
||||
|
||||
[prune]
|
||||
non-go = true
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
[[prune.project]]
|
||||
name = "k8s.io/code-generator"
|
||||
non-go = false
|
||||
unused-packages = false
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
@ -193,15 +205,23 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/client-go"
|
||||
version = "6.0.0"
|
||||
version = "8.0.0" # 8.0.0
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/code-generator"
|
||||
version = "kubernetes-1.11.7"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/api"
|
||||
version = "kubernetes-1.9.0"
|
||||
version = "kubernetes-1.11.7" # "kubernetes-1.11.7"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/apimachinery"
|
||||
version = "kubernetes-1.9.0"
|
||||
version = "kubernetes-1.11.7" # "kubernetes-1.11.7"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/json-iterator/go"
|
||||
version = "1.1.6"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
|
3
Makefile
3
Makefile
@ -113,6 +113,9 @@ generate-webui: build-webui
|
||||
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
||||
fi
|
||||
|
||||
generate-crd:
|
||||
./script/update-generated-crd-code.sh
|
||||
|
||||
lint:
|
||||
script/validate-lint
|
||||
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"github.com/containous/traefik/ping"
|
||||
"github.com/containous/traefik/provider/docker"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/provider/kubernetes"
|
||||
"github.com/containous/traefik/provider/kubernetes/ingress"
|
||||
"github.com/containous/traefik/provider/marathon"
|
||||
"github.com/containous/traefik/provider/rest"
|
||||
"github.com/containous/traefik/tracing/datadog"
|
||||
@ -214,7 +214,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||
defaultBoltDb.Prefix = "/traefik"
|
||||
|
||||
// default Kubernetes
|
||||
var defaultKubernetes kubernetes.Provider
|
||||
var defaultKubernetes ingress.Provider
|
||||
defaultKubernetes.Watch = true
|
||||
|
||||
// default Mesos
|
||||
|
@ -28,7 +28,7 @@ import (
|
||||
"github.com/containous/traefik/old/provider/ecs"
|
||||
oldtypes "github.com/containous/traefik/old/types"
|
||||
"github.com/containous/traefik/provider/aggregator"
|
||||
"github.com/containous/traefik/provider/kubernetes"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
"github.com/containous/traefik/safe"
|
||||
"github.com/containous/traefik/server"
|
||||
"github.com/containous/traefik/server/router"
|
||||
@ -116,7 +116,7 @@ Complete documentation is available at https://traefik.io`,
|
||||
f.AddParser(reflect.SliceOf(reflect.TypeOf("")), &sliceOfStrings{})
|
||||
f.AddParser(reflect.TypeOf(traefiktls.FilesOrContents{}), &traefiktls.FilesOrContents{})
|
||||
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
||||
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
||||
f.AddParser(reflect.TypeOf(k8s.Namespaces{}), &k8s.Namespaces{})
|
||||
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
||||
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
||||
f.AddParser(reflect.TypeOf(types.DNSResolvers{}), &types.DNSResolvers{})
|
||||
|
@ -34,7 +34,7 @@ type TCPRouter struct {
|
||||
|
||||
// RouterTCPTLSConfig holds the TLS configuration for a router
|
||||
type RouterTCPTLSConfig struct {
|
||||
Passthrough bool `json:"passthrough,omitempty" toml:"passthrough,omitzero"`
|
||||
Passthrough bool `json:"passthrough" toml:"passthrough,omitzero"`
|
||||
}
|
||||
|
||||
// LoadBalancerService holds the LoadBalancerService configuration.
|
||||
@ -119,16 +119,6 @@ type HealthCheck struct {
|
||||
Headers map[string]string `json:"headers,omitempty" toml:",omitempty"`
|
||||
}
|
||||
|
||||
// ClientTLS holds the TLS specific configurations as client
|
||||
// CA, Cert and Key can be either path or file contents.
|
||||
type ClientTLS struct {
|
||||
CA string `description:"TLS CA" json:"ca,omitempty"`
|
||||
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty"`
|
||||
Cert string `description:"TLS cert" json:"cert,omitempty"`
|
||||
Key string `description:"TLS key" json:"key,omitempty"`
|
||||
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty"`
|
||||
}
|
||||
|
||||
// CreateTLSConfig creates a TLS config from ClientTLS structures.
|
||||
func (clientTLS *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
|
||||
if clientTLS == nil {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"github.com/containous/traefik/ip"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Middleware holds the Middleware configuration.
|
||||
type Middleware struct {
|
||||
AddPrefix *AddPrefix `json:"addPrefix,omitempty"`
|
||||
@ -30,11 +32,15 @@ type Middleware struct {
|
||||
Retry *Retry `json:"retry,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// AddPrefix holds the AddPrefix configuration.
|
||||
type AddPrefix struct {
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Auth holds the authentication configuration (BASIC, DIGEST, users).
|
||||
type Auth struct {
|
||||
Basic *BasicAuth `json:"basic,omitempty" export:"true"`
|
||||
@ -42,6 +48,8 @@ type Auth struct {
|
||||
Forward *ForwardAuth `json:"forward,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// BasicAuth holds the HTTP basic authentication configuration.
|
||||
type BasicAuth struct {
|
||||
Users `json:"users,omitempty" mapstructure:","`
|
||||
@ -51,6 +59,8 @@ type BasicAuth struct {
|
||||
HeaderField string `json:"headerField,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Buffering holds the request/response buffering configuration.
|
||||
type Buffering struct {
|
||||
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty"`
|
||||
@ -60,19 +70,27 @@ type Buffering struct {
|
||||
RetryExpression string `json:"retryExpression,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Chain holds a chain of middlewares
|
||||
type Chain struct {
|
||||
Middlewares []string `json:"middlewares"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// CircuitBreaker holds the circuit breaker configuration.
|
||||
type CircuitBreaker struct {
|
||||
Expression string `json:"expression,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Compress holds the compress configuration.
|
||||
type Compress struct{}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// DigestAuth holds the Digest HTTP authentication configuration.
|
||||
type DigestAuth struct {
|
||||
Users `json:"users,omitempty" mapstructure:","`
|
||||
@ -82,6 +100,8 @@ type DigestAuth struct {
|
||||
HeaderField string `json:"headerField,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ErrorPage holds the custom error page configuration.
|
||||
type ErrorPage struct {
|
||||
Status []string `json:"status,omitempty"`
|
||||
@ -89,6 +109,8 @@ type ErrorPage struct {
|
||||
Query string `json:"query,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ForwardAuth holds the http forward authentication configuration.
|
||||
type ForwardAuth struct {
|
||||
Address string `description:"Authentication server address" json:"address,omitempty"`
|
||||
@ -97,6 +119,8 @@ type ForwardAuth struct {
|
||||
AuthResponseHeaders []string `description:"Headers to be forwarded from auth response" json:"authResponseHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Headers holds the custom header configuration.
|
||||
type Headers struct {
|
||||
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty"`
|
||||
@ -154,6 +178,8 @@ func (h *Headers) HasSecureHeadersDefined() bool {
|
||||
h.IsDevelopment)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// IPStrategy holds the ip strategy configuration.
|
||||
type IPStrategy struct {
|
||||
Depth int `json:"depth,omitempty" export:"true"`
|
||||
@ -188,12 +214,16 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
||||
return &ip.RemoteAddrStrategy{}, nil
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// IPWhiteList holds the ip white list configuration.
|
||||
type IPWhiteList struct {
|
||||
SourceRange []string `json:"sourceRange,omitempty"`
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" label:"allowEmpty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// MaxConn holds maximum connection configuration.
|
||||
type MaxConn struct {
|
||||
Amount int64 `json:"amount,omitempty"`
|
||||
@ -205,12 +235,16 @@ func (m *MaxConn) SetDefaults() {
|
||||
m.ExtractorFunc = "request.host"
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// PassTLSClientCert holds the TLS client cert headers configuration.
|
||||
type PassTLSClientCert struct {
|
||||
PEM bool `description:"Enable header with escaped client pem" json:"pem"`
|
||||
Info *TLSClientCertificateInfo `description:"Enable header with configured client cert info" json:"info,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Rate holds the rate limiting configuration for a specific time period.
|
||||
type Rate struct {
|
||||
Period parse.Duration `json:"period,omitempty"`
|
||||
@ -218,6 +252,8 @@ type Rate struct {
|
||||
Burst int64 `json:"burst,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RateLimit holds the rate limiting configuration for a given frontend.
|
||||
type RateLimit struct {
|
||||
RateSet map[string]*Rate `json:"rateset,omitempty"`
|
||||
@ -230,6 +266,8 @@ func (r *RateLimit) SetDefaults() {
|
||||
r.ExtractorFunc = "request.host"
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RedirectRegex holds the redirection configuration.
|
||||
type RedirectRegex struct {
|
||||
Regex string `json:"regex,omitempty"`
|
||||
@ -237,6 +275,8 @@ type RedirectRegex struct {
|
||||
Permanent bool `json:"permanent,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RedirectScheme holds the scheme redirection configuration.
|
||||
type RedirectScheme struct {
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
@ -244,32 +284,44 @@ type RedirectScheme struct {
|
||||
Permanent bool `json:"permanent,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ReplacePath holds the ReplacePath configuration.
|
||||
type ReplacePath struct {
|
||||
Path string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ReplacePathRegex holds the ReplacePathRegex configuration.
|
||||
type ReplacePathRegex struct {
|
||||
Regex string `json:"regex,omitempty"`
|
||||
Replacement string `json:"replacement,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Retry holds the retry configuration.
|
||||
type Retry struct {
|
||||
Attempts int `description:"Number of attempts" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// StripPrefix holds the StripPrefix configuration.
|
||||
type StripPrefix struct {
|
||||
Prefixes []string `json:"prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// StripPrefixRegex holds the StripPrefixRegex configuration.
|
||||
type StripPrefixRegex struct {
|
||||
Regex []string `json:"regex,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TLSClientCertificateInfo holds the client TLS certificate info configuration.
|
||||
type TLSClientCertificateInfo struct {
|
||||
NotAfter bool `description:"Add NotAfter info in header" json:"notAfter"`
|
||||
@ -279,6 +331,8 @@ type TLSClientCertificateInfo struct {
|
||||
Issuer *TLSCLientCertificateDNInfo `description:"Add Issuer info in header" json:"issuer,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration
|
||||
// cf https://tools.ietf.org/html/rfc3739
|
||||
type TLSCLientCertificateDNInfo struct {
|
||||
@ -291,5 +345,19 @@ type TLSCLientCertificateDNInfo struct {
|
||||
DomainComponent bool `description:"Add Domain Component info in header" json:"domainComponent"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Users holds a list of users
|
||||
type Users []string
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ClientTLS holds the TLS specific configurations as client
|
||||
// CA, Cert and Key can be either path or file contents.
|
||||
type ClientTLS struct {
|
||||
CA string `description:"TLS CA" json:"ca,omitempty"`
|
||||
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty"`
|
||||
Cert string `description:"TLS cert" json:"cert,omitempty"`
|
||||
Key string `description:"TLS key" json:"key,omitempty"`
|
||||
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty"`
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ import (
|
||||
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||
"github.com/containous/traefik/provider/docker"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/provider/kubernetes"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd"
|
||||
"github.com/containous/traefik/provider/kubernetes/ingress"
|
||||
"github.com/containous/traefik/provider/marathon"
|
||||
"github.com/containous/traefik/provider/rest"
|
||||
"github.com/containous/traefik/tls"
|
||||
@ -137,7 +138,8 @@ type Providers struct {
|
||||
Etcd *etcd.Provider `description:"Enable Etcd backend with default settings" export:"true"`
|
||||
Zookeeper *zk.Provider `description:"Enable Zookeeper backend with default settings" export:"true"`
|
||||
Boltdb *boltdb.Provider `description:"Enable Boltdb backend with default settings" export:"true"`
|
||||
Kubernetes *kubernetes.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||
Kubernetes *ingress.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||
KubernetesCRD *crd.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||
Mesos *mesos.Provider `description:"Enable Mesos backend with default settings" export:"true"`
|
||||
Eureka *eureka.Provider `description:"Enable Eureka backend with default settings" export:"true"`
|
||||
ECS *ecs.Provider `description:"Enable ECS backend with default settings" export:"true"`
|
||||
|
733
config/zz_generated.deepcopy.go
Normal file
733
config/zz_generated.deepcopy.go
Normal file
@ -0,0 +1,733 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package config
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AddPrefix) DeepCopyInto(out *AddPrefix) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddPrefix.
|
||||
func (in *AddPrefix) DeepCopy() *AddPrefix {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AddPrefix)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Auth) DeepCopyInto(out *Auth) {
|
||||
*out = *in
|
||||
if in.Basic != nil {
|
||||
in, out := &in.Basic, &out.Basic
|
||||
*out = new(BasicAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Digest != nil {
|
||||
in, out := &in.Digest, &out.Digest
|
||||
*out = new(DigestAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Forward != nil {
|
||||
in, out := &in.Forward, &out.Forward
|
||||
*out = new(ForwardAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth.
|
||||
func (in *Auth) DeepCopy() *Auth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Auth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BasicAuth) DeepCopyInto(out *BasicAuth) {
|
||||
*out = *in
|
||||
if in.Users != nil {
|
||||
in, out := &in.Users, &out.Users
|
||||
*out = make(Users, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicAuth.
|
||||
func (in *BasicAuth) DeepCopy() *BasicAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BasicAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Buffering) DeepCopyInto(out *Buffering) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Buffering.
|
||||
func (in *Buffering) DeepCopy() *Buffering {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Buffering)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Chain) DeepCopyInto(out *Chain) {
|
||||
*out = *in
|
||||
if in.Middlewares != nil {
|
||||
in, out := &in.Middlewares, &out.Middlewares
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Chain.
|
||||
func (in *Chain) DeepCopy() *Chain {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Chain)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CircuitBreaker) DeepCopyInto(out *CircuitBreaker) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CircuitBreaker.
|
||||
func (in *CircuitBreaker) DeepCopy() *CircuitBreaker {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CircuitBreaker)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientTLS) DeepCopyInto(out *ClientTLS) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientTLS.
|
||||
func (in *ClientTLS) DeepCopy() *ClientTLS {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientTLS)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Compress) DeepCopyInto(out *Compress) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Compress.
|
||||
func (in *Compress) DeepCopy() *Compress {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Compress)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DigestAuth) DeepCopyInto(out *DigestAuth) {
|
||||
*out = *in
|
||||
if in.Users != nil {
|
||||
in, out := &in.Users, &out.Users
|
||||
*out = make(Users, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DigestAuth.
|
||||
func (in *DigestAuth) DeepCopy() *DigestAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DigestAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ErrorPage) DeepCopyInto(out *ErrorPage) {
|
||||
*out = *in
|
||||
if in.Status != nil {
|
||||
in, out := &in.Status, &out.Status
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorPage.
|
||||
func (in *ErrorPage) DeepCopy() *ErrorPage {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ErrorPage)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
||||
*out = *in
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(ClientTLS)
|
||||
**out = **in
|
||||
}
|
||||
if in.AuthResponseHeaders != nil {
|
||||
in, out := &in.AuthResponseHeaders, &out.AuthResponseHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ForwardAuth.
|
||||
func (in *ForwardAuth) DeepCopy() *ForwardAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ForwardAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Headers) DeepCopyInto(out *Headers) {
|
||||
*out = *in
|
||||
if in.CustomRequestHeaders != nil {
|
||||
in, out := &in.CustomRequestHeaders, &out.CustomRequestHeaders
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.CustomResponseHeaders != nil {
|
||||
in, out := &in.CustomResponseHeaders, &out.CustomResponseHeaders
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.AllowedHosts != nil {
|
||||
in, out := &in.AllowedHosts, &out.AllowedHosts
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HostsProxyHeaders != nil {
|
||||
in, out := &in.HostsProxyHeaders, &out.HostsProxyHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.SSLProxyHeaders != nil {
|
||||
in, out := &in.SSLProxyHeaders, &out.SSLProxyHeaders
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Headers.
|
||||
func (in *Headers) DeepCopy() *Headers {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Headers)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IPStrategy) DeepCopyInto(out *IPStrategy) {
|
||||
*out = *in
|
||||
if in.ExcludedIPs != nil {
|
||||
in, out := &in.ExcludedIPs, &out.ExcludedIPs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPStrategy.
|
||||
func (in *IPStrategy) DeepCopy() *IPStrategy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IPStrategy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IPWhiteList) DeepCopyInto(out *IPWhiteList) {
|
||||
*out = *in
|
||||
if in.SourceRange != nil {
|
||||
in, out := &in.SourceRange, &out.SourceRange
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.IPStrategy != nil {
|
||||
in, out := &in.IPStrategy, &out.IPStrategy
|
||||
*out = new(IPStrategy)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPWhiteList.
|
||||
func (in *IPWhiteList) DeepCopy() *IPWhiteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IPWhiteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MaxConn) DeepCopyInto(out *MaxConn) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaxConn.
|
||||
func (in *MaxConn) DeepCopy() *MaxConn {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MaxConn)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Middleware) DeepCopyInto(out *Middleware) {
|
||||
*out = *in
|
||||
if in.AddPrefix != nil {
|
||||
in, out := &in.AddPrefix, &out.AddPrefix
|
||||
*out = new(AddPrefix)
|
||||
**out = **in
|
||||
}
|
||||
if in.StripPrefix != nil {
|
||||
in, out := &in.StripPrefix, &out.StripPrefix
|
||||
*out = new(StripPrefix)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.StripPrefixRegex != nil {
|
||||
in, out := &in.StripPrefixRegex, &out.StripPrefixRegex
|
||||
*out = new(StripPrefixRegex)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ReplacePath != nil {
|
||||
in, out := &in.ReplacePath, &out.ReplacePath
|
||||
*out = new(ReplacePath)
|
||||
**out = **in
|
||||
}
|
||||
if in.ReplacePathRegex != nil {
|
||||
in, out := &in.ReplacePathRegex, &out.ReplacePathRegex
|
||||
*out = new(ReplacePathRegex)
|
||||
**out = **in
|
||||
}
|
||||
if in.Chain != nil {
|
||||
in, out := &in.Chain, &out.Chain
|
||||
*out = new(Chain)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPWhiteList != nil {
|
||||
in, out := &in.IPWhiteList, &out.IPWhiteList
|
||||
*out = new(IPWhiteList)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = new(Headers)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Errors != nil {
|
||||
in, out := &in.Errors, &out.Errors
|
||||
*out = new(ErrorPage)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RateLimit != nil {
|
||||
in, out := &in.RateLimit, &out.RateLimit
|
||||
*out = new(RateLimit)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RedirectRegex != nil {
|
||||
in, out := &in.RedirectRegex, &out.RedirectRegex
|
||||
*out = new(RedirectRegex)
|
||||
**out = **in
|
||||
}
|
||||
if in.RedirectScheme != nil {
|
||||
in, out := &in.RedirectScheme, &out.RedirectScheme
|
||||
*out = new(RedirectScheme)
|
||||
**out = **in
|
||||
}
|
||||
if in.BasicAuth != nil {
|
||||
in, out := &in.BasicAuth, &out.BasicAuth
|
||||
*out = new(BasicAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DigestAuth != nil {
|
||||
in, out := &in.DigestAuth, &out.DigestAuth
|
||||
*out = new(DigestAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ForwardAuth != nil {
|
||||
in, out := &in.ForwardAuth, &out.ForwardAuth
|
||||
*out = new(ForwardAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.MaxConn != nil {
|
||||
in, out := &in.MaxConn, &out.MaxConn
|
||||
*out = new(MaxConn)
|
||||
**out = **in
|
||||
}
|
||||
if in.Buffering != nil {
|
||||
in, out := &in.Buffering, &out.Buffering
|
||||
*out = new(Buffering)
|
||||
**out = **in
|
||||
}
|
||||
if in.CircuitBreaker != nil {
|
||||
in, out := &in.CircuitBreaker, &out.CircuitBreaker
|
||||
*out = new(CircuitBreaker)
|
||||
**out = **in
|
||||
}
|
||||
if in.Compress != nil {
|
||||
in, out := &in.Compress, &out.Compress
|
||||
*out = new(Compress)
|
||||
**out = **in
|
||||
}
|
||||
if in.PassTLSClientCert != nil {
|
||||
in, out := &in.PassTLSClientCert, &out.PassTLSClientCert
|
||||
*out = new(PassTLSClientCert)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Retry != nil {
|
||||
in, out := &in.Retry, &out.Retry
|
||||
*out = new(Retry)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Middleware.
|
||||
func (in *Middleware) DeepCopy() *Middleware {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Middleware)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PassTLSClientCert) DeepCopyInto(out *PassTLSClientCert) {
|
||||
*out = *in
|
||||
if in.Info != nil {
|
||||
in, out := &in.Info, &out.Info
|
||||
*out = new(TLSClientCertificateInfo)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassTLSClientCert.
|
||||
func (in *PassTLSClientCert) DeepCopy() *PassTLSClientCert {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PassTLSClientCert)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Rate) DeepCopyInto(out *Rate) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rate.
|
||||
func (in *Rate) DeepCopy() *Rate {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Rate)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RateLimit) DeepCopyInto(out *RateLimit) {
|
||||
*out = *in
|
||||
if in.RateSet != nil {
|
||||
in, out := &in.RateSet, &out.RateSet
|
||||
*out = make(map[string]*Rate, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal *Rate
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
in, out := &val, &outVal
|
||||
*out = new(Rate)
|
||||
**out = **in
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimit.
|
||||
func (in *RateLimit) DeepCopy() *RateLimit {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RateLimit)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedirectRegex) DeepCopyInto(out *RedirectRegex) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedirectRegex.
|
||||
func (in *RedirectRegex) DeepCopy() *RedirectRegex {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RedirectRegex)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedirectScheme) DeepCopyInto(out *RedirectScheme) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedirectScheme.
|
||||
func (in *RedirectScheme) DeepCopy() *RedirectScheme {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RedirectScheme)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReplacePath) DeepCopyInto(out *ReplacePath) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplacePath.
|
||||
func (in *ReplacePath) DeepCopy() *ReplacePath {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReplacePath)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReplacePathRegex) DeepCopyInto(out *ReplacePathRegex) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplacePathRegex.
|
||||
func (in *ReplacePathRegex) DeepCopy() *ReplacePathRegex {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReplacePathRegex)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Retry) DeepCopyInto(out *Retry) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Retry.
|
||||
func (in *Retry) DeepCopy() *Retry {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Retry)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StripPrefix) DeepCopyInto(out *StripPrefix) {
|
||||
*out = *in
|
||||
if in.Prefixes != nil {
|
||||
in, out := &in.Prefixes, &out.Prefixes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StripPrefix.
|
||||
func (in *StripPrefix) DeepCopy() *StripPrefix {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StripPrefix)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StripPrefixRegex) DeepCopyInto(out *StripPrefixRegex) {
|
||||
*out = *in
|
||||
if in.Regex != nil {
|
||||
in, out := &in.Regex, &out.Regex
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StripPrefixRegex.
|
||||
func (in *StripPrefixRegex) DeepCopy() *StripPrefixRegex {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StripPrefixRegex)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSCLientCertificateDNInfo) DeepCopyInto(out *TLSCLientCertificateDNInfo) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCLientCertificateDNInfo.
|
||||
func (in *TLSCLientCertificateDNInfo) DeepCopy() *TLSCLientCertificateDNInfo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSCLientCertificateDNInfo)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSClientCertificateInfo) DeepCopyInto(out *TLSClientCertificateInfo) {
|
||||
*out = *in
|
||||
if in.Subject != nil {
|
||||
in, out := &in.Subject, &out.Subject
|
||||
*out = new(TLSCLientCertificateDNInfo)
|
||||
**out = **in
|
||||
}
|
||||
if in.Issuer != nil {
|
||||
in, out := &in.Issuer, &out.Issuer
|
||||
*out = new(TLSCLientCertificateDNInfo)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSClientCertificateInfo.
|
||||
func (in *TLSClientCertificateInfo) DeepCopy() *TLSClientCertificateInfo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSClientCertificateInfo)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in Users) DeepCopyInto(out *Users) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(Users, len(*in))
|
||||
copy(*out, *in)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Users.
|
||||
func (in Users) DeepCopy() Users {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Users)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
28
integration/fixtures/k8s/01-crd.yml
Normal file
28
integration/fixtures/k8s/01-crd.yml
Normal file
@ -0,0 +1,28 @@
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: ingressroutes.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: IngressRoute
|
||||
plural: ingressroutes
|
||||
singular: ingressroute
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: middlewares.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: Middleware
|
||||
plural: middlewares
|
||||
singular: middleware
|
||||
scope: Namespaced
|
@ -1,11 +1,12 @@
|
||||
---
|
||||
kind: Deployment
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
labels:
|
||||
app: containous
|
||||
name: whoami
|
||||
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
@ -23,11 +24,14 @@ spec:
|
||||
image: containous/whoami
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
@ -35,17 +39,3 @@ spec:
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: cheeses
|
||||
spec:
|
||||
rules:
|
||||
- host: whoami.test
|
||||
http:
|
||||
paths:
|
||||
- path: /whoami
|
||||
backend:
|
||||
serviceName: whoami
|
||||
servicePort: http
|
15
integration/fixtures/k8s/03-ingress.yml
Normal file
15
integration/fixtures/k8s/03-ingress.yml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test.ingress
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: whoami.test
|
||||
http:
|
||||
paths:
|
||||
- path: /whoami
|
||||
backend:
|
||||
serviceName: whoami
|
||||
servicePort: http
|
18
integration/fixtures/k8s/03-ingressroute.yml
Normal file
18
integration/fixtures/k8s/03-ingressroute.yml
Normal file
@ -0,0 +1,18 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entrypoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
29
integration/fixtures/k8s/04-ingressroute.yml
Normal file
29
integration/fixtures/k8s/04-ingressroute.yml
Normal file
@ -0,0 +1,29 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: stripprefix
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
stripprefix:
|
||||
prefixes:
|
||||
- /tobestripped
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test2.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entrypoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/tobestripped`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
11
integration/fixtures/k8s_crd.toml
Normal file
11
integration/fixtures/k8s_crd.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[global]
|
||||
debug=true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
|
||||
[api]
|
||||
|
||||
[Providers]
|
||||
[Providers.KubernetesCRD]
|
@ -2,7 +2,7 @@
|
||||
debug=true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
|
||||
[api]
|
||||
|
@ -73,7 +73,7 @@ func init() {
|
||||
}
|
||||
if *host {
|
||||
// tests launched from the host
|
||||
// check.Suite(&K8sSuite{})
|
||||
check.Suite(&K8sSuite{})
|
||||
check.Suite(&ProxyProtocolSuite{})
|
||||
check.Suite(&TCPSuite{})
|
||||
// FIXME Provider tests
|
||||
|
@ -1,81 +1,27 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/integration/try"
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/testhelpers"
|
||||
"github.com/go-check/check"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
v1beta12 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// K8sSuite
|
||||
type K8sSuite struct{ BaseSuite }
|
||||
|
||||
const (
|
||||
kubeServer = "https://127.0.0.1:6443"
|
||||
namespace = "default"
|
||||
)
|
||||
|
||||
func (s *K8sSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "k8s")
|
||||
s.composeProject.Start(c)
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TearDownSuite(c *check.C) {
|
||||
s.composeProject.Stop(c)
|
||||
os.Remove("./resources/compose/output/kubeconfig.yaml")
|
||||
}
|
||||
|
||||
func parseK8sYaml(fileR []byte) []runtime.Object {
|
||||
acceptedK8sTypes := regexp.MustCompile(`(Deployment|Service|Ingress)`)
|
||||
sepYamlfiles := strings.Split(string(fileR), "---")
|
||||
retVal := make([]runtime.Object, 0, len(sepYamlfiles))
|
||||
for _, f := range sepYamlfiles {
|
||||
if f == "\n" || f == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, groupVersionKind, err := decode([]byte(f), nil, nil)
|
||||
|
||||
if err != nil {
|
||||
log.WithoutContext().Debugf("Error while decoding YAML object. Err was: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !acceptedK8sTypes.MatchString(groupVersionKind.Kind) {
|
||||
log.WithoutContext().Debugf("The custom-roles configMap contained K8s object types which are not supported! Skipping object with type: %s", groupVersionKind.Kind)
|
||||
} else {
|
||||
retVal = append(retVal, obj)
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestSimpleDefaultConfig(c *check.C) {
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, kubeServer, nil)
|
||||
err := try.RequestWithTransport(req, time.Second*60, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
abs, err := filepath.Abs("./fixtures/k8s/kubeconfig.yaml")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
abs, err := filepath.Abs("./resources/compose/output/kubeconfig.yaml")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.Do(time.Second*60, try.DoCondition(func() error {
|
||||
err = try.Do(60*time.Second, try.DoCondition(func() error {
|
||||
_, err := os.Stat(abs)
|
||||
return err
|
||||
}))
|
||||
@ -83,41 +29,54 @@ func (s *K8sSuite) TestSimpleDefaultConfig(c *check.C) {
|
||||
|
||||
err = os.Setenv("KUBECONFIG", abs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TearDownSuite(c *check.C) {
|
||||
s.composeProject.Stop(c)
|
||||
|
||||
err := os.Remove("./fixtures/k8s/kubeconfig.yaml")
|
||||
if err != nil {
|
||||
c.Log(err)
|
||||
}
|
||||
err = os.Remove("./fixtures/k8s/coredns.yaml")
|
||||
if err != nil {
|
||||
c.Log(err)
|
||||
}
|
||||
err = os.Remove("./fixtures/k8s/traefik.yaml")
|
||||
if err != nil {
|
||||
c.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestIngressSimple(c *check.C) {
|
||||
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_default.toml"))
|
||||
defer display(c)
|
||||
|
||||
err = cmd.Start()
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
config, err := clientcmd.BuildConfigFromFlags("", abs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
yamlContent, err := ioutil.ReadFile("./fixtures/k8s/test.yml")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
k8sObjects := parseK8sYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *v1beta12.Deployment:
|
||||
_, err := clientset.ExtensionsV1beta1().Deployments(namespace).Create(o)
|
||||
c.Assert(err, checker.IsNil)
|
||||
case *v1.Service:
|
||||
_, err := clientset.CoreV1().Services(namespace).Create(o)
|
||||
c.Assert(err, checker.IsNil)
|
||||
case *v1beta12.Ingress:
|
||||
_, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Create(o)
|
||||
c.Assert(err, checker.IsNil)
|
||||
default:
|
||||
log.WithoutContext().Errorf("Unknown runtime object %+v %T", o, o)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/kubernetes/routers", 60*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("Host(`whoami.test`)"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("Host(`whoami.test`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestCRDSimple(c *check.C) {
|
||||
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_crd.toml"))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("Host(`foo.com`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("PathPrefix(`/tobestripped`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/kubernetescrd/routers", 1*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("default/stripprefix"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/kubernetescrd/middlewares", 1*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("stripprefix"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
1
integration/resources/compose/.gitignore
vendored
Normal file
1
integration/resources/compose/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
output/
|
@ -1,17 +1,18 @@
|
||||
server:
|
||||
image: rancher/k3s:v0.2.0-rc4
|
||||
command: server --disable-agent
|
||||
image: rancher/k3s:v0.2.0
|
||||
command: server --disable-agent --no-deploy traefik
|
||||
environment:
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
|
||||
- K3S_KUBECONFIG_MODE=666
|
||||
volumes:
|
||||
- ./output:/output
|
||||
- ../../fixtures/k8s:/output
|
||||
- ../../fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
ports:
|
||||
- 6443:6443
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v0.2.0-rc4
|
||||
image: rancher/k3s:v0.2.0
|
||||
privileged: true
|
||||
links:
|
||||
- server
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"github.com/containous/traefik/old/provider/ecs"
|
||||
"github.com/containous/traefik/old/provider/etcd"
|
||||
"github.com/containous/traefik/old/provider/eureka"
|
||||
"github.com/containous/traefik/old/provider/kubernetes"
|
||||
"github.com/containous/traefik/old/provider/mesos"
|
||||
"github.com/containous/traefik/old/provider/rancher"
|
||||
"github.com/containous/traefik/old/provider/rest"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||
"github.com/containous/traefik/provider/docker"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/provider/kubernetes/ingress"
|
||||
newtypes "github.com/containous/traefik/types"
|
||||
"github.com/go-acme/lego/challenge/dns01"
|
||||
"github.com/pkg/errors"
|
||||
@ -92,7 +92,7 @@ type GlobalConfiguration struct {
|
||||
Etcd *etcd.Provider `description:"Enable Etcd backend with default settings" export:"true"`
|
||||
Zookeeper *zk.Provider `description:"Enable Zookeeper backend with default settings" export:"true"`
|
||||
Boltdb *boltdb.Provider `description:"Enable Boltdb backend with default settings" export:"true"`
|
||||
Kubernetes *kubernetes.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||
Kubernetes *ingress.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||
Mesos *mesos.Provider `description:"Enable Mesos backend with default settings" export:"true"`
|
||||
Eureka *eureka.Provider `description:"Enable Eureka backend with default settings" export:"true"`
|
||||
ECS *ecs.Provider `description:"Enable ECS backend with default settings" export:"true"`
|
||||
|
@ -1,122 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/containous/traefik/old/provider/label"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationKubernetesIngressClass = "kubernetes.io/ingress.class"
|
||||
annotationKubernetesAuthRealm = "ingress.kubernetes.io/auth-realm"
|
||||
annotationKubernetesAuthType = "ingress.kubernetes.io/auth-type"
|
||||
annotationKubernetesAuthSecret = "ingress.kubernetes.io/auth-secret"
|
||||
annotationKubernetesAuthHeaderField = "ingress.kubernetes.io/auth-header-field"
|
||||
annotationKubernetesAuthForwardResponseHeaders = "ingress.kubernetes.io/auth-response-headers"
|
||||
annotationKubernetesAuthRemoveHeader = "ingress.kubernetes.io/auth-remove-header"
|
||||
annotationKubernetesAuthForwardURL = "ingress.kubernetes.io/auth-url"
|
||||
annotationKubernetesAuthForwardTrustHeaders = "ingress.kubernetes.io/auth-trust-headers"
|
||||
annotationKubernetesAuthForwardTLSSecret = "ingress.kubernetes.io/auth-tls-secret"
|
||||
annotationKubernetesAuthForwardTLSInsecure = "ingress.kubernetes.io/auth-tls-insecure"
|
||||
annotationKubernetesRewriteTarget = "ingress.kubernetes.io/rewrite-target"
|
||||
annotationKubernetesWhiteListSourceRange = "ingress.kubernetes.io/whitelist-source-range"
|
||||
annotationKubernetesWhiteListIPStrategy = "ingress.kubernetes.io/whitelist-ipstrategy"
|
||||
annotationKubernetesWhiteListIPStrategyDepth = "ingress.kubernetes.io/whitelist-ipstrategy-depth"
|
||||
annotationKubernetesWhiteListIPStrategyExcludedIPs = "ingress.kubernetes.io/whitelist-ipstrategy-excluded-ips"
|
||||
annotationKubernetesPreserveHost = "ingress.kubernetes.io/preserve-host"
|
||||
annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert" // Deprecated
|
||||
annotationKubernetesPassTLSClientCert = "ingress.kubernetes.io/pass-client-tls-cert"
|
||||
annotationKubernetesFrontendEntryPoints = "ingress.kubernetes.io/frontend-entry-points"
|
||||
annotationKubernetesPriority = "ingress.kubernetes.io/priority"
|
||||
annotationKubernetesCircuitBreakerExpression = "ingress.kubernetes.io/circuit-breaker-expression"
|
||||
annotationKubernetesLoadBalancerMethod = "ingress.kubernetes.io/load-balancer-method"
|
||||
annotationKubernetesAffinity = "ingress.kubernetes.io/affinity"
|
||||
annotationKubernetesSessionCookieName = "ingress.kubernetes.io/session-cookie-name"
|
||||
annotationKubernetesRuleType = "ingress.kubernetes.io/rule-type"
|
||||
annotationKubernetesRedirectEntryPoint = "ingress.kubernetes.io/redirect-entry-point"
|
||||
annotationKubernetesRedirectPermanent = "ingress.kubernetes.io/redirect-permanent"
|
||||
annotationKubernetesRedirectRegex = "ingress.kubernetes.io/redirect-regex"
|
||||
annotationKubernetesRedirectReplacement = "ingress.kubernetes.io/redirect-replacement"
|
||||
annotationKubernetesMaxConnAmount = "ingress.kubernetes.io/max-conn-amount"
|
||||
annotationKubernetesMaxConnExtractorFunc = "ingress.kubernetes.io/max-conn-extractor-func"
|
||||
annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit"
|
||||
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages"
|
||||
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering"
|
||||
annotationKubernetesResponseForwardingFlushInterval = "ingress.kubernetes.io/responseforwarding-flushinterval"
|
||||
annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root"
|
||||
annotationKubernetesServiceWeights = "ingress.kubernetes.io/service-weights"
|
||||
annotationKubernetesRequestModifier = "ingress.kubernetes.io/request-modifier"
|
||||
|
||||
annotationKubernetesSSLForceHost = "ingress.kubernetes.io/ssl-force-host"
|
||||
annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect"
|
||||
annotationKubernetesHSTSMaxAge = "ingress.kubernetes.io/hsts-max-age"
|
||||
annotationKubernetesHSTSIncludeSubdomains = "ingress.kubernetes.io/hsts-include-subdomains"
|
||||
annotationKubernetesCustomRequestHeaders = "ingress.kubernetes.io/custom-request-headers"
|
||||
annotationKubernetesCustomResponseHeaders = "ingress.kubernetes.io/custom-response-headers"
|
||||
annotationKubernetesAllowedHosts = "ingress.kubernetes.io/allowed-hosts"
|
||||
annotationKubernetesProxyHeaders = "ingress.kubernetes.io/proxy-headers"
|
||||
annotationKubernetesSSLTemporaryRedirect = "ingress.kubernetes.io/ssl-temporary-redirect"
|
||||
annotationKubernetesSSLHost = "ingress.kubernetes.io/ssl-host"
|
||||
annotationKubernetesSSLProxyHeaders = "ingress.kubernetes.io/ssl-proxy-headers"
|
||||
annotationKubernetesHSTSPreload = "ingress.kubernetes.io/hsts-preload"
|
||||
annotationKubernetesForceHSTSHeader = "ingress.kubernetes.io/force-hsts"
|
||||
annotationKubernetesFrameDeny = "ingress.kubernetes.io/frame-deny"
|
||||
annotationKubernetesCustomFrameOptionsValue = "ingress.kubernetes.io/custom-frame-options-value"
|
||||
annotationKubernetesContentTypeNosniff = "ingress.kubernetes.io/content-type-nosniff"
|
||||
annotationKubernetesBrowserXSSFilter = "ingress.kubernetes.io/browser-xss-filter"
|
||||
annotationKubernetesCustomBrowserXSSValue = "ingress.kubernetes.io/custom-browser-xss-value"
|
||||
annotationKubernetesContentSecurityPolicy = "ingress.kubernetes.io/content-security-policy"
|
||||
annotationKubernetesPublicKey = "ingress.kubernetes.io/public-key"
|
||||
annotationKubernetesReferrerPolicy = "ingress.kubernetes.io/referrer-policy"
|
||||
annotationKubernetesIsDevelopment = "ingress.kubernetes.io/is-development"
|
||||
annotationKubernetesProtocol = "ingress.kubernetes.io/protocol"
|
||||
)
|
||||
|
||||
func getAnnotationName(annotations map[string]string, name string) string {
|
||||
if _, ok := annotations[name]; ok {
|
||||
return name
|
||||
}
|
||||
|
||||
if _, ok := annotations[label.Prefix+name]; ok {
|
||||
return label.Prefix + name
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func getStringValue(annotations map[string]string, annotation string, defaultValue string) string {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetStringValue(annotations, annotationName, defaultValue)
|
||||
}
|
||||
|
||||
func getStringSafeValue(annotations map[string]string, annotation string, defaultValue string) (string, error) {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
value := label.GetStringValue(annotations, annotationName, defaultValue)
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return value, err
|
||||
}
|
||||
|
||||
func getBoolValue(annotations map[string]string, annotation string, defaultValue bool) bool {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetBoolValue(annotations, annotationName, defaultValue)
|
||||
}
|
||||
|
||||
func getIntValue(annotations map[string]string, annotation string, defaultValue int) int {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetIntValue(annotations, annotationName, defaultValue)
|
||||
}
|
||||
|
||||
func getInt64Value(annotations map[string]string, annotation string, defaultValue int64) int64 {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetInt64Value(annotations, annotationName, defaultValue)
|
||||
}
|
||||
|
||||
func getSliceStringValue(annotations map[string]string, annotation string) []string {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetSliceStringValue(annotations, annotationName)
|
||||
}
|
||||
|
||||
func getMapValue(annotations map[string]string, annotation string) map[string]string {
|
||||
annotationName := getAnnotationName(annotations, annotation)
|
||||
return label.GetMapValue(annotations, annotationName)
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/old/provider/label"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetAnnotationName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
annotations map[string]string
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "with standard annotation",
|
||||
name: annotationKubernetesPreserveHost,
|
||||
annotations: map[string]string{
|
||||
annotationKubernetesPreserveHost: "true",
|
||||
},
|
||||
expected: annotationKubernetesPreserveHost,
|
||||
},
|
||||
{
|
||||
desc: "with prefixed annotation",
|
||||
name: annotationKubernetesPreserveHost,
|
||||
annotations: map[string]string{
|
||||
label.Prefix + annotationKubernetesPreserveHost: "true",
|
||||
},
|
||||
expected: label.Prefix + annotationKubernetesPreserveHost,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := getAnnotationName(test.annotations, test.name)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,647 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/flaeg/parse"
|
||||
"github.com/containous/traefik/old/provider/label"
|
||||
"github.com/containous/traefik/old/types"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func buildConfiguration(opts ...func(*types.Configuration)) *types.Configuration {
|
||||
conf := &types.Configuration{}
|
||||
for _, opt := range opts {
|
||||
opt(conf)
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
// Backend
|
||||
|
||||
func backends(opts ...func(*types.Backend) string) func(*types.Configuration) {
|
||||
return func(c *types.Configuration) {
|
||||
c.Backends = make(map[string]*types.Backend)
|
||||
for _, opt := range opts {
|
||||
b := &types.Backend{}
|
||||
name := opt(b)
|
||||
c.Backends[name] = b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func backend(name string, opts ...func(*types.Backend)) func(*types.Backend) string {
|
||||
return func(b *types.Backend) string {
|
||||
for _, opt := range opts {
|
||||
opt(b)
|
||||
}
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
func servers(opts ...func(*types.Server) string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
b.Servers = make(map[string]types.Server)
|
||||
for _, opt := range opts {
|
||||
s := &types.Server{}
|
||||
name := opt(s)
|
||||
b.Servers[name] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func server(url string, opts ...func(*types.Server)) func(*types.Server) string {
|
||||
return func(s *types.Server) string {
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
s.URL = url
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
func weight(value int) func(*types.Server) {
|
||||
return func(s *types.Server) {
|
||||
s.Weight = value
|
||||
}
|
||||
}
|
||||
|
||||
func lbMethod(method string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
if b.LoadBalancer == nil {
|
||||
b.LoadBalancer = &types.LoadBalancer{}
|
||||
}
|
||||
b.LoadBalancer.Method = method
|
||||
}
|
||||
}
|
||||
|
||||
func lbStickiness() func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
if b.LoadBalancer == nil {
|
||||
b.LoadBalancer = &types.LoadBalancer{}
|
||||
}
|
||||
b.LoadBalancer.Stickiness = &types.Stickiness{}
|
||||
}
|
||||
}
|
||||
|
||||
func circuitBreaker(exp string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
b.CircuitBreaker = &types.CircuitBreaker{}
|
||||
b.CircuitBreaker.Expression = exp
|
||||
}
|
||||
}
|
||||
|
||||
func responseForwarding(interval string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
b.ResponseForwarding = &types.ResponseForwarding{}
|
||||
b.ResponseForwarding.FlushInterval = interval
|
||||
}
|
||||
}
|
||||
|
||||
func buffering(opts ...func(*types.Buffering)) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
if b.Buffering == nil {
|
||||
b.Buffering = &types.Buffering{}
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(b.Buffering)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func maxRequestBodyBytes(value int64) func(*types.Buffering) {
|
||||
return func(b *types.Buffering) {
|
||||
b.MaxRequestBodyBytes = value
|
||||
}
|
||||
}
|
||||
|
||||
func memRequestBodyBytes(value int64) func(*types.Buffering) {
|
||||
return func(b *types.Buffering) {
|
||||
b.MemRequestBodyBytes = value
|
||||
}
|
||||
}
|
||||
|
||||
func maxResponseBodyBytes(value int64) func(*types.Buffering) {
|
||||
return func(b *types.Buffering) {
|
||||
b.MaxResponseBodyBytes = value
|
||||
}
|
||||
}
|
||||
|
||||
func memResponseBodyBytes(value int64) func(*types.Buffering) {
|
||||
return func(b *types.Buffering) {
|
||||
b.MemResponseBodyBytes = value
|
||||
}
|
||||
}
|
||||
|
||||
func retrying(exp string) func(*types.Buffering) {
|
||||
return func(b *types.Buffering) {
|
||||
b.RetryExpression = exp
|
||||
}
|
||||
}
|
||||
|
||||
func maxConnExtractorFunc(exp string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
if b.MaxConn == nil {
|
||||
b.MaxConn = &types.MaxConn{}
|
||||
}
|
||||
b.MaxConn.ExtractorFunc = exp
|
||||
}
|
||||
}
|
||||
|
||||
func maxConnAmount(value int64) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
if b.MaxConn == nil {
|
||||
b.MaxConn = &types.MaxConn{}
|
||||
}
|
||||
b.MaxConn.Amount = value
|
||||
}
|
||||
}
|
||||
|
||||
// Frontend
|
||||
|
||||
func buildFrontends(opts ...func(*types.Frontend) string) map[string]*types.Frontend {
|
||||
fronts := make(map[string]*types.Frontend)
|
||||
for _, opt := range opts {
|
||||
f := &types.Frontend{}
|
||||
name := opt(f)
|
||||
fronts[name] = f
|
||||
}
|
||||
return fronts
|
||||
}
|
||||
|
||||
func frontends(opts ...func(*types.Frontend) string) func(*types.Configuration) {
|
||||
return func(c *types.Configuration) {
|
||||
c.Frontends = make(map[string]*types.Frontend)
|
||||
for _, opt := range opts {
|
||||
f := &types.Frontend{}
|
||||
name := opt(f)
|
||||
c.Frontends[name] = f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func frontend(backend string, opts ...func(*types.Frontend)) func(*types.Frontend) string {
|
||||
return func(f *types.Frontend) string {
|
||||
for _, opt := range opts {
|
||||
opt(f)
|
||||
}
|
||||
// related the function frontendName
|
||||
name := f.Backend
|
||||
f.Backend = backend
|
||||
if len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
return backend
|
||||
}
|
||||
}
|
||||
|
||||
func frontendName(name string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
// store temporary the frontend name into the backend name
|
||||
f.Backend = name
|
||||
}
|
||||
}
|
||||
func passHostHeader() func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.PassHostHeader = true
|
||||
}
|
||||
}
|
||||
|
||||
func entryPoints(eps ...string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.EntryPoints = eps
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
func basicAuthDeprecated(auth ...string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.Auth = &types.Auth{Basic: &types.Basic{Users: auth}}
|
||||
}
|
||||
}
|
||||
|
||||
func auth(opt func(*types.Auth)) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
auth := &types.Auth{}
|
||||
opt(auth)
|
||||
f.Auth = auth
|
||||
}
|
||||
}
|
||||
|
||||
func basicAuth(users ...string) func(*types.Auth) {
|
||||
return func(a *types.Auth) {
|
||||
a.Basic = &types.Basic{Users: users}
|
||||
}
|
||||
}
|
||||
|
||||
func forwardAuth(forwardURL string, opts ...func(*types.Forward)) func(*types.Auth) {
|
||||
return func(a *types.Auth) {
|
||||
fwd := &types.Forward{Address: forwardURL}
|
||||
for _, opt := range opts {
|
||||
opt(fwd)
|
||||
}
|
||||
a.Forward = fwd
|
||||
}
|
||||
}
|
||||
|
||||
func fwdAuthResponseHeaders(headers ...string) func(*types.Forward) {
|
||||
return func(f *types.Forward) {
|
||||
f.AuthResponseHeaders = headers
|
||||
}
|
||||
}
|
||||
|
||||
func fwdTrustForwardHeader() func(*types.Forward) {
|
||||
return func(f *types.Forward) {
|
||||
f.TrustForwardHeader = true
|
||||
}
|
||||
}
|
||||
|
||||
func fwdAuthTLS(cert, key string, insecure bool) func(*types.Forward) {
|
||||
return func(f *types.Forward) {
|
||||
f.TLS = &types.ClientTLS{Cert: cert, Key: key, InsecureSkipVerify: insecure}
|
||||
}
|
||||
}
|
||||
|
||||
func whiteListRange(ranges ...string) func(*types.WhiteList) {
|
||||
return func(wl *types.WhiteList) {
|
||||
wl.SourceRange = ranges
|
||||
}
|
||||
}
|
||||
|
||||
func whiteListIPStrategy(depth int, excludedIPs ...string) func(*types.WhiteList) {
|
||||
return func(wl *types.WhiteList) {
|
||||
wl.IPStrategy = &types.IPStrategy{
|
||||
Depth: depth,
|
||||
ExcludedIPs: excludedIPs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func whiteList(opts ...func(*types.WhiteList)) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
if f.WhiteList == nil {
|
||||
f.WhiteList = &types.WhiteList{}
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(f.WhiteList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func priority(value int) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.Priority = value
|
||||
}
|
||||
}
|
||||
|
||||
func headers(h *types.Headers) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.Headers = h
|
||||
}
|
||||
}
|
||||
|
||||
func redirectEntryPoint(name string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
if f.Redirect == nil {
|
||||
f.Redirect = &types.Redirect{}
|
||||
}
|
||||
f.Redirect.EntryPoint = name
|
||||
}
|
||||
}
|
||||
|
||||
func redirectRegex(regex, replacement string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
if f.Redirect == nil {
|
||||
f.Redirect = &types.Redirect{}
|
||||
}
|
||||
f.Redirect.Regex = regex
|
||||
f.Redirect.Replacement = replacement
|
||||
}
|
||||
}
|
||||
|
||||
func errorPage(name string, opts ...func(*types.ErrorPage)) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
if f.Errors == nil {
|
||||
f.Errors = make(map[string]*types.ErrorPage)
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
f.Errors[name] = &types.ErrorPage{}
|
||||
for _, opt := range opts {
|
||||
opt(f.Errors[name])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func errorStatus(status ...string) func(*types.ErrorPage) {
|
||||
return func(page *types.ErrorPage) {
|
||||
page.Status = status
|
||||
}
|
||||
}
|
||||
|
||||
func errorQuery(query string) func(*types.ErrorPage) {
|
||||
return func(page *types.ErrorPage) {
|
||||
page.Query = query
|
||||
}
|
||||
}
|
||||
|
||||
func errorBackend(backend string) func(*types.ErrorPage) {
|
||||
return func(page *types.ErrorPage) {
|
||||
page.Backend = backend
|
||||
}
|
||||
}
|
||||
|
||||
func rateLimit(opts ...func(*types.RateLimit)) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
if f.RateLimit == nil {
|
||||
f.RateLimit = &types.RateLimit{}
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(f.RateLimit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func rateExtractorFunc(exp string) func(*types.RateLimit) {
|
||||
return func(limit *types.RateLimit) {
|
||||
limit.ExtractorFunc = exp
|
||||
}
|
||||
}
|
||||
|
||||
func rateSet(name string, opts ...func(*types.Rate)) func(*types.RateLimit) {
|
||||
return func(limit *types.RateLimit) {
|
||||
if limit.RateSet == nil {
|
||||
limit.RateSet = make(map[string]*types.Rate)
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
limit.RateSet[name] = &types.Rate{}
|
||||
for _, opt := range opts {
|
||||
opt(limit.RateSet[name])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func limitAverage(avg int64) func(*types.Rate) {
|
||||
return func(rate *types.Rate) {
|
||||
rate.Average = avg
|
||||
}
|
||||
}
|
||||
|
||||
func limitBurst(burst int64) func(*types.Rate) {
|
||||
return func(rate *types.Rate) {
|
||||
rate.Burst = burst
|
||||
}
|
||||
}
|
||||
|
||||
func limitPeriod(period time.Duration) func(*types.Rate) {
|
||||
return func(rate *types.Rate) {
|
||||
rate.Period = parse.Duration(period)
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
func passTLSCert() func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.PassTLSCert = true
|
||||
}
|
||||
}
|
||||
|
||||
func passTLSClientCert() func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.PassTLSClientCert = &types.TLSClientHeaders{
|
||||
PEM: true,
|
||||
Infos: &types.TLSClientCertificateInfos{
|
||||
NotAfter: true,
|
||||
NotBefore: true,
|
||||
Subject: &types.TLSCLientCertificateDNInfos{
|
||||
CommonName: true,
|
||||
Country: true,
|
||||
DomainComponent: true,
|
||||
Locality: true,
|
||||
Organization: true,
|
||||
Province: true,
|
||||
SerialNumber: true,
|
||||
},
|
||||
Issuer: &types.TLSCLientCertificateDNInfos{
|
||||
CommonName: true,
|
||||
Country: true,
|
||||
DomainComponent: true,
|
||||
Locality: true,
|
||||
Organization: true,
|
||||
Province: true,
|
||||
SerialNumber: true,
|
||||
},
|
||||
Sans: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func routes(opts ...func(*types.Route) string) func(*types.Frontend) {
|
||||
return func(f *types.Frontend) {
|
||||
f.Routes = make(map[string]types.Route)
|
||||
for _, opt := range opts {
|
||||
s := &types.Route{}
|
||||
name := opt(s)
|
||||
f.Routes[name] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func route(name string, rule string) func(*types.Route) string {
|
||||
return func(r *types.Route) string {
|
||||
r.Rule = rule
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
func tlsesSection(opts ...func(*tls.Configuration)) func(*types.Configuration) {
|
||||
return func(c *types.Configuration) {
|
||||
for _, opt := range opts {
|
||||
tlsConf := &tls.Configuration{}
|
||||
opt(tlsConf)
|
||||
c.TLS = append(c.TLS, tlsConf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tlsSection(opts ...func(*tls.Configuration)) func(*tls.Configuration) {
|
||||
return func(c *tls.Configuration) {
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tlsEntryPoints(entryPoints ...string) func(*tls.Configuration) {
|
||||
return func(c *tls.Configuration) {
|
||||
c.Stores = entryPoints
|
||||
}
|
||||
}
|
||||
|
||||
func certificate(cert string, key string) func(*tls.Configuration) {
|
||||
return func(c *tls.Configuration) {
|
||||
c.Certificate = &tls.Certificate{
|
||||
CertFile: tls.FileOrContent(cert),
|
||||
KeyFile: tls.FileOrContent(key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildConfiguration(t *testing.T) {
|
||||
actual := buildConfiguration(
|
||||
backends(
|
||||
backend("foo/bar",
|
||||
servers(
|
||||
server("http://10.10.0.1:8080", weight(1)),
|
||||
server("http://10.21.0.1:8080", weight(1)),
|
||||
),
|
||||
lbMethod("wrr"),
|
||||
),
|
||||
backend("foo/namedthing",
|
||||
servers(server("https://example.com", weight(1))),
|
||||
lbMethod("wrr"),
|
||||
),
|
||||
backend("bar",
|
||||
servers(
|
||||
server("https://10.15.0.1:8443", weight(1)),
|
||||
server("https://10.15.0.2:9443", weight(1)),
|
||||
),
|
||||
lbMethod("wrr"),
|
||||
),
|
||||
),
|
||||
frontends(
|
||||
frontend("foo/bar",
|
||||
passHostHeader(),
|
||||
routes(
|
||||
route("/bar", "PathPrefix:/bar"),
|
||||
route("foo", "Host:foo"),
|
||||
),
|
||||
),
|
||||
frontend("foo/namedthing",
|
||||
passHostHeader(),
|
||||
routes(
|
||||
route("/namedthing", "PathPrefix:/namedthing"),
|
||||
route("foo", "Host:foo"),
|
||||
),
|
||||
),
|
||||
frontend("bar",
|
||||
passHostHeader(),
|
||||
routes(
|
||||
route("bar", "Host:bar"),
|
||||
),
|
||||
),
|
||||
),
|
||||
tlsesSection(
|
||||
tlsSection(
|
||||
tlsEntryPoints("https"),
|
||||
certificate("certificate", "key"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleConfiguration(), actual)
|
||||
}
|
||||
|
||||
func sampleConfiguration() *types.Configuration {
|
||||
return &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
"foo/bar": {
|
||||
Servers: map[string]types.Server{
|
||||
"http://10.10.0.1:8080": {
|
||||
URL: "http://10.10.0.1:8080",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"http://10.21.0.1:8080": {
|
||||
URL: "http://10.21.0.1:8080",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
LoadBalancer: &types.LoadBalancer{
|
||||
Method: "wrr",
|
||||
},
|
||||
},
|
||||
"foo/namedthing": {
|
||||
Servers: map[string]types.Server{
|
||||
"https://example.com": {
|
||||
URL: "https://example.com",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
LoadBalancer: &types.LoadBalancer{
|
||||
Method: "wrr",
|
||||
},
|
||||
},
|
||||
"bar": {
|
||||
Servers: map[string]types.Server{
|
||||
"https://10.15.0.1:8443": {
|
||||
URL: "https://10.15.0.1:8443",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"https://10.15.0.2:9443": {
|
||||
URL: "https://10.15.0.2:9443",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
LoadBalancer: &types.LoadBalancer{
|
||||
Method: "wrr",
|
||||
},
|
||||
},
|
||||
},
|
||||
Frontends: map[string]*types.Frontend{
|
||||
"foo/bar": {
|
||||
Backend: "foo/bar",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"/bar": {
|
||||
Rule: "PathPrefix:/bar",
|
||||
},
|
||||
"foo": {
|
||||
Rule: "Host:foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
"foo/namedthing": {
|
||||
Backend: "foo/namedthing",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"/namedthing": {
|
||||
Rule: "PathPrefix:/namedthing",
|
||||
},
|
||||
"foo": {
|
||||
Rule: "Host:foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bar": {
|
||||
Backend: "bar",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"bar": {
|
||||
Rule: "Host:bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: []*tls.Configuration{
|
||||
{
|
||||
Stores: []string{"https"},
|
||||
Certificate: &tls.Certificate{
|
||||
CertFile: tls.FileOrContent("certificate"),
|
||||
KeyFile: tls.FileOrContent("key"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildEndpoint(opts ...func(*corev1.Endpoints)) *corev1.Endpoints {
|
||||
e := &corev1.Endpoints{}
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func eNamespace(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func eName(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func eUID(value types.UID) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func subset(opts ...func(*corev1.EndpointSubset)) func(*corev1.Endpoints) {
|
||||
return func(e *corev1.Endpoints) {
|
||||
s := &corev1.EndpointSubset{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
e.Subsets = append(e.Subsets, *s)
|
||||
}
|
||||
}
|
||||
|
||||
func eAddresses(opts ...func(*corev1.EndpointAddress)) func(*corev1.EndpointSubset) {
|
||||
return func(subset *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
a := &corev1.EndpointAddress{}
|
||||
opt(a)
|
||||
subset.Addresses = append(subset.Addresses, *a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func eAddress(ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func eAddressWithTargetRef(targetRef, ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.TargetRef = &corev1.ObjectReference{Name: targetRef}
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func ePorts(opts ...func(port *corev1.EndpointPort)) func(*corev1.EndpointSubset) {
|
||||
return func(spec *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.EndpointPort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ePort(port int32, name string) func(*corev1.EndpointPort) {
|
||||
return func(sp *corev1.EndpointPort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildEndpoint(t *testing.T) {
|
||||
actual := buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service3"),
|
||||
eUID("3"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.1")),
|
||||
ePorts(
|
||||
ePort(8080, "http"),
|
||||
ePort(8443, "https"),
|
||||
),
|
||||
),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.2")),
|
||||
ePorts(
|
||||
ePort(9080, "http"),
|
||||
ePort(9443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleEndpoint1(), actual)
|
||||
}
|
||||
|
||||
func sampleEndpoint1() *corev1.Endpoints {
|
||||
return &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.1",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.2",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 9080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 9443,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress(opts ...func(*extensionsv1beta1.Ingress)) *extensionsv1beta1.Ingress {
|
||||
i := &extensionsv1beta1.Ingress{}
|
||||
for _, opt := range opts {
|
||||
opt(i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func iNamespace(value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func iAnnotation(name string, value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
if i.Annotations == nil {
|
||||
i.Annotations = make(map[string]string)
|
||||
}
|
||||
i.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func iRules(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackends(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackend(opts ...func(*extensionsv1beta1.IngressBackend)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(s *extensionsv1beta1.IngressSpec) {
|
||||
p := &extensionsv1beta1.IngressBackend{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
s.Backend = p
|
||||
}
|
||||
}
|
||||
|
||||
func iIngressBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.IngressBackend) {
|
||||
return func(p *extensionsv1beta1.IngressBackend) {
|
||||
p.ServiceName = name
|
||||
p.ServicePort = port
|
||||
}
|
||||
}
|
||||
|
||||
func iRule(opts ...func(*extensionsv1beta1.IngressRule)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(spec *extensionsv1beta1.IngressSpec) {
|
||||
r := &extensionsv1beta1.IngressRule{}
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
spec.Rules = append(spec.Rules, *r)
|
||||
}
|
||||
}
|
||||
|
||||
func iHost(name string) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.Host = name
|
||||
}
|
||||
}
|
||||
|
||||
func iPaths(opts ...func(*extensionsv1beta1.HTTPIngressRuleValue)) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.HTTP = &extensionsv1beta1.HTTPIngressRuleValue{}
|
||||
for _, opt := range opts {
|
||||
opt(rule.HTTP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func onePath(opts ...func(*extensionsv1beta1.HTTPIngressPath)) func(*extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
return func(irv *extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
p := &extensionsv1beta1.HTTPIngressPath{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
irv.Paths = append(irv.Paths, *p)
|
||||
}
|
||||
}
|
||||
|
||||
func iPath(name string) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Path = name
|
||||
}
|
||||
}
|
||||
|
||||
func iBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Backend = extensionsv1beta1.IngressBackend{
|
||||
ServiceName: name,
|
||||
ServicePort: port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLSes(opts ...func(*extensionsv1beta1.IngressTLS)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
for _, opt := range opts {
|
||||
iTLS := extensionsv1beta1.IngressTLS{}
|
||||
opt(&iTLS)
|
||||
i.Spec.TLS = append(i.Spec.TLS, iTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLS(secret string, hosts ...string) func(*extensionsv1beta1.IngressTLS) {
|
||||
return func(i *extensionsv1beta1.IngressTLS) {
|
||||
i.SecretName = secret
|
||||
i.Hosts = hosts
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildIngress(t *testing.T) {
|
||||
i := buildIngress(
|
||||
iNamespace("testing"),
|
||||
iRules(
|
||||
iRule(iHost("foo"), iPaths(
|
||||
onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))),
|
||||
onePath(iPath("/namedthing"), iBackend("service4", intstr.FromString("https")))),
|
||||
),
|
||||
iRule(iHost("bar"), iPaths(
|
||||
onePath(iBackend("service3", intstr.FromString("https"))),
|
||||
onePath(iBackend("service2", intstr.FromInt(802))),
|
||||
),
|
||||
),
|
||||
),
|
||||
iTLSes(
|
||||
iTLS("tls-secret", "foo"),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleIngress(), i)
|
||||
}
|
||||
|
||||
func sampleIngress() *extensionsv1beta1.Ingress {
|
||||
return &extensionsv1beta1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: extensionsv1beta1.IngressSpec{
|
||||
Rules: []extensionsv1beta1.IngressRule{
|
||||
{
|
||||
Host: "foo",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Path: "/bar",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service1",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/namedthing",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service4",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Host: "bar",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service3",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service2",
|
||||
ServicePort: intstr.FromInt(802),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: []extensionsv1beta1.IngressTLS{
|
||||
{
|
||||
Hosts: []string{"foo"},
|
||||
SecretName: "tls-secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildService(opts ...func(*corev1.Service)) *corev1.Service {
|
||||
s := &corev1.Service{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sNamespace(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func sName(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func sUID(value types.UID) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func sAnnotation(name string, value string) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
if s.Annotations == nil {
|
||||
s.Annotations = make(map[string]string)
|
||||
}
|
||||
s.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func sSpec(opts ...func(*corev1.ServiceSpec)) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
spec := &corev1.ServiceSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(spec)
|
||||
}
|
||||
s.Spec = *spec
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerStatus(opts ...func(*corev1.LoadBalancerStatus)) func(service *corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
loadBalancer := &corev1.LoadBalancerStatus{}
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(loadBalancer)
|
||||
}
|
||||
}
|
||||
s.Status = corev1.ServiceStatus{
|
||||
LoadBalancer: *loadBalancer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerIngress(ip string, hostname string) func(*corev1.LoadBalancerStatus) {
|
||||
return func(status *corev1.LoadBalancerStatus) {
|
||||
ingress := corev1.LoadBalancerIngress{
|
||||
IP: ip,
|
||||
Hostname: hostname,
|
||||
}
|
||||
status.Ingress = append(status.Ingress, ingress)
|
||||
}
|
||||
}
|
||||
|
||||
func clusterIP(ip string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ClusterIP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func sType(value corev1.ServiceType) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.Type = value
|
||||
}
|
||||
}
|
||||
|
||||
func sExternalName(name string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ExternalName = name
|
||||
}
|
||||
}
|
||||
|
||||
func sPorts(opts ...func(*corev1.ServicePort)) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.ServicePort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sPort(port int32, name string) func(*corev1.ServicePort) {
|
||||
return func(sp *corev1.ServicePort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildService(t *testing.T) {
|
||||
actual1 := buildService(
|
||||
sName("service1"),
|
||||
sNamespace("testing"),
|
||||
sUID("1"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.1"),
|
||||
sPorts(sPort(80, "")),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService1(), actual1)
|
||||
|
||||
actual2 := buildService(
|
||||
sName("service2"),
|
||||
sNamespace("testing"),
|
||||
sUID("2"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.2"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(80, "http"),
|
||||
sPort(443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService2(), actual2)
|
||||
|
||||
actual3 := buildService(
|
||||
sName("service3"),
|
||||
sNamespace("testing"),
|
||||
sUID("3"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.3"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(8080, "http"),
|
||||
sPort(8443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService3(), actual3)
|
||||
}
|
||||
|
||||
func sampleService1() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service1",
|
||||
UID: "1",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService2() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service2",
|
||||
UID: "2",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.2",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 80,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService3() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.3",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
kubeerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestTranslateNotFoundError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
err error
|
||||
expectedExists bool
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
desc: "kubernetes not found error",
|
||||
err: kubeerror.NewNotFound(schema.GroupResource{}, "foo"),
|
||||
expectedExists: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
desc: "nil error",
|
||||
err: nil,
|
||||
expectedExists: true,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
desc: "not a kubernetes not found error",
|
||||
err: fmt.Errorf("bar error"),
|
||||
expectedExists: false,
|
||||
expectedError: fmt.Errorf("bar error"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
test := testCase
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
exists, err := translateNotFoundError(test.err)
|
||||
assert.Equal(t, test.expectedExists, exists)
|
||||
assert.Equal(t, test.expectedError, err)
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,32 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Namespaces holds kubernetes namespaces
|
||||
type Namespaces []string
|
||||
|
||||
// Set adds strings elem into the the parser
|
||||
// it splits str on , and ;
|
||||
func (ns *Namespaces) Set(str string) error {
|
||||
fargs := func(c rune) bool {
|
||||
return c == ',' || c == ';'
|
||||
}
|
||||
// get function
|
||||
slice := strings.FieldsFunc(str, fargs)
|
||||
*ns = append(*ns, slice...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get []string
|
||||
func (ns *Namespaces) Get() interface{} { return *ns }
|
||||
|
||||
// String return slice in a string
|
||||
func (ns *Namespaces) String() string { return fmt.Sprintf("%v", *ns) }
|
||||
|
||||
// SetValue sets []string into the parser
|
||||
func (ns *Namespaces) SetValue(val interface{}) {
|
||||
*ns = val.(Namespaces)
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const defaultPercentageValuePrecision = 3
|
||||
|
||||
// percentageValue is int64 form of percentage value with 10^-3 precision.
|
||||
type percentageValue int64
|
||||
|
||||
// toFloat64 returns its decimal float64 value.
|
||||
func (v percentageValue) toFloat64() float64 {
|
||||
return float64(v) / (1000 * 100)
|
||||
}
|
||||
|
||||
func (v percentageValue) computeWeight(count int) int {
|
||||
if count == 0 {
|
||||
return 0
|
||||
}
|
||||
return int(float64(v) / float64(count))
|
||||
}
|
||||
|
||||
// String returns its string form of percentage value.
|
||||
func (v percentageValue) String() string {
|
||||
return strconv.FormatFloat(v.toFloat64()*100, 'f', defaultPercentageValuePrecision, 64) + "%"
|
||||
}
|
||||
|
||||
// newPercentageValueFromString tries to read percentage value from string, it can be either "1.1" or "1.1%", "6%".
|
||||
// It will lose the extra precision if there are more digits after decimal point.
|
||||
func newPercentageValueFromString(rawValue string) (percentageValue, error) {
|
||||
if strings.HasSuffix(rawValue, "%") {
|
||||
rawValue = rawValue[:len(rawValue)-1]
|
||||
}
|
||||
value, err := strconv.ParseFloat(rawValue, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return newPercentageValueFromFloat64(value) / 100, nil
|
||||
}
|
||||
|
||||
// newPercentageValueFromFloat64 reads percentage value from float64
|
||||
func newPercentageValueFromFloat64(f float64) percentageValue {
|
||||
return percentageValue(f * (1000 * 100))
|
||||
}
|
@ -1,196 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewPercentageValueFromFloat64(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
value float64
|
||||
expectedString string
|
||||
expectedFloat64 float64
|
||||
}{
|
||||
{
|
||||
value: 0.01,
|
||||
expectedString: "1.000%",
|
||||
expectedFloat64: 0.01,
|
||||
},
|
||||
{
|
||||
value: 0.5,
|
||||
expectedString: "50.000%",
|
||||
expectedFloat64: 0.5,
|
||||
},
|
||||
{
|
||||
value: 0.99,
|
||||
expectedString: "99.000%",
|
||||
expectedFloat64: 0.99,
|
||||
},
|
||||
{
|
||||
value: 0.99999,
|
||||
expectedString: "99.999%",
|
||||
expectedFloat64: 0.99999,
|
||||
},
|
||||
{
|
||||
value: -0.99999,
|
||||
expectedString: "-99.999%",
|
||||
expectedFloat64: -0.99999,
|
||||
},
|
||||
{
|
||||
value: -0.9999999,
|
||||
expectedString: "-99.999%",
|
||||
expectedFloat64: -0.99999,
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
expectedString: "0.000%",
|
||||
expectedFloat64: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pvFromFloat64 := newPercentageValueFromFloat64(test.value)
|
||||
|
||||
assert.Equal(t, test.expectedString, pvFromFloat64.String(), "percentage string value mismatched")
|
||||
assert.Equal(t, test.expectedFloat64, pvFromFloat64.toFloat64(), "percentage float64 value mismatched")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPercentageValueFromString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
value string
|
||||
expectError bool
|
||||
expectedString string
|
||||
expectedFloat64 float64
|
||||
}{
|
||||
{
|
||||
value: "1%",
|
||||
expectError: false,
|
||||
expectedString: "1.000%",
|
||||
expectedFloat64: 0.01,
|
||||
},
|
||||
{
|
||||
value: "0.5",
|
||||
expectError: false,
|
||||
expectedString: "0.500%",
|
||||
expectedFloat64: 0.005,
|
||||
},
|
||||
{
|
||||
value: "99%",
|
||||
expectError: false,
|
||||
expectedString: "99.000%",
|
||||
expectedFloat64: 0.99,
|
||||
},
|
||||
{
|
||||
value: "99.9%",
|
||||
expectError: false,
|
||||
expectedString: "99.900%",
|
||||
expectedFloat64: 0.999,
|
||||
},
|
||||
{
|
||||
value: "-99.9%",
|
||||
expectError: false,
|
||||
expectedString: "-99.900%",
|
||||
expectedFloat64: -0.999,
|
||||
},
|
||||
{
|
||||
value: "-99.99999%",
|
||||
expectError: false,
|
||||
expectedString: "-99.999%",
|
||||
expectedFloat64: -0.99999,
|
||||
},
|
||||
{
|
||||
value: "0%",
|
||||
expectError: false,
|
||||
expectedString: "0.000%",
|
||||
expectedFloat64: 0,
|
||||
},
|
||||
{
|
||||
value: "%",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
value: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pvFromString, err := newPercentageValueFromString(test.value)
|
||||
|
||||
if test.expectError {
|
||||
require.Error(t, err, "expecting error but not happening")
|
||||
} else {
|
||||
require.NoError(t, err, "fail to parse percentage value")
|
||||
|
||||
assert.Equal(t, test.expectedString, pvFromString.String(), "percentage string value mismatched")
|
||||
assert.Equal(t, test.expectedFloat64, pvFromString.toFloat64(), "percentage float64 value mismatched")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPercentageValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
stringValue string
|
||||
floatValue float64
|
||||
}{
|
||||
{
|
||||
desc: "percentage",
|
||||
stringValue: "1%",
|
||||
floatValue: 0.01,
|
||||
},
|
||||
{
|
||||
desc: "decimal",
|
||||
stringValue: "0.5",
|
||||
floatValue: 0.005,
|
||||
},
|
||||
{
|
||||
desc: "negative percentage",
|
||||
stringValue: "-99.999%",
|
||||
floatValue: -0.99999,
|
||||
},
|
||||
{
|
||||
desc: "negative decimal",
|
||||
stringValue: "-0.99999",
|
||||
floatValue: -0.0099999,
|
||||
},
|
||||
{
|
||||
desc: "zero",
|
||||
stringValue: "0%",
|
||||
floatValue: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pvFromString, err := newPercentageValueFromString(test.stringValue)
|
||||
require.NoError(t, err, "fail to parse percentage value")
|
||||
|
||||
pvFromFloat64 := newPercentageValueFromFloat64(test.floatValue)
|
||||
|
||||
assert.Equal(t, pvFromString, pvFromFloat64)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/old/provider/label"
|
||||
"gopkg.in/yaml.v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
type weightAllocator interface {
|
||||
getWeight(host, path, serviceName string) int
|
||||
}
|
||||
|
||||
var _ weightAllocator = &defaultWeightAllocator{}
|
||||
var _ weightAllocator = &fractionalWeightAllocator{}
|
||||
|
||||
type defaultWeightAllocator struct{}
|
||||
|
||||
func (d *defaultWeightAllocator) getWeight(host, path, serviceName string) int {
|
||||
return label.DefaultWeight
|
||||
}
|
||||
|
||||
type ingressService struct {
|
||||
host string
|
||||
path string
|
||||
service string
|
||||
}
|
||||
|
||||
type fractionalWeightAllocator map[ingressService]int
|
||||
|
||||
// String returns a string representation as service name / percentage tuples
|
||||
// sorted by service names.
|
||||
// Example: [foo-svc: 30.000% bar-svc: 70.000%]
|
||||
func (f *fractionalWeightAllocator) String() string {
|
||||
var sorted []ingressService
|
||||
for ingServ := range map[ingressService]int(*f) {
|
||||
sorted = append(sorted, ingServ)
|
||||
}
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return sorted[i].service < sorted[j].service
|
||||
})
|
||||
|
||||
var res []string
|
||||
for _, ingServ := range sorted {
|
||||
res = append(res, fmt.Sprintf("%s: %s", ingServ.service, percentageValue(map[ingressService]int(*f)[ingServ])))
|
||||
}
|
||||
return fmt.Sprintf("[%s]", strings.Join(res, " "))
|
||||
}
|
||||
|
||||
func newFractionalWeightAllocator(ingress *extensionsv1beta1.Ingress, client Client) (*fractionalWeightAllocator, error) {
|
||||
servicePercentageWeights, err := getServicesPercentageWeights(ingress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceInstanceCounts, err := getServiceInstanceCounts(ingress, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceWeights := map[ingressService]int{}
|
||||
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
// key: rule path string
|
||||
// value: service names
|
||||
fractionalPathServices := map[string][]string{}
|
||||
|
||||
// key: rule path string
|
||||
// value: fractional percentage weight
|
||||
fractionalPathWeights := map[string]percentageValue{}
|
||||
|
||||
for _, pa := range rule.HTTP.Paths {
|
||||
if _, ok := fractionalPathWeights[pa.Path]; !ok {
|
||||
fractionalPathWeights[pa.Path] = newPercentageValueFromFloat64(1)
|
||||
}
|
||||
|
||||
if weight, ok := servicePercentageWeights[pa.Backend.ServiceName]; ok {
|
||||
ingSvc := ingressService{
|
||||
host: rule.Host,
|
||||
path: pa.Path,
|
||||
service: pa.Backend.ServiceName,
|
||||
}
|
||||
|
||||
serviceWeights[ingSvc] = weight.computeWeight(serviceInstanceCounts[ingSvc])
|
||||
|
||||
fractionalPathWeights[pa.Path] -= weight
|
||||
|
||||
if fractionalPathWeights[pa.Path].toFloat64() < 0 {
|
||||
assignedWeight := newPercentageValueFromFloat64(1) - fractionalPathWeights[pa.Path]
|
||||
return nil, fmt.Errorf("percentage value %s must not exceed 100%%", assignedWeight.String())
|
||||
}
|
||||
} else {
|
||||
fractionalPathServices[pa.Path] = append(fractionalPathServices[pa.Path], pa.Backend.ServiceName)
|
||||
}
|
||||
}
|
||||
|
||||
for pa, fractionalWeight := range fractionalPathWeights {
|
||||
fractionalServices := fractionalPathServices[pa]
|
||||
|
||||
if len(fractionalServices) == 0 {
|
||||
if fractionalWeight > 0 {
|
||||
assignedWeight := newPercentageValueFromFloat64(1) - fractionalWeight
|
||||
return nil, fmt.Errorf("the sum of weights(%s) in the path %s%s must be 100%% when no omitted fractional service left", assignedWeight.String(), rule.Host, pa)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
totalFractionalInstanceCount := 0
|
||||
for _, svc := range fractionalServices {
|
||||
totalFractionalInstanceCount += serviceInstanceCounts[ingressService{
|
||||
host: rule.Host,
|
||||
path: pa,
|
||||
service: svc,
|
||||
}]
|
||||
}
|
||||
|
||||
for _, svc := range fractionalServices {
|
||||
ingSvc := ingressService{
|
||||
host: rule.Host,
|
||||
path: pa,
|
||||
service: svc,
|
||||
}
|
||||
serviceWeights[ingSvc] = fractionalWeight.computeWeight(totalFractionalInstanceCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allocator := fractionalWeightAllocator(serviceWeights)
|
||||
return &allocator, nil
|
||||
}
|
||||
|
||||
func (f *fractionalWeightAllocator) getWeight(host, path, serviceName string) int {
|
||||
return map[ingressService]int(*f)[ingressService{
|
||||
host: host,
|
||||
path: path,
|
||||
service: serviceName,
|
||||
}]
|
||||
}
|
||||
|
||||
func getServicesPercentageWeights(ingress *extensionsv1beta1.Ingress) (map[string]percentageValue, error) {
|
||||
percentageWeight := make(map[string]string)
|
||||
|
||||
annotationPercentageWeights := getAnnotationName(ingress.Annotations, annotationKubernetesServiceWeights)
|
||||
if err := yaml.Unmarshal([]byte(ingress.Annotations[annotationPercentageWeights]), percentageWeight); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
servicesPercentageWeights := make(map[string]percentageValue)
|
||||
for serviceName, percentageStr := range percentageWeight {
|
||||
percentageValue, err := newPercentageValueFromString(percentageStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid percentage value %q", percentageStr)
|
||||
}
|
||||
|
||||
servicesPercentageWeights[serviceName] = percentageValue
|
||||
}
|
||||
return servicesPercentageWeights, nil
|
||||
}
|
||||
|
||||
func getServiceInstanceCounts(ingress *extensionsv1beta1.Ingress, client Client) (map[ingressService]int, error) {
|
||||
serviceInstanceCounts := map[ingressService]int{}
|
||||
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
for _, pa := range rule.HTTP.Paths {
|
||||
svc, exists, err := client.GetService(ingress.Namespace, pa.Backend.ServiceName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get service %s/%s: %v", ingress.Namespace, pa.Backend.ServiceName, err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("service not found for %s/%s", ingress.Namespace, pa.Backend.ServiceName)
|
||||
}
|
||||
if svc.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
// external-name service has only one instance b/c it will actually be interpreted as a DNS record
|
||||
// instead of real server.
|
||||
serviceInstanceCounts[ingressService{
|
||||
host: rule.Host,
|
||||
path: pa.Path,
|
||||
service: pa.Backend.ServiceName,
|
||||
}] = 1
|
||||
continue
|
||||
}
|
||||
count := 0
|
||||
endpoints, exists, err := client.GetEndpoints(ingress.Namespace, pa.Backend.ServiceName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get endpoints %s/%s: %v", ingress.Namespace, pa.Backend.ServiceName, err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("endpoints not found for %s/%s", ingress.Namespace, pa.Backend.ServiceName)
|
||||
}
|
||||
|
||||
for _, subset := range endpoints.Subsets {
|
||||
count += len(subset.Addresses)
|
||||
}
|
||||
|
||||
serviceInstanceCounts[ingressService{
|
||||
host: rule.Host,
|
||||
path: pa.Path,
|
||||
service: pa.Backend.ServiceName,
|
||||
}] += count
|
||||
}
|
||||
}
|
||||
|
||||
return serviceInstanceCounts, nil
|
||||
}
|
@ -1,477 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
pv1 := newPercentageValueFromFloat64(0.5)
|
||||
pv2 := newPercentageValueFromFloat64(0.2)
|
||||
pv3 := newPercentageValueFromFloat64(0.3)
|
||||
f := fractionalWeightAllocator(
|
||||
map[ingressService]int{
|
||||
{
|
||||
host: "host2",
|
||||
path: "path2",
|
||||
service: "service2",
|
||||
}: int(pv2),
|
||||
{
|
||||
host: "host3",
|
||||
path: "path3",
|
||||
service: "service3",
|
||||
}: int(pv3),
|
||||
{
|
||||
host: "host1",
|
||||
path: "path1",
|
||||
service: "service1",
|
||||
}: int(pv1),
|
||||
},
|
||||
)
|
||||
|
||||
expected := fmt.Sprintf("[service1: %s service2: %s service3: %s]", pv1, pv2, pv3)
|
||||
actual := f.String()
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestGetServicesPercentageWeights(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
annotationValue string
|
||||
expectError bool
|
||||
expectedWeights map[string]percentageValue
|
||||
}{
|
||||
{
|
||||
desc: "empty annotation",
|
||||
annotationValue: ``,
|
||||
expectedWeights: map[string]percentageValue{},
|
||||
},
|
||||
{
|
||||
desc: "50% fraction",
|
||||
annotationValue: `
|
||||
service1: 10%
|
||||
service2: 20%
|
||||
service3: 20%
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(0.1),
|
||||
"service2": newPercentageValueFromFloat64(0.2),
|
||||
"service3": newPercentageValueFromFloat64(0.2),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "50% fraction with empty fraction",
|
||||
annotationValue: `
|
||||
service1: 10%
|
||||
service2: 20%
|
||||
service3: 20%
|
||||
service4:
|
||||
`,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
desc: "50% fraction float form",
|
||||
annotationValue: `
|
||||
service1: 0.1
|
||||
service2: 0.2
|
||||
service3: 0.2
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(0.001),
|
||||
"service2": newPercentageValueFromFloat64(0.002),
|
||||
"service3": newPercentageValueFromFloat64(0.002),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no fraction",
|
||||
annotationValue: `
|
||||
service1: 10%
|
||||
service2: 90%
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(0.1),
|
||||
"service2": newPercentageValueFromFloat64(0.9),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "extra weight specification",
|
||||
annotationValue: `
|
||||
service1: 90%
|
||||
service5: 90%
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(0.9),
|
||||
"service5": newPercentageValueFromFloat64(0.9),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "malformed annotation",
|
||||
annotationValue: `
|
||||
service1- 90%
|
||||
service5- 90%
|
||||
`,
|
||||
expectError: true,
|
||||
expectedWeights: nil,
|
||||
},
|
||||
{
|
||||
desc: "more than one hundred percentaged service",
|
||||
annotationValue: `
|
||||
service1: 100%
|
||||
service2: 1%
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(1),
|
||||
"service2": newPercentageValueFromFloat64(0.01),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "incorrect percentage value",
|
||||
annotationValue: `
|
||||
service1: 1000%
|
||||
`,
|
||||
expectedWeights: map[string]percentageValue{
|
||||
"service1": newPercentageValueFromFloat64(10),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ingress := &extensionsv1beta1.Ingress{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
annotationKubernetesServiceWeights: test.annotationValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
weights, err := getServicesPercentageWeights(ingress)
|
||||
|
||||
if test.expectError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expectedWeights, weights)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeServiceWeights(t *testing.T) {
|
||||
client := clientMock{
|
||||
services: []*corev1.Service{
|
||||
buildService(
|
||||
sName("service1"),
|
||||
sNamespace("testing"),
|
||||
),
|
||||
buildService(
|
||||
sName("service2"),
|
||||
sNamespace("testing"),
|
||||
),
|
||||
buildService(
|
||||
sName("service3"),
|
||||
sNamespace("testing"),
|
||||
),
|
||||
buildService(
|
||||
sName("service4"),
|
||||
sNamespace("testing"),
|
||||
),
|
||||
},
|
||||
endpoints: []*corev1.Endpoints{
|
||||
buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service1"),
|
||||
eUID("1"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.10.0.1")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
subset(
|
||||
eAddresses(eAddress("10.21.0.2")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
),
|
||||
buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service2"),
|
||||
eUID("2"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.10.0.3")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
),
|
||||
buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service3"),
|
||||
eUID("3"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.10.0.4")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
subset(
|
||||
eAddresses(eAddress("10.21.0.5")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
subset(
|
||||
eAddresses(eAddress("10.21.0.6")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
subset(
|
||||
eAddresses(eAddress("10.21.0.7")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
),
|
||||
buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service4"),
|
||||
eUID("4"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.10.0.7")),
|
||||
ePorts(ePort(8080, ""))),
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ingress *extensionsv1beta1.Ingress
|
||||
expectError bool
|
||||
expectedWeights map[ingressService]percentageValue
|
||||
}{
|
||||
{
|
||||
desc: "1 path 2 service",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 10%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service2", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: false,
|
||||
expectedWeights: map[ingressService]percentageValue{
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.05),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(0.90),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "2 path 2 service",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 60%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service2", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("service3", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: false,
|
||||
expectedWeights: map[ingressService]percentageValue{
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.30),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(0.40),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/bar",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.30),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/bar",
|
||||
service: "service3",
|
||||
}: newPercentageValueFromFloat64(0.10),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "2 path 3 service",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 20%
|
||||
service3: 20%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service2", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("service2", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("service3", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: false,
|
||||
expectedWeights: map[ingressService]percentageValue{
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.10),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(0.80),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/bar",
|
||||
service: "service3",
|
||||
}: newPercentageValueFromFloat64(0.05),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/bar",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(0.80),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "1 path 4 service",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 20%
|
||||
service2: 40%
|
||||
service3: 40%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service2", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service3", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service4", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: false,
|
||||
expectedWeights: map[ingressService]percentageValue{
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.10),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(0.40),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service3",
|
||||
}: newPercentageValueFromFloat64(0.10),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service4",
|
||||
}: newPercentageValueFromFloat64(0.00),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "2 path no service",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 20%
|
||||
service2: 40%
|
||||
service3: 40%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("noservice", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("noservice", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
desc: "2 path without weight",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, ``),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/bar"), iBackend("service2", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: false,
|
||||
expectedWeights: map[ingressService]percentageValue{
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/foo",
|
||||
service: "service1",
|
||||
}: newPercentageValueFromFloat64(0.50),
|
||||
{
|
||||
host: "foo.test",
|
||||
path: "/bar",
|
||||
service: "service2",
|
||||
}: newPercentageValueFromFloat64(1.00),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "2 path overflow",
|
||||
ingress: buildIngress(
|
||||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesServiceWeights, `
|
||||
service1: 70%
|
||||
service2: 80%
|
||||
`),
|
||||
iRules(
|
||||
iRule(iHost("foo.test"), iPaths(
|
||||
onePath(iPath("/foo"), iBackend("service1", intstr.FromInt(8080))),
|
||||
onePath(iPath("/foo"), iBackend("service2", intstr.FromInt(8080))),
|
||||
)),
|
||||
),
|
||||
),
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
weightAllocator, err := newFractionalWeightAllocator(test.ingress, client)
|
||||
if test.expectError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("%v failed: %v", test.desc, err)
|
||||
} else {
|
||||
for ingSvc, percentage := range test.expectedWeights {
|
||||
assert.Equal(t, int(percentage), weightAllocator.getWeight(ingSvc.host, ingSvc.path, ingSvc.service))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -41,6 +41,10 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
|
||||
p.quietAddProvider(conf.Kubernetes)
|
||||
}
|
||||
|
||||
if conf.KubernetesCRD != nil {
|
||||
p.quietAddProvider(conf.KubernetesCRD)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -1,158 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildEndpoint(opts ...func(*corev1.Endpoints)) *corev1.Endpoints {
|
||||
e := &corev1.Endpoints{}
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func eNamespace(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func eName(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func eUID(value types.UID) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func subset(opts ...func(*corev1.EndpointSubset)) func(*corev1.Endpoints) {
|
||||
return func(e *corev1.Endpoints) {
|
||||
s := &corev1.EndpointSubset{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
e.Subsets = append(e.Subsets, *s)
|
||||
}
|
||||
}
|
||||
|
||||
func eAddresses(opts ...func(*corev1.EndpointAddress)) func(*corev1.EndpointSubset) {
|
||||
return func(subset *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
a := &corev1.EndpointAddress{}
|
||||
opt(a)
|
||||
subset.Addresses = append(subset.Addresses, *a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func eAddress(ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func eAddressWithTargetRef(targetRef, ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.TargetRef = &corev1.ObjectReference{Name: targetRef}
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func ePorts(opts ...func(port *corev1.EndpointPort)) func(*corev1.EndpointSubset) {
|
||||
return func(spec *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.EndpointPort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ePort(port int32, name string) func(*corev1.EndpointPort) {
|
||||
return func(sp *corev1.EndpointPort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildEndpoint(t *testing.T) {
|
||||
actual := buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service3"),
|
||||
eUID("3"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.1")),
|
||||
ePorts(
|
||||
ePort(8080, "http"),
|
||||
ePort(8443, "https"),
|
||||
),
|
||||
),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.2")),
|
||||
ePorts(
|
||||
ePort(9080, "http"),
|
||||
ePort(9443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleEndpoint1(), actual)
|
||||
}
|
||||
|
||||
func sampleEndpoint1() *corev1.Endpoints {
|
||||
return &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.1",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.2",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 9080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 9443,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress(opts ...func(*extensionsv1beta1.Ingress)) *extensionsv1beta1.Ingress {
|
||||
i := &extensionsv1beta1.Ingress{}
|
||||
for _, opt := range opts {
|
||||
opt(i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func iNamespace(value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func iAnnotation(name string, value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
if i.Annotations == nil {
|
||||
i.Annotations = make(map[string]string)
|
||||
}
|
||||
i.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func iRules(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackends(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackend(opts ...func(*extensionsv1beta1.IngressBackend)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(s *extensionsv1beta1.IngressSpec) {
|
||||
p := &extensionsv1beta1.IngressBackend{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
s.Backend = p
|
||||
}
|
||||
}
|
||||
|
||||
func iIngressBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.IngressBackend) {
|
||||
return func(p *extensionsv1beta1.IngressBackend) {
|
||||
p.ServiceName = name
|
||||
p.ServicePort = port
|
||||
}
|
||||
}
|
||||
|
||||
func iRule(opts ...func(*extensionsv1beta1.IngressRule)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(spec *extensionsv1beta1.IngressSpec) {
|
||||
r := &extensionsv1beta1.IngressRule{}
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
spec.Rules = append(spec.Rules, *r)
|
||||
}
|
||||
}
|
||||
|
||||
func iHost(name string) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.Host = name
|
||||
}
|
||||
}
|
||||
|
||||
func iPaths(opts ...func(*extensionsv1beta1.HTTPIngressRuleValue)) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.HTTP = &extensionsv1beta1.HTTPIngressRuleValue{}
|
||||
for _, opt := range opts {
|
||||
opt(rule.HTTP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func onePath(opts ...func(*extensionsv1beta1.HTTPIngressPath)) func(*extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
return func(irv *extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
p := &extensionsv1beta1.HTTPIngressPath{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
irv.Paths = append(irv.Paths, *p)
|
||||
}
|
||||
}
|
||||
|
||||
func iPath(name string) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Path = name
|
||||
}
|
||||
}
|
||||
|
||||
func iBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Backend = extensionsv1beta1.IngressBackend{
|
||||
ServiceName: name,
|
||||
ServicePort: port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLSes(opts ...func(*extensionsv1beta1.IngressTLS)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
for _, opt := range opts {
|
||||
iTLS := extensionsv1beta1.IngressTLS{}
|
||||
opt(&iTLS)
|
||||
i.Spec.TLS = append(i.Spec.TLS, iTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLS(secret string, hosts ...string) func(*extensionsv1beta1.IngressTLS) {
|
||||
return func(i *extensionsv1beta1.IngressTLS) {
|
||||
i.SecretName = secret
|
||||
i.Hosts = hosts
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildIngress(t *testing.T) {
|
||||
i := buildIngress(
|
||||
iNamespace("testing"),
|
||||
iRules(
|
||||
iRule(iHost("foo"), iPaths(
|
||||
onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))),
|
||||
onePath(iPath("/namedthing"), iBackend("service4", intstr.FromString("https")))),
|
||||
),
|
||||
iRule(iHost("bar"), iPaths(
|
||||
onePath(iBackend("service3", intstr.FromString("https"))),
|
||||
onePath(iBackend("service2", intstr.FromInt(802))),
|
||||
),
|
||||
),
|
||||
),
|
||||
iTLSes(
|
||||
iTLS("tls-secret", "foo"),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleIngress(), i)
|
||||
}
|
||||
|
||||
func sampleIngress() *extensionsv1beta1.Ingress {
|
||||
return &extensionsv1beta1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: extensionsv1beta1.IngressSpec{
|
||||
Rules: []extensionsv1beta1.IngressRule{
|
||||
{
|
||||
Host: "foo",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Path: "/bar",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service1",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/namedthing",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service4",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Host: "bar",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service3",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service2",
|
||||
ServicePort: intstr.FromInt(802),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: []extensionsv1beta1.IngressTLS{
|
||||
{
|
||||
Hosts: []string{"foo"},
|
||||
SecretName: "tls-secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildService(opts ...func(*corev1.Service)) *corev1.Service {
|
||||
s := &corev1.Service{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sNamespace(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func sName(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func sUID(value types.UID) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func sAnnotation(name string, value string) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
if s.Annotations == nil {
|
||||
s.Annotations = make(map[string]string)
|
||||
}
|
||||
s.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func sSpec(opts ...func(*corev1.ServiceSpec)) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
spec := &corev1.ServiceSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(spec)
|
||||
}
|
||||
s.Spec = *spec
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerStatus(opts ...func(*corev1.LoadBalancerStatus)) func(service *corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
loadBalancer := &corev1.LoadBalancerStatus{}
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(loadBalancer)
|
||||
}
|
||||
}
|
||||
s.Status = corev1.ServiceStatus{
|
||||
LoadBalancer: *loadBalancer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerIngress(ip string, hostname string) func(*corev1.LoadBalancerStatus) {
|
||||
return func(status *corev1.LoadBalancerStatus) {
|
||||
ingress := corev1.LoadBalancerIngress{
|
||||
IP: ip,
|
||||
Hostname: hostname,
|
||||
}
|
||||
status.Ingress = append(status.Ingress, ingress)
|
||||
}
|
||||
}
|
||||
|
||||
func clusterIP(ip string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ClusterIP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func sType(value corev1.ServiceType) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.Type = value
|
||||
}
|
||||
}
|
||||
|
||||
func sExternalName(name string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ExternalName = name
|
||||
}
|
||||
}
|
||||
|
||||
func sPorts(opts ...func(*corev1.ServicePort)) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.ServicePort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sPort(port int32, name string) func(*corev1.ServicePort) {
|
||||
return func(sp *corev1.ServicePort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildService(t *testing.T) {
|
||||
actual1 := buildService(
|
||||
sName("service1"),
|
||||
sNamespace("testing"),
|
||||
sUID("1"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.1"),
|
||||
sPorts(sPort(80, "")),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService1(), actual1)
|
||||
|
||||
actual2 := buildService(
|
||||
sName("service2"),
|
||||
sNamespace("testing"),
|
||||
sUID("2"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.2"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(80, "http"),
|
||||
sPort(443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService2(), actual2)
|
||||
|
||||
actual3 := buildService(
|
||||
sName("service3"),
|
||||
sNamespace("testing"),
|
||||
sUID("3"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.3"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(8080, "http"),
|
||||
sPort(8443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService3(), actual3)
|
||||
}
|
||||
|
||||
func sampleService1() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service1",
|
||||
UID: "1",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService2() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service2",
|
||||
UID: "2",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.2",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 80,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService3() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.3",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package kubernetes
|
||||
package crd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -7,6 +7,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/old/log"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
kubeerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -16,6 +20,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
const resyncPeriod = 10 * time.Minute
|
||||
@ -40,7 +45,11 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
|
||||
// WatchAll starts the watch of the Provider resources and updates the stores.
|
||||
// The stores can then be accessed via the Get* functions.
|
||||
type Client interface {
|
||||
WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
|
||||
GetIngressRoutes() []*v1alpha1.IngressRoute
|
||||
GetMiddlewares() []*v1alpha1.Middleware
|
||||
|
||||
GetIngresses() []*extensionsv1beta1.Ingress
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
@ -48,24 +57,46 @@ type Client interface {
|
||||
UpdateIngressStatus(namespace, name, ip, hostname string) error
|
||||
}
|
||||
|
||||
type clientImpl struct {
|
||||
clientset *kubernetes.Clientset
|
||||
factories map[string]informers.SharedInformerFactory
|
||||
// TODO: add tests for the clientWrapper (and its methods) itself.
|
||||
type clientWrapper struct {
|
||||
csCrd *versioned.Clientset
|
||||
csKube *kubernetes.Clientset
|
||||
|
||||
factoriesCrd map[string]externalversions.SharedInformerFactory
|
||||
factoriesKube map[string]informers.SharedInformerFactory
|
||||
|
||||
ingressLabelSelector labels.Selector
|
||||
isNamespaceAll bool
|
||||
watchedNamespaces Namespaces
|
||||
|
||||
isNamespaceAll bool
|
||||
watchedNamespaces k8s.Namespaces
|
||||
}
|
||||
|
||||
func newClientImpl(clientset *kubernetes.Clientset) *clientImpl {
|
||||
return &clientImpl{
|
||||
clientset: clientset,
|
||||
factories: make(map[string]informers.SharedInformerFactory),
|
||||
func createClientFromConfig(c *rest.Config) (*clientWrapper, error) {
|
||||
csCrd, err := versioned.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
csKube, err := kubernetes.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newClientImpl(csKube, csCrd), nil
|
||||
}
|
||||
|
||||
func newClientImpl(csKube *kubernetes.Clientset, csCrd *versioned.Clientset) *clientWrapper {
|
||||
return &clientWrapper{
|
||||
csCrd: csCrd,
|
||||
csKube: csKube,
|
||||
factoriesCrd: make(map[string]externalversions.SharedInformerFactory),
|
||||
factoriesKube: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
}
|
||||
|
||||
// newInClusterClient returns a new Provider client that is expected to run
|
||||
// inside the cluster.
|
||||
func newInClusterClient(endpoint string) (*clientImpl, error) {
|
||||
func newInClusterClient(endpoint string) (*clientWrapper, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create in-cluster configuration: %s", err)
|
||||
@ -78,10 +109,18 @@ func newInClusterClient(endpoint string) (*clientImpl, error) {
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||
configFromFlags, err := clientcmd.BuildConfigFromFlags("", file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return createClientFromConfig(configFromFlags)
|
||||
}
|
||||
|
||||
// newExternalClusterClient returns a new Provider client that may run outside
|
||||
// of the cluster.
|
||||
// The endpoint parameter must not be empty.
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl, error) {
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("endpoint missing for external cluster client")
|
||||
}
|
||||
@ -103,41 +142,44 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl,
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func createClientFromConfig(c *rest.Config) (*clientImpl, error) {
|
||||
clientset, err := kubernetes.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newClientImpl(clientset), nil
|
||||
}
|
||||
|
||||
// WatchAll starts namespace-specific controllers for all relevant kinds.
|
||||
func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c *clientWrapper) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
eventCh := make(chan interface{}, 1)
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
|
||||
if len(namespaces) == 0 {
|
||||
namespaces = Namespaces{metav1.NamespaceAll}
|
||||
namespaces = k8s.Namespaces{metav1.NamespaceAll}
|
||||
c.isNamespaceAll = true
|
||||
}
|
||||
|
||||
c.watchedNamespaces = namespaces
|
||||
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
for _, ns := range namespaces {
|
||||
factory := informers.NewFilteredSharedInformerFactory(c.clientset, resyncPeriod, ns, nil)
|
||||
factory.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
factory.Core().V1().Services().Informer().AddEventHandler(eventHandler)
|
||||
factory.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
c.factories[ns] = factory
|
||||
factoryCrd := externalversions.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, externalversions.WithNamespace(ns))
|
||||
factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler)
|
||||
factoryCrd.Traefik().V1alpha1().Middlewares().Informer().AddEventHandler(eventHandler)
|
||||
|
||||
factoryKube := informers.NewFilteredSharedInformerFactory(c.csKube, resyncPeriod, ns, nil)
|
||||
factoryKube.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
|
||||
factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
|
||||
c.factoriesCrd[ns] = factoryCrd
|
||||
c.factoriesKube[ns] = factoryKube
|
||||
}
|
||||
|
||||
for _, ns := range namespaces {
|
||||
c.factories[ns].Start(stopCh)
|
||||
c.factoriesCrd[ns].Start(stopCh)
|
||||
c.factoriesKube[ns].Start(stopCh)
|
||||
}
|
||||
|
||||
for _, ns := range namespaces {
|
||||
for t, ok := range c.factories[ns].WaitForCacheSync(stopCh) {
|
||||
for t, ok := range c.factoriesCrd[ns].WaitForCacheSync(stopCh) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s in namespace %q", t.String(), ns)
|
||||
}
|
||||
}
|
||||
|
||||
for t, ok := range c.factoriesKube[ns].WaitForCacheSync(stopCh) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s in namespace %q", t.String(), ns)
|
||||
}
|
||||
@ -149,17 +191,45 @@ func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-
|
||||
// https://github.com/containous/traefik/issues/1784 should improve the
|
||||
// situation here in the future.
|
||||
for _, ns := range namespaces {
|
||||
c.factories[ns].Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
|
||||
c.factories[ns].Start(stopCh)
|
||||
c.factoriesKube[ns].Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
|
||||
c.factoriesKube[ns].Start(stopCh)
|
||||
}
|
||||
|
||||
return eventCh, nil
|
||||
}
|
||||
|
||||
func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute {
|
||||
var result []*v1alpha1.IngressRoute
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
||||
var result []*v1alpha1.Middleware
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetIngresses returns all Ingresses for observed namespaces in the cluster.
|
||||
func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
var result []*extensionsv1beta1.Ingress
|
||||
for ns, factory := range c.factories {
|
||||
for ns, factory := range c.factoriesKube {
|
||||
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
@ -170,12 +240,12 @@ func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
}
|
||||
|
||||
// UpdateIngressStatus updates an Ingress with a provided status.
|
||||
func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
func (c *clientWrapper) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
ing, err := c.factories[c.lookupNamespace(namespace)].Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).Get(name)
|
||||
ing, err := c.factoriesKube[c.lookupNamespace(namespace)].Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).Get(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: %v", namespace, name, err)
|
||||
}
|
||||
@ -190,7 +260,7 @@ func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) e
|
||||
ingCopy := ing.DeepCopy()
|
||||
ingCopy.Status = extensionsv1beta1.IngressStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: []corev1.LoadBalancerIngress{{IP: ip, Hostname: hostname}}}}
|
||||
|
||||
_, err = c.clientset.ExtensionsV1beta1().Ingresses(ingCopy.Namespace).UpdateStatus(ingCopy)
|
||||
_, err = c.csKube.ExtensionsV1beta1().Ingresses(ingCopy.Namespace).UpdateStatus(ingCopy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update ingress status %s/%s: %v", namespace, name, err)
|
||||
}
|
||||
@ -199,34 +269,34 @@ func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) e
|
||||
}
|
||||
|
||||
// GetService returns the named service from the given namespace.
|
||||
func (c *clientImpl) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get service %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
service, err := c.factories[c.lookupNamespace(namespace)].Core().V1().Services().Lister().Services(namespace).Get(name)
|
||||
service, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Services().Lister().Services(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return service, exist, err
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientImpl) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
endpoint, err := c.factories[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
endpoint, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return endpoint, exist, err
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get secret %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
secret, err := c.factories[c.lookupNamespace(namespace)].Core().V1().Secrets().Lister().Secrets(namespace).Get(name)
|
||||
secret, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Secrets().Lister().Secrets(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return secret, exist, err
|
||||
}
|
||||
@ -237,14 +307,14 @@ func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, er
|
||||
// The distinction is necessary because we index all informers on the special
|
||||
// identifier iff all-namespaces are requested but receive specific namespace
|
||||
// identifiers from the Kubernetes API, so we have to bridge this gap.
|
||||
func (c *clientImpl) lookupNamespace(ns string) string {
|
||||
func (c *clientWrapper) lookupNamespace(ns string) string {
|
||||
if c.isNamespaceAll {
|
||||
return metav1.NamespaceAll
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (c *clientImpl) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
return &cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
// Ignore Ingresses that do not match our custom label selector.
|
||||
@ -278,8 +348,8 @@ func translateNotFoundError(err error) (bool, error) {
|
||||
}
|
||||
|
||||
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
|
||||
// it to ensure we don't panic by requesting an out-of-watch object
|
||||
func (c *clientImpl) isWatchedNamespace(ns string) bool {
|
||||
// it to ensure we don't panic by requesting an out-of-watch object.
|
||||
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
|
||||
if c.isNamespaceAll {
|
||||
return true
|
||||
}
|
@ -1,21 +1,83 @@
|
||||
package kubernetes
|
||||
package crd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
v1beta12 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var _ Client = (*clientMock)(nil)
|
||||
|
||||
func init() {
|
||||
// required by k8s.MustParseYaml
|
||||
err := v1alpha1.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type clientMock struct {
|
||||
ingresses []*extensionsv1beta1.Ingress
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
watchChan chan interface{}
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
apiIngressStatusError error
|
||||
|
||||
ingressRoutes []*v1alpha1.IngressRoute
|
||||
middlewares []*v1alpha1.Middleware
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
||||
func newClientMock(paths ...string) clientMock {
|
||||
var c clientMock
|
||||
|
||||
for _, path := range paths {
|
||||
yamlContent, err := ioutil.ReadFile("./fixtures/" + path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sObjects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service:
|
||||
c.services = append(c.services, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *v1alpha1.IngressRoute:
|
||||
c.ingressRoutes = append(c.ingressRoutes, o)
|
||||
case *v1alpha1.Middleware:
|
||||
c.middlewares = append(c.middlewares, o)
|
||||
case *v1beta12.Ingress:
|
||||
c.ingresses = append(c.ingresses, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngressRoutes() []*v1alpha1.IngressRoute {
|
||||
return c.ingressRoutes
|
||||
}
|
||||
|
||||
func (c clientMock) GetMiddlewares() []*v1alpha1.Middleware {
|
||||
return c.middlewares
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
@ -62,7 +124,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c clientMock) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
return c.watchChan, nil
|
||||
}
|
||||
|
88
provider/kubernetes/crd/fixtures/services.yml
Normal file
88
provider/kubernetes/crd/fixtures/services.yml
Normal file
@ -0,0 +1,88 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami2
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoami2
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamitls
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web-secure
|
||||
port: 443
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoamitls
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: web-secure
|
||||
port: 443
|
17
provider/kubernetes/crd/fixtures/simple.yml
Normal file
17
provider/kubernetes/crd/fixtures/simple.yml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
17
provider/kubernetes/crd/fixtures/with_bad_host_rule.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_bad_host_rule.yml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com"0"`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
17
provider/kubernetes/crd/fixtures/with_https_default.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_https_default.yml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoamitls
|
||||
port: 443
|
44
provider/kubernetes/crd/fixtures/with_middleware.yml
Normal file
44
provider/kubernetes/crd/fixtures/with_middleware.yml
Normal file
@ -0,0 +1,44 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: stripprefix
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /tobestripped
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: addprefix
|
||||
namespace: foo
|
||||
|
||||
spec:
|
||||
addPrefix:
|
||||
prefix: /tobeadded
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test2.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/tobestripped`)
|
||||
priority: 12
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
- name: addprefix
|
||||
namespace: foo
|
17
provider/kubernetes/crd/fixtures/with_no_rule_value.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_no_rule_value.yml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: ""
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
31
provider/kubernetes/crd/fixtures/with_tls.yml
Normal file
31
provider/kubernetes/crd/fixtures/with_tls.yml
Normal file
@ -0,0 +1,31 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
secretName: supersecret
|
23
provider/kubernetes/crd/fixtures/with_two_rules.yml
Normal file
23
provider/kubernetes/crd/fixtures/with_two_rules.yml
Normal file
@ -0,0 +1,23 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 14
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
20
provider/kubernetes/crd/fixtures/with_two_services.yml
Normal file
20
provider/kubernetes/crd/fixtures/with_two_services.yml
Normal file
@ -0,0 +1,20 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
|
16
provider/kubernetes/crd/fixtures/with_wrong_rule_kind.yml
Normal file
16
provider/kubernetes/crd/fixtures/with_wrong_rule_kind.yml
Normal file
@ -0,0 +1,16 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: /prefix
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface
|
||||
// Deprecated: please explicitly pick a version if possible.
|
||||
Traefik() traefikv1alpha1.TraefikV1alpha1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
// version included in a Clientset.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
traefikV1alpha1 *traefikv1alpha1.TraefikV1alpha1Client
|
||||
}
|
||||
|
||||
// TraefikV1alpha1 retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return c.traefikV1alpha1
|
||||
}
|
||||
|
||||
// Deprecated: Traefik retrieves the default version of TraefikClient.
|
||||
// Please explicitly pick a version.
|
||||
func (c *Clientset) Traefik() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return c.traefikV1alpha1
|
||||
}
|
||||
|
||||
// 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.traefikV1alpha1, err = traefikv1alpha1.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.traefikV1alpha1 = traefikv1alpha1.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.traefikV1alpha1 = traefikv1alpha1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
28
provider/kubernetes/crd/generated/clientset/versioned/doc.go
Normal file
28
provider/kubernetes/crd/generated/clientset/versioned/doc.go
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated clientset.
|
||||
package versioned
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
clientset "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
faketraefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1/fake"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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{}
|
||||
|
||||
// TraefikV1alpha1 retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return &faketraefikv1alpha1.FakeTraefikV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// Traefik retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) Traefik() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return &faketraefikv1alpha1.FakeTraefikV1alpha1{Fake: &c.Fake}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated fake clientset.
|
||||
package fake
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(scheme)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
traefikv1alpha1.AddToScheme(scheme)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package contains the scheme of the automatically generated clientset.
|
||||
package scheme
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(Scheme)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
traefikv1alpha1.AddToScheme(scheme)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha1
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// FakeIngressRoutes implements IngressRouteInterface
|
||||
type FakeIngressRoutes struct {
|
||||
Fake *FakeTraefikV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var ingressroutesResource = schema.GroupVersionResource{Group: "traefik.containo.us", Version: "v1alpha1", Resource: "ingressroutes"}
|
||||
|
||||
var ingressroutesKind = schema.GroupVersionKind{Group: "traefik.containo.us", Version: "v1alpha1", Kind: "IngressRoute"}
|
||||
|
||||
// Get takes name of the ingressRoute, and returns the corresponding ingressRoute object, and an error if there is any.
|
||||
func (c *FakeIngressRoutes) Get(name string, options v1.GetOptions) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(ingressroutesResource, c.ns, name), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of IngressRoutes that match those selectors.
|
||||
func (c *FakeIngressRoutes) List(opts v1.ListOptions) (result *v1alpha1.IngressRouteList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(ingressroutesResource, ingressroutesKind, c.ns, opts), &v1alpha1.IngressRouteList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.IngressRouteList{ListMeta: obj.(*v1alpha1.IngressRouteList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.IngressRouteList).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 ingressRoutes.
|
||||
func (c *FakeIngressRoutes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(ingressroutesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a ingressRoute and creates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *FakeIngressRoutes) Create(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(ingressroutesResource, c.ns, ingressRoute), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a ingressRoute and updates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *FakeIngressRoutes) Update(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(ingressroutesResource, c.ns, ingressRoute), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// Delete takes name of the ingressRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeIngressRoutes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(ingressroutesResource, c.ns, name), &v1alpha1.IngressRoute{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeIngressRoutes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(ingressroutesResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.IngressRouteList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched ingressRoute.
|
||||
func (c *FakeIngressRoutes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(ingressroutesResource, c.ns, name, data, subresources...), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// FakeMiddlewares implements MiddlewareInterface
|
||||
type FakeMiddlewares struct {
|
||||
Fake *FakeTraefikV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var middlewaresResource = schema.GroupVersionResource{Group: "traefik.containo.us", Version: "v1alpha1", Resource: "middlewares"}
|
||||
|
||||
var middlewaresKind = schema.GroupVersionKind{Group: "traefik.containo.us", Version: "v1alpha1", Kind: "Middleware"}
|
||||
|
||||
// Get takes name of the middleware, and returns the corresponding middleware object, and an error if there is any.
|
||||
func (c *FakeMiddlewares) Get(name string, options v1.GetOptions) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(middlewaresResource, c.ns, name), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Middlewares that match those selectors.
|
||||
func (c *FakeMiddlewares) List(opts v1.ListOptions) (result *v1alpha1.MiddlewareList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(middlewaresResource, middlewaresKind, c.ns, opts), &v1alpha1.MiddlewareList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.MiddlewareList{ListMeta: obj.(*v1alpha1.MiddlewareList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.MiddlewareList).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 middlewares.
|
||||
func (c *FakeMiddlewares) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(middlewaresResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a middleware and creates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *FakeMiddlewares) Create(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(middlewaresResource, c.ns, middleware), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a middleware and updates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *FakeMiddlewares) Update(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(middlewaresResource, c.ns, middleware), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// Delete takes name of the middleware and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeMiddlewares) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(middlewaresResource, c.ns, name), &v1alpha1.Middleware{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeMiddlewares) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(middlewaresResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.MiddlewareList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched middleware.
|
||||
func (c *FakeMiddlewares) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(middlewaresResource, c.ns, name, data, subresources...), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeTraefikV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeTraefikV1alpha1) IngressRoutes(namespace string) v1alpha1.IngressRouteInterface {
|
||||
return &FakeIngressRoutes{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeTraefikV1alpha1) Middlewares(namespace string) v1alpha1.MiddlewareInterface {
|
||||
return &FakeMiddlewares{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeTraefikV1alpha1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type IngressRouteExpansion interface{}
|
||||
|
||||
type MiddlewareExpansion interface{}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
scheme "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// IngressRoutesGetter has a method to return a IngressRouteInterface.
|
||||
// A group's client should implement this interface.
|
||||
type IngressRoutesGetter interface {
|
||||
IngressRoutes(namespace string) IngressRouteInterface
|
||||
}
|
||||
|
||||
// IngressRouteInterface has methods to work with IngressRoute resources.
|
||||
type IngressRouteInterface interface {
|
||||
Create(*v1alpha1.IngressRoute) (*v1alpha1.IngressRoute, error)
|
||||
Update(*v1alpha1.IngressRoute) (*v1alpha1.IngressRoute, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.IngressRoute, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.IngressRouteList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error)
|
||||
IngressRouteExpansion
|
||||
}
|
||||
|
||||
// ingressRoutes implements IngressRouteInterface
|
||||
type ingressRoutes struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newIngressRoutes returns a IngressRoutes
|
||||
func newIngressRoutes(c *TraefikV1alpha1Client, namespace string) *ingressRoutes {
|
||||
return &ingressRoutes{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the ingressRoute, and returns the corresponding ingressRoute object, and an error if there is any.
|
||||
func (c *ingressRoutes) Get(name string, options v1.GetOptions) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of IngressRoutes that match those selectors.
|
||||
func (c *ingressRoutes) List(opts v1.ListOptions) (result *v1alpha1.IngressRouteList, err error) {
|
||||
result = &v1alpha1.IngressRouteList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested ingressRoutes.
|
||||
func (c *ingressRoutes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a ingressRoute and creates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *ingressRoutes) Create(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Body(ingressRoute).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a ingressRoute and updates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *ingressRoutes) Update(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(ingressRoute.Name).
|
||||
Body(ingressRoute).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the ingressRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *ingressRoutes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *ingressRoutes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched ingressRoute.
|
||||
func (c *ingressRoutes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
scheme "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// MiddlewaresGetter has a method to return a MiddlewareInterface.
|
||||
// A group's client should implement this interface.
|
||||
type MiddlewaresGetter interface {
|
||||
Middlewares(namespace string) MiddlewareInterface
|
||||
}
|
||||
|
||||
// MiddlewareInterface has methods to work with Middleware resources.
|
||||
type MiddlewareInterface interface {
|
||||
Create(*v1alpha1.Middleware) (*v1alpha1.Middleware, error)
|
||||
Update(*v1alpha1.Middleware) (*v1alpha1.Middleware, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.Middleware, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.MiddlewareList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error)
|
||||
MiddlewareExpansion
|
||||
}
|
||||
|
||||
// middlewares implements MiddlewareInterface
|
||||
type middlewares struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newMiddlewares returns a Middlewares
|
||||
func newMiddlewares(c *TraefikV1alpha1Client, namespace string) *middlewares {
|
||||
return &middlewares{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the middleware, and returns the corresponding middleware object, and an error if there is any.
|
||||
func (c *middlewares) Get(name string, options v1.GetOptions) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Middlewares that match those selectors.
|
||||
func (c *middlewares) List(opts v1.ListOptions) (result *v1alpha1.MiddlewareList, err error) {
|
||||
result = &v1alpha1.MiddlewareList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested middlewares.
|
||||
func (c *middlewares) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a middleware and creates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *middlewares) Create(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Body(middleware).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a middleware and updates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *middlewares) Update(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(middleware.Name).
|
||||
Body(middleware).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the middleware and deletes it. Returns an error if one occurs.
|
||||
func (c *middlewares) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *middlewares) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched middleware.
|
||||
func (c *middlewares) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type TraefikV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
IngressRoutesGetter
|
||||
MiddlewaresGetter
|
||||
}
|
||||
|
||||
// TraefikV1alpha1Client is used to interact with features provided by the traefik.containo.us group.
|
||||
type TraefikV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *TraefikV1alpha1Client) IngressRoutes(namespace string) IngressRouteInterface {
|
||||
return newIngressRoutes(c, namespace)
|
||||
}
|
||||
|
||||
func (c *TraefikV1alpha1Client) Middlewares(namespace string) MiddlewareInterface {
|
||||
return newMiddlewares(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new TraefikV1alpha1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*TraefikV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TraefikV1alpha1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new TraefikV1alpha1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *TraefikV1alpha1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new TraefikV1alpha1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *TraefikV1alpha1Client {
|
||||
return &TraefikV1alpha1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1alpha1.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 *TraefikV1alpha1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
traefik "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/traefik"
|
||||
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"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
Traefik() traefik.Interface
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Traefik() traefik.Interface {
|
||||
return traefik.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("ingressroutes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().IngressRoutes().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("middlewares"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().Middlewares().Informer()}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package internalinterfaces
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type TweakListOptionsFunc func(*v1.ListOptions)
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package traefik
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/traefik/v1alpha1"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
type Interface interface {
|
||||
// V1alpha1 provides access to shared informers for resources in V1alpha1.
|
||||
V1alpha1() v1alpha1.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}
|
||||
}
|
||||
|
||||
// V1alpha1 returns a new v1alpha1.Interface.
|
||||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/listers/traefik/v1alpha1"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// IngressRouteInformer provides access to a shared informer and lister for
|
||||
// IngressRoutes.
|
||||
type IngressRouteInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.IngressRouteLister
|
||||
}
|
||||
|
||||
type ingressRouteInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewIngressRouteInformer constructs a new informer for IngressRoute 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 NewIngressRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredIngressRouteInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredIngressRouteInformer constructs a new informer for IngressRoute 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 NewFilteredIngressRouteInformer(client versioned.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.TraefikV1alpha1().IngressRoutes(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().IngressRoutes(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&traefikv1alpha1.IngressRoute{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredIngressRouteInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&traefikv1alpha1.IngressRoute{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) Lister() v1alpha1.IngressRouteLister {
|
||||
return v1alpha1.NewIngressRouteLister(f.Informer().GetIndexer())
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// IngressRoutes returns a IngressRouteInformer.
|
||||
IngressRoutes() IngressRouteInformer
|
||||
// Middlewares returns a MiddlewareInformer.
|
||||
Middlewares() MiddlewareInformer
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
// IngressRoutes returns a IngressRouteInformer.
|
||||
func (v *version) IngressRoutes() IngressRouteInformer {
|
||||
return &ingressRouteInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// Middlewares returns a MiddlewareInformer.
|
||||
func (v *version) Middlewares() MiddlewareInformer {
|
||||
return &middlewareInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/listers/traefik/v1alpha1"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
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"
|
||||
)
|
||||
|
||||
// MiddlewareInformer provides access to a shared informer and lister for
|
||||
// Middlewares.
|
||||
type MiddlewareInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.MiddlewareLister
|
||||
}
|
||||
|
||||
type middlewareInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewMiddlewareInformer constructs a new informer for Middleware 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 NewMiddlewareInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredMiddlewareInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredMiddlewareInformer constructs a new informer for Middleware 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 NewFilteredMiddlewareInformer(client versioned.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.TraefikV1alpha1().Middlewares(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().Middlewares(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&traefikv1alpha1.Middleware{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredMiddlewareInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&traefikv1alpha1.Middleware{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) Lister() v1alpha1.MiddlewareLister {
|
||||
return v1alpha1.NewMiddlewareLister(f.Informer().GetIndexer())
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// IngressRouteListerExpansion allows custom methods to be added to
|
||||
// IngressRouteLister.
|
||||
type IngressRouteListerExpansion interface{}
|
||||
|
||||
// IngressRouteNamespaceListerExpansion allows custom methods to be added to
|
||||
// IngressRouteNamespaceLister.
|
||||
type IngressRouteNamespaceListerExpansion interface{}
|
||||
|
||||
// MiddlewareListerExpansion allows custom methods to be added to
|
||||
// MiddlewareLister.
|
||||
type MiddlewareListerExpansion interface{}
|
||||
|
||||
// MiddlewareNamespaceListerExpansion allows custom methods to be added to
|
||||
// MiddlewareNamespaceLister.
|
||||
type MiddlewareNamespaceListerExpansion interface{}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// IngressRouteLister helps list IngressRoutes.
|
||||
type IngressRouteLister interface {
|
||||
// List lists all IngressRoutes in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error)
|
||||
// IngressRoutes returns an object that can list and get IngressRoutes.
|
||||
IngressRoutes(namespace string) IngressRouteNamespaceLister
|
||||
IngressRouteListerExpansion
|
||||
}
|
||||
|
||||
// ingressRouteLister implements the IngressRouteLister interface.
|
||||
type ingressRouteLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewIngressRouteLister returns a new IngressRouteLister.
|
||||
func NewIngressRouteLister(indexer cache.Indexer) IngressRouteLister {
|
||||
return &ingressRouteLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all IngressRoutes in the indexer.
|
||||
func (s *ingressRouteLister) List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.IngressRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// IngressRoutes returns an object that can list and get IngressRoutes.
|
||||
func (s *ingressRouteLister) IngressRoutes(namespace string) IngressRouteNamespaceLister {
|
||||
return ingressRouteNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// IngressRouteNamespaceLister helps list and get IngressRoutes.
|
||||
type IngressRouteNamespaceLister interface {
|
||||
// List lists all IngressRoutes in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error)
|
||||
// Get retrieves the IngressRoute from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.IngressRoute, error)
|
||||
IngressRouteNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// ingressRouteNamespaceLister implements the IngressRouteNamespaceLister
|
||||
// interface.
|
||||
type ingressRouteNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all IngressRoutes in the indexer for a given namespace.
|
||||
func (s ingressRouteNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.IngressRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the IngressRoute from the indexer for a given namespace and name.
|
||||
func (s ingressRouteNamespaceLister) Get(name string) (*v1alpha1.IngressRoute, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("ingressroute"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), nil
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// MiddlewareLister helps list Middlewares.
|
||||
type MiddlewareLister interface {
|
||||
// List lists all Middlewares in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error)
|
||||
// Middlewares returns an object that can list and get Middlewares.
|
||||
Middlewares(namespace string) MiddlewareNamespaceLister
|
||||
MiddlewareListerExpansion
|
||||
}
|
||||
|
||||
// middlewareLister implements the MiddlewareLister interface.
|
||||
type middlewareLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewMiddlewareLister returns a new MiddlewareLister.
|
||||
func NewMiddlewareLister(indexer cache.Indexer) MiddlewareLister {
|
||||
return &middlewareLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all Middlewares in the indexer.
|
||||
func (s *middlewareLister) List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Middleware))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Middlewares returns an object that can list and get Middlewares.
|
||||
func (s *middlewareLister) Middlewares(namespace string) MiddlewareNamespaceLister {
|
||||
return middlewareNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// MiddlewareNamespaceLister helps list and get Middlewares.
|
||||
type MiddlewareNamespaceLister interface {
|
||||
// List lists all Middlewares in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error)
|
||||
// Get retrieves the Middleware from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.Middleware, error)
|
||||
MiddlewareNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// middlewareNamespaceLister implements the MiddlewareNamespaceLister
|
||||
// interface.
|
||||
type middlewareNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all Middlewares in the indexer for a given namespace.
|
||||
func (s middlewareNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Middleware))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the Middleware from the indexer for a given namespace and name.
|
||||
func (s middlewareNamespaceLister) Get(name string) (*v1alpha1.Middleware, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("middleware"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), nil
|
||||
}
|
458
provider/kubernetes/crd/kubernetes.go
Normal file
458
provider/kubernetes/crd/kubernetes.go
Normal file
@ -0,0 +1,458 @@
|
||||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/job"
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
"github.com/containous/traefik/safe"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationKubernetesIngressClass = "kubernetes.io/ingress.class"
|
||||
traefikDefaultIngressClass = "traefik"
|
||||
)
|
||||
|
||||
// IngressEndpoint holds the endpoint information for the Kubernetes provider.
|
||||
type IngressEndpoint struct {
|
||||
IP string `description:"IP used for Kubernetes Ingress endpoints"`
|
||||
Hostname string `description:"Hostname used for Kubernetes Ingress endpoints"`
|
||||
PublishedService string `description:"Published Kubernetes Service to copy status from"`
|
||||
}
|
||||
|
||||
// Provider holds configurations of the provider.
|
||||
type Provider struct {
|
||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
||||
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
||||
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"` // Deprecated
|
||||
Namespaces k8s.Namespaces `description:"Kubernetes namespaces" export:"true"`
|
||||
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
|
||||
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
||||
IngressEndpoint *IngressEndpoint `description:"Kubernetes Ingress Endpoint"`
|
||||
lastConfiguration safe.Safe
|
||||
}
|
||||
|
||||
func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string) (*clientWrapper, error) {
|
||||
ingLabelSel, err := labels.Parse(ingressLabelSelector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ingress label selector: %q", ingressLabelSelector)
|
||||
}
|
||||
log.FromContext(ctx).Infof("ingress label selector is: %q", ingLabelSel)
|
||||
|
||||
withEndpoint := ""
|
||||
if p.Endpoint != "" {
|
||||
withEndpoint = fmt.Sprintf(" with endpoint %v", p.Endpoint)
|
||||
}
|
||||
|
||||
var client *clientWrapper
|
||||
switch {
|
||||
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
|
||||
log.FromContext(ctx).Infof("Creating in-cluster Provider client%s", withEndpoint)
|
||||
client, err = newInClusterClient(p.Endpoint)
|
||||
case os.Getenv("KUBECONFIG") != "":
|
||||
log.FromContext(ctx).Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
|
||||
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
||||
default:
|
||||
log.FromContext(ctx).Infof("Creating cluster-external Provider client%s", withEndpoint)
|
||||
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
client.ingressLabelSelector = ingLabelSel
|
||||
}
|
||||
|
||||
return client, err
|
||||
}
|
||||
|
||||
// Init the provider.
|
||||
func (p *Provider) Init() error {
|
||||
return p.BaseProvider.Init()
|
||||
}
|
||||
|
||||
// Provide allows the k8s provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.Pool) error {
|
||||
ctxLog := log.With(context.Background(), log.Str(log.ProviderName, "kubernetescrd"))
|
||||
logger := log.FromContext(ctxLog)
|
||||
// Tell glog (used by client-go) to log into STDERR. Otherwise, we risk
|
||||
// certain kinds of API errors getting logged into a directory not
|
||||
// available in a `FROM scratch` Docker container, causing glog to abort
|
||||
// hard with an exit code > 0.
|
||||
err := flag.Set("logtostderr", "true")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debugf("Using Ingress label selector: %q", p.LabelSelector)
|
||||
k8sClient, err := p.newK8sClient(ctxLog, p.LabelSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pool.Go(func(stop chan bool) {
|
||||
operation := func() error {
|
||||
stopWatch := make(chan struct{}, 1)
|
||||
defer close(stopWatch)
|
||||
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
|
||||
if err != nil {
|
||||
logger.Errorf("Error watching kubernetes events: %v", err)
|
||||
timer := time.NewTimer(1 * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
return err
|
||||
case <-stop:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
case event := <-eventsChan:
|
||||
conf := p.loadConfigurationFromIngresses(ctxLog, k8sClient)
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
|
||||
logger.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(conf)
|
||||
configurationChan <- config.Message{
|
||||
ProviderName: "kubernetescrd",
|
||||
Configuration: conf,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notify := func(err error, time time.Duration) {
|
||||
logger.Errorf("Provider connection error: %s; retrying in %s", err, time)
|
||||
}
|
||||
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot connect to Provider: %s", err)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]config.Server, error) {
|
||||
strategy := svc.Strategy
|
||||
if strategy == "" {
|
||||
strategy = "RoundRobin"
|
||||
}
|
||||
if strategy != "RoundRobin" {
|
||||
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
||||
}
|
||||
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec corev1.ServicePort
|
||||
var match bool
|
||||
// TODO: support name ports? do we actually care?
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = p
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []config.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, config.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
Weight: 1,
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
if port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, config.Server{
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
||||
Weight: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Client) *config.Configuration {
|
||||
|
||||
conf := &config.Configuration{
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{},
|
||||
}
|
||||
tlsConfigs := make(map[string]*tls.Configuration)
|
||||
|
||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace)))
|
||||
|
||||
// TODO keep the name ingressClass?
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := getTLS(ctx, ingressRoute, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
|
||||
ingressName := ingressRoute.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRoute.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRoute.Spec.Routes {
|
||||
if route.Kind != "Rule" {
|
||||
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
var allServers []config.Server
|
||||
for _, service := range route.Services {
|
||||
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
allServers = append(allServers, servers...)
|
||||
}
|
||||
|
||||
// TODO: support middlewares from other providers.
|
||||
// Mechanism: in the spec, prefix the name with the provider name,
|
||||
// with dot as the separator. In which case. we ignore the
|
||||
// namespace.
|
||||
|
||||
var mds []string
|
||||
for _, mi := range route.Middlewares {
|
||||
ns := mi.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
mds = append(mds, makeID(ns, mi.Name))
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
_, err = h.Write([]byte(route.Match))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%s-%.10x", ingressName, h.Sum(nil))
|
||||
|
||||
serviceName := makeID(ingressRoute.Namespace, key)
|
||||
|
||||
conf.HTTP.Routers[serviceName] = &config.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
conf.HTTP.Routers[serviceName].TLS = &config.RouterTLSConfig{}
|
||||
}
|
||||
conf.HTTP.Services[serviceName] = &config.Service{
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: allServers,
|
||||
// TODO: support other strategies.
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conf.TLS = getTLSConfig(tlsConfigs)
|
||||
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func makeID(namespace, name string) string {
|
||||
if namespace == "" {
|
||||
return name
|
||||
}
|
||||
return namespace + "/" + name
|
||||
}
|
||||
|
||||
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {
|
||||
return ingressClass == ingressClassAnnotation ||
|
||||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
|
||||
}
|
||||
|
||||
func getTLS(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.Configuration) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section: No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
secret, exists, err := k8sClient.GetSecret(ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch secret %s/%s: %v", ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName, err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("secret %s/%s does not exist", ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
}
|
||||
|
||||
cert, key, err := getCertificateBlocks(secret, ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = &tls.Configuration{
|
||||
Certificate: &tls.Certificate{
|
||||
CertFile: tls.FileOrContent(cert),
|
||||
KeyFile: tls.FileOrContent(key),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTLSConfig(tlsConfigs map[string]*tls.Configuration) []*tls.Configuration {
|
||||
var secretNames []string
|
||||
for secretName := range tlsConfigs {
|
||||
secretNames = append(secretNames, secretName)
|
||||
}
|
||||
sort.Strings(secretNames)
|
||||
|
||||
var configs []*tls.Configuration
|
||||
for _, secretName := range secretNames {
|
||||
configs = append(configs, tlsConfigs[secretName])
|
||||
}
|
||||
|
||||
return configs
|
||||
}
|
||||
|
||||
func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) {
|
||||
var missingEntries []string
|
||||
|
||||
tlsCrtData, tlsCrtExists := secret.Data["tls.crt"]
|
||||
if !tlsCrtExists {
|
||||
missingEntries = append(missingEntries, "tls.crt")
|
||||
}
|
||||
|
||||
tlsKeyData, tlsKeyExists := secret.Data["tls.key"]
|
||||
if !tlsKeyExists {
|
||||
missingEntries = append(missingEntries, "tls.key")
|
||||
}
|
||||
|
||||
if len(missingEntries) > 0 {
|
||||
return "", "", fmt.Errorf("secret %s/%s is missing the following TLS data entries: %s",
|
||||
namespace, secretName, strings.Join(missingEntries, ", "))
|
||||
}
|
||||
|
||||
cert := string(tlsCrtData)
|
||||
if cert == "" {
|
||||
missingEntries = append(missingEntries, "tls.crt")
|
||||
}
|
||||
|
||||
key := string(tlsKeyData)
|
||||
if key == "" {
|
||||
missingEntries = append(missingEntries, "tls.key")
|
||||
}
|
||||
|
||||
if len(missingEntries) > 0 {
|
||||
return "", "", fmt.Errorf("secret %s/%s contains the following empty TLS data entries: %s",
|
||||
namespace, secretName, strings.Join(missingEntries, ", "))
|
||||
}
|
||||
|
||||
return cert, key, nil
|
||||
}
|
368
provider/kubernetes/crd/kubernetes_test.go
Normal file
368
provider/kubernetes/crd/kubernetes_test.go
Normal file
@ -0,0 +1,368 @@
|
||||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func TestLoadIngressRoutes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ingressClass string
|
||||
paths []string
|
||||
expected *config.Configuration
|
||||
}{
|
||||
{
|
||||
desc: "Empty",
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route, with foo entrypoint",
|
||||
paths: []string{"services.yml", "simple.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route with middleware",
|
||||
paths: []string{"services.yml", "with_middleware.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test2.crd-23c7f4c450289ee29016": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test2.crd-23c7f4c450289ee29016",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)",
|
||||
Priority: 12,
|
||||
Middlewares: []string{"default/stripprefix", "foo/addprefix"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{
|
||||
"default/stripprefix": {
|
||||
StripPrefix: &config.StripPrefix{
|
||||
Prefixes: []string{"/tobestripped"},
|
||||
},
|
||||
},
|
||||
"foo/addprefix": {
|
||||
AddPrefix: &config.AddPrefix{
|
||||
Prefix: "/tobeadded",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test2.crd-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different rules",
|
||||
paths: []string{"services.yml", "with_two_rules.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Priority: 14,
|
||||
},
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-77c62dfe9517144aeeaa",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different services, their servers will merge",
|
||||
paths: []string{"services.yml", "with_two_services.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-77c62dfe9517144aeeaa",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Ingress class",
|
||||
paths: []string{"services.yml", "simple.yml"},
|
||||
ingressClass: "tchouk",
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Route with empty rule value is ignored",
|
||||
paths: []string{"services.yml", "with_no_rule_value.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Route with kind not of a rule type (empty kind) is ignored",
|
||||
paths: []string{"services.yml", "with_wrong_rule_kind.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "check rule quoting validity",
|
||||
paths: []string{"services.yml", "with_bad_host_rule.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS",
|
||||
paths: []string{"services.yml", "with_tls.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLS: []*tls.Configuration{
|
||||
{
|
||||
Certificate: &tls.Certificate{
|
||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||
},
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route, defaulting to https for servers",
|
||||
paths: []string{"services.yml", "with_https_default.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "https://10.10.0.5:443",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.6:443",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "port selected by name (TODO)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if test.expected == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), newClientMock(test.paths...))
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
}
|
5
provider/kubernetes/crd/traefik/v1alpha1/doc.go
Normal file
5
provider/kubernetes/crd/traefik/v1alpha1/doc.go
Normal file
@ -0,0 +1,5 @@
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
// Package v1alpha1 is the v1alpha1 version of the API.
|
||||
// +groupName=traefik.containo.us
|
||||
package v1alpha1
|
72
provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go
Normal file
72
provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go
Normal file
@ -0,0 +1,72 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// IngressRouteSpec is a specification for a IngressRouteSpec resource.
|
||||
type IngressRouteSpec struct {
|
||||
Routes []Route `json:"routes"`
|
||||
EntryPoints []string `json:"entryPoints"`
|
||||
TLS *TLS `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// Route contains the set of routes.
|
||||
type Route struct {
|
||||
Match string `json:"match"`
|
||||
Kind string `json:"kind"`
|
||||
Priority int `json:"priority"`
|
||||
Services []Service `json:"services,omitempty"`
|
||||
Middlewares []MiddlewareRef `json:"middlewares"`
|
||||
}
|
||||
|
||||
// TLS contains the TLS certificates configuration of the routes.
|
||||
type TLS struct {
|
||||
SecretName string `json:"secretName"`
|
||||
// TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"`
|
||||
}
|
||||
|
||||
// Service defines an upstream to proxy traffic.
|
||||
type Service struct {
|
||||
Name string `json:"name"`
|
||||
Port int32 `json:"port"`
|
||||
// TODO Weight int `json:"weight,omitempty"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
}
|
||||
|
||||
// MiddlewareRef is a ref to the Middleware resources.
|
||||
type MiddlewareRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// HealthCheck is the HealthCheck definition.
|
||||
type HealthCheck struct {
|
||||
Path string `json:"path"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Scheme string `json:"scheme"`
|
||||
IntervalSeconds int64 `json:"intervalSeconds"`
|
||||
TimeoutSeconds int64 `json:"timeoutSeconds"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// IngressRoute is an Ingress CRD specification.
|
||||
type IngressRoute struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec IngressRouteSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// IngressRouteList is a list of IngressRoutes.
|
||||
type IngressRouteList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
Items []IngressRoute `json:"items"`
|
||||
}
|
27
provider/kubernetes/crd/traefik/v1alpha1/middleware.go
Normal file
27
provider/kubernetes/crd/traefik/v1alpha1/middleware.go
Normal file
@ -0,0 +1,27 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/containous/traefik/config"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Middleware is a specification for a Middleware resource.
|
||||
type Middleware struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec config.Middleware `json:"spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// MiddlewareList is a list of Middleware resources.
|
||||
type MiddlewareList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []Middleware `json:"items"`
|
||||
}
|
43
provider/kubernetes/crd/traefik/v1alpha1/register.go
Normal file
43
provider/kubernetes/crd/traefik/v1alpha1/register.go
Normal file
@ -0,0 +1,43 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name for Traefik.
|
||||
const GroupName = "traefik.containo.us"
|
||||
|
||||
var (
|
||||
// SchemeBuilder collects the scheme builder functions.
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
|
||||
// AddToScheme applies the SchemeBuilder functions to a specified scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects.
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
|
||||
// Kind takes an unqualified kind and returns back a Group qualified GroupKind.
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// 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 Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&IngressRoute{},
|
||||
&IngressRouteList{},
|
||||
&Middleware{},
|
||||
&MiddlewareList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
@ -0,0 +1,290 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
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 *HealthCheck) DeepCopyInto(out *HealthCheck) {
|
||||
*out = *in
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheck.
|
||||
func (in *HealthCheck) DeepCopy() *HealthCheck {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HealthCheck)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IngressRoute) DeepCopyInto(out *IngressRoute) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRoute.
|
||||
func (in *IngressRoute) DeepCopy() *IngressRoute {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRoute)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IngressRoute) 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 *IngressRouteList) DeepCopyInto(out *IngressRouteList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]IngressRoute, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRouteList.
|
||||
func (in *IngressRouteList) DeepCopy() *IngressRouteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRouteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IngressRouteList) 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 *IngressRouteSpec) DeepCopyInto(out *IngressRouteSpec) {
|
||||
*out = *in
|
||||
if in.Routes != nil {
|
||||
in, out := &in.Routes, &out.Routes
|
||||
*out = make([]Route, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.EntryPoints != nil {
|
||||
in, out := &in.EntryPoints, &out.EntryPoints
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLS)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRouteSpec.
|
||||
func (in *IngressRouteSpec) DeepCopy() *IngressRouteSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRouteSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Middleware) DeepCopyInto(out *Middleware) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Middleware.
|
||||
func (in *Middleware) DeepCopy() *Middleware {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Middleware)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Middleware) 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 *MiddlewareList) DeepCopyInto(out *MiddlewareList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Middleware, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MiddlewareList.
|
||||
func (in *MiddlewareList) DeepCopy() *MiddlewareList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MiddlewareList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *MiddlewareList) 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 *MiddlewareRef) DeepCopyInto(out *MiddlewareRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MiddlewareRef.
|
||||
func (in *MiddlewareRef) DeepCopy() *MiddlewareRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MiddlewareRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Route) DeepCopyInto(out *Route) {
|
||||
*out = *in
|
||||
if in.Services != nil {
|
||||
in, out := &in.Services, &out.Services
|
||||
*out = make([]Service, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Middlewares != nil {
|
||||
in, out := &in.Middlewares, &out.Middlewares
|
||||
*out = make([]MiddlewareRef, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route.
|
||||
func (in *Route) DeepCopy() *Route {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Route)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Service) DeepCopyInto(out *Service) {
|
||||
*out = *in
|
||||
if in.HealthCheck != nil {
|
||||
in, out := &in.HealthCheck, &out.HealthCheck
|
||||
*out = new(HealthCheck)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service.
|
||||
func (in *Service) DeepCopy() *Service {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Service)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLS) DeepCopyInto(out *TLS) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLS.
|
||||
func (in *TLS) DeepCopy() *TLS {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLS)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
63
provider/kubernetes/ingress/builder_ingress_test.go
Normal file
63
provider/kubernetes/ingress/builder_ingress_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func buildIngress(opts ...func(*extensionsv1beta1.Ingress)) *extensionsv1beta1.Ingress {
|
||||
i := &extensionsv1beta1.Ingress{}
|
||||
i.Kind = "Ingress"
|
||||
for _, opt := range opts {
|
||||
opt(i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func iNamespace(value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func iRules(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iRule(opts ...func(*extensionsv1beta1.IngressRule)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(spec *extensionsv1beta1.IngressSpec) {
|
||||
r := &extensionsv1beta1.IngressRule{}
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
spec.Rules = append(spec.Rules, *r)
|
||||
}
|
||||
}
|
||||
|
||||
func iHost(name string) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.Host = name
|
||||
}
|
||||
}
|
||||
|
||||
func iTLSes(opts ...func(*extensionsv1beta1.IngressTLS)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
for _, opt := range opts {
|
||||
iTLS := extensionsv1beta1.IngressTLS{}
|
||||
opt(&iTLS)
|
||||
i.Spec.TLS = append(i.Spec.TLS, iTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLS(secret string, hosts ...string) func(*extensionsv1beta1.IngressTLS) {
|
||||
return func(i *extensionsv1beta1.IngressTLS) {
|
||||
i.SecretName = secret
|
||||
i.Hosts = hosts
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/old/log"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
kubeerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -41,7 +42,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
|
||||
// WatchAll starts the watch of the Provider resources and updates the stores.
|
||||
// The stores can then be accessed via the Get* functions.
|
||||
type Client interface {
|
||||
WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
GetIngresses() []*extensionsv1beta1.Ingress
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
@ -49,24 +50,17 @@ type Client interface {
|
||||
UpdateIngressStatus(namespace, name, ip, hostname string) error
|
||||
}
|
||||
|
||||
type clientImpl struct {
|
||||
type clientWrapper struct {
|
||||
clientset *kubernetes.Clientset
|
||||
factories map[string]informers.SharedInformerFactory
|
||||
ingressLabelSelector labels.Selector
|
||||
isNamespaceAll bool
|
||||
watchedNamespaces Namespaces
|
||||
}
|
||||
|
||||
func newClientImpl(clientset *kubernetes.Clientset) *clientImpl {
|
||||
return &clientImpl{
|
||||
clientset: clientset,
|
||||
factories: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
watchedNamespaces k8s.Namespaces
|
||||
}
|
||||
|
||||
// newInClusterClient returns a new Provider client that is expected to run
|
||||
// inside the cluster.
|
||||
func newInClusterClient(endpoint string) (*clientImpl, error) {
|
||||
func newInClusterClient(endpoint string) (*clientWrapper, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create in-cluster configuration: %s", err)
|
||||
@ -79,7 +73,7 @@ func newInClusterClient(endpoint string) (*clientImpl, error) {
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func newExternalClusterClientFromFile(file string) (*clientImpl, error) {
|
||||
func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||
configFromFlags, err := clientcmd.BuildConfigFromFlags("", file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -90,7 +84,7 @@ func newExternalClusterClientFromFile(file string) (*clientImpl, error) {
|
||||
// newExternalClusterClient returns a new Provider client that may run outside
|
||||
// of the cluster.
|
||||
// The endpoint parameter must not be empty.
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl, error) {
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("endpoint missing for external cluster client")
|
||||
}
|
||||
@ -111,7 +105,7 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl,
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func createClientFromConfig(c *rest.Config) (*clientImpl, error) {
|
||||
func createClientFromConfig(c *rest.Config) (*clientWrapper, error) {
|
||||
clientset, err := kubernetes.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -120,18 +114,25 @@ func createClientFromConfig(c *rest.Config) (*clientImpl, error) {
|
||||
return newClientImpl(clientset), nil
|
||||
}
|
||||
|
||||
func newClientImpl(clientset *kubernetes.Clientset) *clientWrapper {
|
||||
return &clientWrapper{
|
||||
clientset: clientset,
|
||||
factories: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
}
|
||||
|
||||
// WatchAll starts namespace-specific controllers for all relevant kinds.
|
||||
func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c *clientWrapper) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
eventCh := make(chan interface{}, 1)
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
|
||||
if len(namespaces) == 0 {
|
||||
namespaces = Namespaces{metav1.NamespaceAll}
|
||||
namespaces = k8s.Namespaces{metav1.NamespaceAll}
|
||||
c.isNamespaceAll = true
|
||||
}
|
||||
|
||||
c.watchedNamespaces = namespaces
|
||||
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
for _, ns := range namespaces {
|
||||
factory := informers.NewFilteredSharedInformerFactory(c.clientset, resyncPeriod, ns, nil)
|
||||
factory.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
@ -165,7 +166,7 @@ func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-
|
||||
}
|
||||
|
||||
// GetIngresses returns all Ingresses for observed namespaces in the cluster.
|
||||
func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
var result []*extensionsv1beta1.Ingress
|
||||
for ns, factory := range c.factories {
|
||||
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector)
|
||||
@ -178,7 +179,7 @@ func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
}
|
||||
|
||||
// UpdateIngressStatus updates an Ingress with a provided status.
|
||||
func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
func (c *clientWrapper) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
@ -207,7 +208,7 @@ func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) e
|
||||
}
|
||||
|
||||
// GetService returns the named service from the given namespace.
|
||||
func (c *clientImpl) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get service %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
@ -218,7 +219,7 @@ func (c *clientImpl) GetService(namespace, name string) (*corev1.Service, bool,
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientImpl) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
@ -229,7 +230,7 @@ func (c *clientImpl) GetEndpoints(namespace, name string) (*corev1.Endpoints, bo
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get secret %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
@ -245,14 +246,14 @@ func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, er
|
||||
// The distinction is necessary because we index all informers on the special
|
||||
// identifier iff all-namespaces are requested but receive specific namespace
|
||||
// identifiers from the Kubernetes API, so we have to bridge this gap.
|
||||
func (c *clientImpl) lookupNamespace(ns string) string {
|
||||
func (c *clientWrapper) lookupNamespace(ns string) string {
|
||||
if c.isNamespaceAll {
|
||||
return metav1.NamespaceAll
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (c *clientImpl) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
return &cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
// Ignore Ingresses that do not match our custom label selector.
|
||||
@ -287,7 +288,7 @@ func translateNotFoundError(err error) (bool, error) {
|
||||
|
||||
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
|
||||
// it to ensure we don't panic by requesting an out-of-watch object.
|
||||
func (c *clientImpl) isWatchedNamespace(ns string) bool {
|
||||
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
|
||||
if c.isNamespaceAll {
|
||||
return true
|
||||
}
|
@ -1,21 +1,58 @@
|
||||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
v1beta12 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
var _ Client = (*clientMock)(nil)
|
||||
|
||||
type clientMock struct {
|
||||
ingresses []*extensionsv1beta1.Ingress
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
watchChan chan interface{}
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
apiIngressStatusError error
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
||||
func newClientMock(paths ...string) clientMock {
|
||||
var c clientMock
|
||||
|
||||
for _, path := range paths {
|
||||
yamlContent, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sObjects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service:
|
||||
c.services = append(c.services, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *v1beta12.Ingress:
|
||||
c.ingresses = append(c.ingresses, o)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
@ -62,7 +99,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c clientMock) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
return c.watchChan, nil
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -0,0 +1,29 @@
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: toto
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
- ip: 10.11.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
@ -0,0 +1,37 @@
|
||||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: tchouk
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: carotte
|
||||
|
||||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: toto
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: toto.traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: tchouk
|
@ -0,0 +1,24 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 80
|
||||
clusterIp: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: toto
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 80
|
||||
clusterIp: 10.0.0.1
|
@ -0,0 +1,32 @@
|
||||
kind: Endpoints
|
||||
apiversion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.30.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.41.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiversion: v1
|
||||
metadata:
|
||||
name: service2
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
@ -0,0 +1,22 @@
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
|
||||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
backend:
|
||||
serviceName: service2
|
||||
servicePort: 80
|
@ -0,0 +1,22 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service2
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
@ -0,0 +1,15 @@
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
@ -0,0 +1,22 @@
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- host: traefik.courgette
|
||||
http:
|
||||
paths:
|
||||
- path: /carotte
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
@ -0,0 +1,10 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
@ -0,0 +1,15 @@
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
@ -0,0 +1,19 @@
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
@ -0,0 +1,10 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user