Merge pull request #836 from yvespp/master

Migrate k8s to kubernetes/client-go
This commit is contained in:
Vincent Demeester 2016-12-01 12:00:05 +01:00 committed by GitHub
commit 131f581f77
13 changed files with 1090 additions and 1195 deletions

View file

@ -21,6 +21,10 @@ WORKDIR /go/src/github.com/containous/traefik
COPY glide.yaml glide.yaml
COPY glide.lock glide.lock
RUN glide install
RUN glide install -v
COPY integration/glide.yaml integration/glide.yaml
COPY integration/glide.lock integration/glide.lock
RUN cd integration && glide install
COPY . /go/src/github.com/containous/traefik

301
glide.lock generated
View file

@ -1,5 +1,5 @@
hash: aae2fd761966717bcc30d8c03590cc28df8af49b36cc1d87689512cdfb44475e
updated: 2016-11-16T21:37:51.673291661+01:00
hash: 3ff2f92356bc5d286ce4d72835d5ace63c43cc591e561fd2d557e8dc8abd1672
updated: 2016-11-17T17:17:58.806741449Z
imports:
- name: github.com/abbot/go-http-auth
version: cb4372376e1e00e9f6ab9ec142e029302c9e7140
@ -9,6 +9,8 @@ imports:
- eureka
- name: github.com/ArthurHlt/gominlog
version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab
- name: github.com/blang/semver
version: 60ec3488bfea7cca02b021d106d9911120d25fe9
- name: github.com/boltdb/bolt
version: f4c032d907f61f08dba2d719c58f108a1abb8e81
- name: github.com/BurntSushi/toml
@ -19,10 +21,12 @@ imports:
- fun
- name: github.com/cenk/backoff
version: 8edc80b07f38c27352fb186d971c628a6c32552b
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/codahale/hdrhistogram
version: f8ad88b59a584afeee9d334eff879b104439117b
version: 9208b142303c12d8899bae836fd524ac9338b4fd
- name: github.com/codegangsta/cli
version: 1efa31f08b9333f1bd4882d61f9d668a70cd902e
version: bf4a526f48af7badd25d2cb02d587e1b01be3b50
- name: github.com/codegangsta/negroni
version: 3f7ce7b928e14ff890b067e5bbbc80af73690a9c
- name: github.com/containous/flaeg
@ -32,11 +36,28 @@ imports:
- name: github.com/containous/staert
version: 92329254783dc01174f03302d51d7cf2c9ff84cf
- name: github.com/coreos/etcd
version: 1c9e0a0e33051fed6c05c141e6fcbfe5c7f2a899
version: c400d05d0aa73e21e431c16145e558d624098018
subpackages:
- Godeps/_workspace/src/github.com/ugorji/go/codec
- Godeps/_workspace/src/golang.org/x/net/context
- client
- pkg/pathutil
- pkg/types
- name: github.com/coreos/go-oidc
version: 16c5ecc505f1efa0fe4685826fd9962c4d137e87
subpackages:
- http
- jose
- key
- oauth2
- oidc
- name: github.com/coreos/pkg
version: 2c77715c4df99b5420ffcae14ead08f52104065d
subpackages:
- capnslog
- health
- httputil
- timeutil
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
@ -133,23 +154,6 @@ imports:
version: f2145db703495b2e525c59662db69a7344b00bb8
- name: github.com/docker/leadership
version: 0a913e2d71a12fd14a028452435cb71ac8d82cb6
- name: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740
subpackages:
- config
- docker
- docker/builder
- docker/client
- docker/network
- labels
- logger
- lookup
- project
- project/events
- project/options
- utils
- version
- yaml
- name: github.com/docker/libkv
version: 3fce6a0f26e07da3eac45796a8e255547a47a750
subpackages:
@ -162,22 +166,42 @@ imports:
version: fd1de70867126402be23c306e1ce32828455d85b
- name: github.com/elazarl/go-bindata-assetfs
version: 9a6736ed45b44bf3835afeebb3034b57ed329f3e
- name: github.com/emicklei/go-restful
version: 892402ba11a2e2fd5e1295dd633481f27365f14d
subpackages:
- log
- swagger
- name: github.com/gambol99/go-marathon
version: a558128c87724cd7430060ef5aedf39f83937f55
- name: github.com/go-check/check
version: 4f90aeace3a26ad7021961c297b22c42160c7b25
- name: github.com/ghodss/yaml
version: aa0c862057666179de291b67d9f093d12b5a8473
- name: github.com/go-openapi/jsonpointer
version: 8d96a2dc61536b690bd36b2e9df0b3c0b62825b2
- name: github.com/go-openapi/jsonreference
version: 36d33bfe519efae5632669801b180bf1a245da3b
- name: github.com/go-openapi/spec
version: d1c18b339aece4b16ead6d253b85b6ad7180ea54
- name: github.com/go-openapi/swag
version: 3b6d86cd965820f968760d5d419cb4add096bdd7
- name: github.com/gogo/protobuf
version: 99cb9b23110011cc45571c901ecae6f6f5e65cd3
version: 909568be09de550ed094403c2bf8a261b5bb730a
subpackages:
- proto
- sortkeys
- name: github.com/golang/glog
version: fca8c8854093a154ff1eb580aae10276ad6b1b5f
- name: github.com/golang/protobuf
version: 5677a0e3d5e89854c9974e1256839ee23f8233ca
subpackages:
- proto
- name: github.com/google/go-querystring
version: 9235644dd9e52eeae6fa48efd539fdc351a0af53
subpackages:
- query
- name: github.com/google/gofuzz
version: fd52762d25a41827db7ef64c43756fd4b9f7e382
- name: github.com/gorilla/context
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
version: 14f550f51af52180c2eefed15e5fd18d63c0a64a
- name: github.com/hashicorp/consul
version: d8e2fb7dd594163e25a89bc52c1a4613f5c5bfb8
subpackages:
@ -185,21 +209,25 @@ imports:
- name: github.com/hashicorp/go-cleanhttp
version: ad28ea4487f05916463e2423a55166280e8254b5
- name: github.com/hashicorp/serf
version: b03bf85930b2349eb04b97c8fac437495296e3e7
version: 598c54895cc5a7b1a24a398d635e8c0ea0959870
subpackages:
- coordinate
- name: github.com/jarcoal/httpmock
version: 145b10d659265440f062c31ea15326166bae56ee
- name: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
subpackages:
- check
- name: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- name: github.com/jonboulle/clockwork
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/mailgun/manners
version: a585afd9d65c0e05f6c003f921e71ebc05074f4f
- name: github.com/mailgun/timetools
version: fd192d755b00c968d312d23f521eb0cdc6f66bd0
- name: github.com/mailru/easyjson
version: 159cdb893c982e3d1bc6450322fedd514f9c9de3
subpackages:
- buffer
- jlexer
- jwriter
- name: github.com/mattn/go-shellwords
version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24
- name: github.com/mesos/mesos-go
@ -230,22 +258,22 @@ imports:
version: 5d001d020961ae1c184f9f8152fdc73810481677
- name: github.com/mitchellh/mapstructure
version: ca63d7c062ee3c9f34db231e352b60012b4fd0c1
- name: github.com/moul/http2curl
version: b1479103caacaa39319f75e7f57fc545287fca0d
- name: github.com/NYTimes/gziphandler
version: f6438dbf4a82c56684964b03956aa727b0d7816b
- name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/runc
version: 02f8fa7863dd3f82909a73e2061897828460d52f
version: ba1568de399395774ad84c2ace65937814c542ed
subpackages:
- libcontainer/user
- name: github.com/parnurzeal/gorequest
version: e30af16d4e485943aab0b0885ad6bdbb8c0d3dc7
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/pborman/uuid
version: 3d4f2ba23642d3cfd06bd4b54cf03d99d95c0f1b
- name: github.com/PuerkitoBio/purell
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
- name: github.com/ryanuber/go-glob
version: 572520ed46dbddaed19ea3d9541bdd0494163693
- name: github.com/samuel/go-zookeeper
@ -256,12 +284,14 @@ imports:
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/Sirupsen/logrus
version: 3ec0642a7fb6488f65b06f9040adc67e3990296a
- name: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842
- name: github.com/streamrail/concurrent-map
version: 8bf1e9bacbf65b10c81d0f4314cf2b1ebef728b5
- name: github.com/stretchr/objx
version: cbeaeb16a013161a98496fad62933b1d21786672
- name: github.com/stretchr/testify
version: 976c720a22c8eb4eb6a0b4348ad85ad12491a506
version: b8dc1cecf15bdaf1988d9e87aa7cd98d899a06d6
subpackages:
- assert
- mock
@ -270,15 +300,13 @@ imports:
- name: github.com/tv42/zbase32
version: 03389da7e0bf9844767f82690f4d68fc097a1306
- name: github.com/ugorji/go
version: b94837a2404ab90efe9289e77a70694c355739cb
version: ea9cd21fa0bc41ee4bdd50ac7ed8cbc7ea2ed960
subpackages:
- codec
- name: github.com/unrolled/render
version: 526faf80cd4b305bb8134abea8d20d5ced74faa6
- name: github.com/vdemeester/docker-events
version: be74d4929ec1ad118df54349fda4b0cba60f849b
- name: github.com/vdemeester/shakers
version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
- name: github.com/vulcand/oxy
version: 4298f24d572dc554eb984f2ffdf6bdd54d4bd613
repo: https://github.com/containous/oxy.git
@ -296,7 +324,7 @@ imports:
- name: github.com/vulcand/route
version: cb89d787ddbb1c5849a7ac9f79004c1fd12a4a32
- name: github.com/vulcand/vulcand
version: bed092e10989250b48bdb6aa3b0557b207f05c80
version: 42492a3a85e294bdbdd1bcabb8c12769a81ea284
subpackages:
- conntracker
- plugin
@ -307,26 +335,62 @@ imports:
subpackages:
- acme
- name: golang.org/x/crypto
version: d81fdb778bf2c40a91b24519d60cdc5767318829
version: 4ed45ec682102c643324fae5dff8dab085b6c300
subpackages:
- bcrypt
- blowfish
- ocsp
- name: golang.org/x/net
version: b400c2eff1badec7022a8c8f5bea058b6315eed7
version: d4c55e66d8c3a2f3382d264b08e3e3454a66355a
subpackages:
- context
- http2
- http2/hpack
- idna
- lex/httplex
- proxy
- publicsuffix
- name: golang.org/x/oauth2
version: 3046bc76d6dfd7d3707f6640f85e42d9c4050f50
subpackages:
- google
- internal
- jws
- jwt
- name: golang.org/x/sys
version: 62bee037599929a6e9146f29d10dd5208c43507d
version: eb2c74142fd19a79b3f237334c7384d5167b1b46
subpackages:
- unix
- windows
- name: golang.org/x/text
version: a263ba8db058568bb9beba166777d9c9dbe75d68
subpackages:
- transform
- unicode/norm
- width
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
subpackages:
- internal
- internal/app_identity
- internal/base
- internal/datastore
- internal/log
- internal/modules
- internal/remote_api
- internal/urlfetch
- urlfetch
- name: google.golang.org/cloud
version: f20d6dcccb44ed49de45ae3703312cb46e627db1
subpackages:
- compute/metadata
- internal
- name: gopkg.in/fsnotify.v1
version: 944cff21b3baf3ced9a880365682152ba577d348
- name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/mgo.v2
version: 22287bab4379e1fbf6002fb4eb769888f3fb224c
version: 29cc868a5ca65f401ff318143f9408d02f4799cc
subpackages:
- bson
- name: gopkg.in/square/go-jose.v1
@ -334,27 +398,156 @@ imports:
subpackages:
- cipher
- json
- name: k8s.io/client-go
version: 843f7c4f28b1f647f664f883697107d5c02c5acc
subpackages:
- 1.5/discovery
- 1.5/kubernetes
- 1.5/kubernetes/typed/apps/v1alpha1
- 1.5/kubernetes/typed/authentication/v1beta1
- 1.5/kubernetes/typed/authorization/v1beta1
- 1.5/kubernetes/typed/autoscaling/v1
- 1.5/kubernetes/typed/batch/v1
- 1.5/kubernetes/typed/certificates/v1alpha1
- 1.5/kubernetes/typed/core/v1
- 1.5/kubernetes/typed/extensions/v1beta1
- 1.5/kubernetes/typed/policy/v1alpha1
- 1.5/kubernetes/typed/rbac/v1alpha1
- 1.5/kubernetes/typed/storage/v1beta1
- 1.5/pkg/api
- 1.5/pkg/api/errors
- 1.5/pkg/api/install
- 1.5/pkg/api/meta
- 1.5/pkg/api/meta/metatypes
- 1.5/pkg/api/resource
- 1.5/pkg/api/unversioned
- 1.5/pkg/api/v1
- 1.5/pkg/api/validation/path
- 1.5/pkg/apimachinery
- 1.5/pkg/apimachinery/announced
- 1.5/pkg/apimachinery/registered
- 1.5/pkg/apis/apps
- 1.5/pkg/apis/apps/install
- 1.5/pkg/apis/apps/v1alpha1
- 1.5/pkg/apis/authentication
- 1.5/pkg/apis/authentication/install
- 1.5/pkg/apis/authentication/v1beta1
- 1.5/pkg/apis/authorization
- 1.5/pkg/apis/authorization/install
- 1.5/pkg/apis/authorization/v1beta1
- 1.5/pkg/apis/autoscaling
- 1.5/pkg/apis/autoscaling/install
- 1.5/pkg/apis/autoscaling/v1
- 1.5/pkg/apis/batch
- 1.5/pkg/apis/batch/install
- 1.5/pkg/apis/batch/v1
- 1.5/pkg/apis/batch/v2alpha1
- 1.5/pkg/apis/certificates
- 1.5/pkg/apis/certificates/install
- 1.5/pkg/apis/certificates/v1alpha1
- 1.5/pkg/apis/extensions
- 1.5/pkg/apis/extensions/install
- 1.5/pkg/apis/extensions/v1beta1
- 1.5/pkg/apis/policy
- 1.5/pkg/apis/policy/install
- 1.5/pkg/apis/policy/v1alpha1
- 1.5/pkg/apis/rbac
- 1.5/pkg/apis/rbac/install
- 1.5/pkg/apis/rbac/v1alpha1
- 1.5/pkg/apis/storage
- 1.5/pkg/apis/storage/install
- 1.5/pkg/apis/storage/v1beta1
- 1.5/pkg/auth/user
- 1.5/pkg/conversion
- 1.5/pkg/conversion/queryparams
- 1.5/pkg/fields
- 1.5/pkg/genericapiserver/openapi/common
- 1.5/pkg/labels
- 1.5/pkg/runtime
- 1.5/pkg/runtime/serializer
- 1.5/pkg/runtime/serializer/json
- 1.5/pkg/runtime/serializer/protobuf
- 1.5/pkg/runtime/serializer/recognizer
- 1.5/pkg/runtime/serializer/streaming
- 1.5/pkg/runtime/serializer/versioning
- 1.5/pkg/selection
- 1.5/pkg/third_party/forked/golang/reflect
- 1.5/pkg/types
- 1.5/pkg/util
- 1.5/pkg/util/cert
- 1.5/pkg/util/clock
- 1.5/pkg/util/errors
- 1.5/pkg/util/flowcontrol
- 1.5/pkg/util/framer
- 1.5/pkg/util/integer
- 1.5/pkg/util/intstr
- 1.5/pkg/util/json
- 1.5/pkg/util/labels
- 1.5/pkg/util/net
- 1.5/pkg/util/parsers
- 1.5/pkg/util/rand
- 1.5/pkg/util/runtime
- 1.5/pkg/util/sets
- 1.5/pkg/util/uuid
- 1.5/pkg/util/validation
- 1.5/pkg/util/validation/field
- 1.5/pkg/util/wait
- 1.5/pkg/util/yaml
- 1.5/pkg/version
- 1.5/pkg/watch
- 1.5/pkg/watch/versioned
- 1.5/plugin/pkg/client/auth
- 1.5/plugin/pkg/client/auth/gcp
- 1.5/plugin/pkg/client/auth/oidc
- 1.5/rest
- 1.5/tools/cache
- 1.5/tools/clientcmd/api
- 1.5/tools/metrics
- 1.5/transport
testImports:
- name: github.com/Azure/go-ansiterm
version: fa152c58bc15761d0200cb75fe958b89a9d4888e
subpackages:
- winterm
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740
subpackages:
- config
- docker
- docker/builder
- docker/client
- docker/network
- labels
- logger
- lookup
- project
- project/events
- project/options
- utils
- version
- yaml
- name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/go-check/check
version: 11d3bc7aa68e238947792f30573146a3231fc0f1
- name: github.com/gorilla/mux
version: 9fa818a44c2bf1396a17f9d5a3c0f6dd39d2ff8e
version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
- name: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
subpackages:
- check
- name: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- name: github.com/libkermit/docker-check
version: cbe0ef03b3d23070eac4d00ba8828f2cc7f7e5a3
- name: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842
- name: github.com/vbatts/tar-split
version: bd4c5d64c3e9297f410025a3b1bd0c58f659e721
subpackages:
- archive/tar
- tar/asm
- tar/storage
- name: github.com/vdemeester/shakers
version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
- name: github.com/xeipuuv/gojsonpointer
version: e0fe6f68307607d540ed8eac07a342c33fa1b54a
- name: github.com/xeipuuv/gojsonreference

View file

@ -58,26 +58,23 @@ import:
- package: github.com/vdemeester/docker-events
version: be74d4929ec1ad118df54349fda4b0cba60f849b
- package: github.com/vulcand/vulcand
version: 42492a3a85e294bdbdd1bcabb8c12769a81ea284
subpackages:
- plugin/rewrite
- package: github.com/xenolf/lego
version: b2fad6198110326662e9e356a97199078a4a775c
subpackages:
- acme
- package: golang.org/x/net
version: release-branch.go1.7
subpackages:
- context
- package: gopkg.in/fsnotify.v1
- package: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
- package: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- package: github.com/docker/docker
version: 534753663161334baba06f13b8efa4cad22b5bc5
subpackages:
- namesgenerator
- package: github.com/go-check/check
- package: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740
- package: github.com/mattn/go-shellwords
- package: github.com/vdemeester/shakers
- package: github.com/ryanuber/go-glob
- package: github.com/mesos/mesos-go
subpackages:
@ -99,6 +96,10 @@ import:
- package: github.com/docker/leadership
- package: github.com/satori/go.uuid
version: ^1.1.0
- package: k8s.io/client-go
version: ^v1.5.0
- package: github.com/gogo/protobuf
version: 0.3
- package: github.com/ArthurHlt/go-eureka-client
subpackages:
- eureka

295
integration/glide.lock generated Normal file
View file

@ -0,0 +1,295 @@
hash: c53f57a45247b08a91f127ece494d49f1b7fee8c5f75be87ab12e27aa92d065f
updated: 2016-11-17T16:23:56.727970904Z
imports:
- name: github.com/cenk/backoff
version: 8edc80b07f38c27352fb186d971c628a6c32552b
testImports:
- name: github.com/ArthurHlt/go-eureka-client
version: ba361cd0f9f571b4e871421423d2f02f5689c3d2
subpackages:
- eureka
- name: github.com/ArthurHlt/gominlog
version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab
- name: github.com/Azure/go-ansiterm
version: fa152c58bc15761d0200cb75fe958b89a9d4888e
subpackages:
- winterm
- name: github.com/boltdb/bolt
version: f4c032d907f61f08dba2d719c58f108a1abb8e81
- name: github.com/BurntSushi/toml
version: 99064174e013895bbd9b025c31100bd1d9b590ca
- name: github.com/BurntSushi/ty
version: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74
subpackages:
- fun
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/containous/flaeg
version: a731c034dda967333efce5f8d276aeff11f8ff87
- name: github.com/containous/staert
version: 92329254783dc01174f03302d51d7cf2c9ff84cf
- name: github.com/containous/traefik
version: 15732269da23c35524bf7cabea5857e4c5f63881
subpackages:
- autogen
- cluster
- job
- log
- provider
- provider/k8s
- safe
- types
- version
- name: github.com/coreos/etcd
version: c400d05d0aa73e21e431c16145e558d624098018
subpackages:
- Godeps/_workspace/src/github.com/ugorji/go/codec
- Godeps/_workspace/src/golang.org/x/net/context
- client
- pkg/pathutil
- pkg/types
- name: github.com/daviddengcn/go-colortext
version: 3b18c8575a432453d41fdafb340099fff5bba2f7
- name: github.com/docker/distribution
version: 99cb7c0946d2f5a38015443e515dc916295064d7
subpackages:
- context
- digest
- reference
- registry/api/errcode
- registry/api/v2
- registry/client
- registry/client/auth
- registry/client/transport
- registry/storage/cache
- registry/storage/cache/memory
- uuid
- name: github.com/docker/docker
version: 534753663161334baba06f13b8efa4cad22b5bc5
subpackages:
- api/types/backend
- builder
- builder/dockerignore
- cliconfig
- cliconfig/configfile
- daemon/graphdriver
- image
- image/v1
- layer
- opts
- pkg/archive
- pkg/chrootarchive
- pkg/fileutils
- pkg/gitutils
- pkg/homedir
- pkg/httputils
- pkg/idtools
- pkg/ioutils
- pkg/jsonlog
- pkg/jsonmessage
- pkg/longpath
- pkg/mflag
- pkg/mount
- pkg/namesgenerator
- pkg/plugins
- pkg/plugins/transport
- pkg/pools
- pkg/progress
- pkg/promise
- pkg/random
- pkg/reexec
- pkg/signal
- pkg/stdcopy
- pkg/streamformatter
- pkg/stringid
- pkg/symlink
- pkg/system
- pkg/tarsum
- pkg/term
- pkg/term/windows
- pkg/urlutil
- reference
- registry
- runconfig/opts
- name: github.com/docker/engine-api
version: 62043eb79d581a32ea849645277023c550732e52
subpackages:
- client
- client/transport
- client/transport/cancellable
- types
- types/blkiodev
- types/container
- types/events
- types/filters
- types/network
- types/reference
- types/registry
- types/strslice
- types/swarm
- types/time
- types/versions
- name: github.com/docker/go-connections
version: 988efe982fdecb46f01d53465878ff1f2ff411ce
subpackages:
- nat
- sockets
- tlsconfig
- name: github.com/docker/go-units
version: f2145db703495b2e525c59662db69a7344b00bb8
- name: github.com/docker/leadership
version: 0a913e2d71a12fd14a028452435cb71ac8d82cb6
- name: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740
subpackages:
- config
- docker
- docker/builder
- docker/client
- docker/network
- labels
- logger
- lookup
- project
- project/events
- project/options
- utils
- version
- yaml
- name: github.com/docker/libkv
version: 3fce6a0f26e07da3eac45796a8e255547a47a750
subpackages:
- store
- store/boltdb
- store/consul
- store/etcd
- store/zookeeper
- name: github.com/donovanhide/eventsource
version: fd1de70867126402be23c306e1ce32828455d85b
- name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/gambol99/go-marathon
version: a558128c87724cd7430060ef5aedf39f83937f55
- name: github.com/go-check/check
version: 11d3bc7aa68e238947792f30573146a3231fc0f1
- name: github.com/gogo/protobuf
version: 43ab7f0ec7b6d072e0368bd537ffefe74ed30198
subpackages:
- proto
- name: github.com/golang/glog
version: fca8c8854093a154ff1eb580aae10276ad6b1b5f
- name: github.com/google/go-querystring
version: 9235644dd9e52eeae6fa48efd539fdc351a0af53
subpackages:
- query
- name: github.com/gorilla/context
version: 14f550f51af52180c2eefed15e5fd18d63c0a64a
- name: github.com/gorilla/mux
version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
- name: github.com/hashicorp/consul
version: d8e2fb7dd594163e25a89bc52c1a4613f5c5bfb8
subpackages:
- api
- name: github.com/hashicorp/go-cleanhttp
version: ad28ea4487f05916463e2423a55166280e8254b5
- name: github.com/hashicorp/serf
version: 598c54895cc5a7b1a24a398d635e8c0ea0959870
subpackages:
- coordinate
- name: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
subpackages:
- check
- name: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- name: github.com/libkermit/docker-check
version: cbe0ef03b3d23070eac4d00ba8828f2cc7f7e5a3
- name: github.com/mattn/go-shellwords
version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24
- name: github.com/mesos/mesos-go
version: 068d5470506e3780189fe607af40892814197c5e
subpackages:
- detector
- detector/zoo
- mesosproto
- mesosutil
- upid
- name: github.com/mesosphere/mesos-dns
version: b47dc4c19f215e98da687b15b4c64e70f629bea5
repo: https://github.com/containous/mesos-dns.git
vcs: git
subpackages:
- detect
- errorutil
- logging
- models
- records
- records/labels
- records/state
- util
- name: github.com/Microsoft/go-winio
version: ce2922f643c8fd76b46cadc7f404a06282678b34
- name: github.com/miekg/dns
version: 5d001d020961ae1c184f9f8152fdc73810481677
- name: github.com/mitchellh/mapstructure
version: ca63d7c062ee3c9f34db231e352b60012b4fd0c1
- name: github.com/moul/http2curl
version: b1479103caacaa39319f75e7f57fc545287fca0d
- name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/runc
version: ba1568de399395774ad84c2ace65937814c542ed
subpackages:
- libcontainer/user
- name: github.com/parnurzeal/gorequest
version: e30af16d4e485943aab0b0885ad6bdbb8c0d3dc7
- name: github.com/ryanuber/go-glob
version: 572520ed46dbddaed19ea3d9541bdd0494163693
- name: github.com/samuel/go-zookeeper
version: 87e1bca4477a3cc767ca71be023ced183d74e538
subpackages:
- zk
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/Sirupsen/logrus
version: 3ec0642a7fb6488f65b06f9040adc67e3990296a
- name: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842
- name: github.com/stretchr/objx
version: cbeaeb16a013161a98496fad62933b1d21786672
- name: github.com/stretchr/testify
version: b8dc1cecf15bdaf1988d9e87aa7cd98d899a06d6
subpackages:
- assert
- mock
- name: github.com/tv42/zbase32
version: 03389da7e0bf9844767f82690f4d68fc097a1306
- name: github.com/vbatts/tar-split
version: bd4c5d64c3e9297f410025a3b1bd0c58f659e721
subpackages:
- archive/tar
- tar/asm
- tar/storage
- name: github.com/vdemeester/docker-events
version: be74d4929ec1ad118df54349fda4b0cba60f849b
- name: github.com/vdemeester/shakers
version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
- name: github.com/xeipuuv/gojsonpointer
version: e0fe6f68307607d540ed8eac07a342c33fa1b54a
- name: github.com/xeipuuv/gojsonreference
version: e02fc20de94c78484cd5ffb007f8af96be030a45
- name: github.com/xeipuuv/gojsonschema
version: 00f9fafb54d2244d291b86ab63d12c38bd5c3886
- name: golang.org/x/net
version: db8e4de5b2d6653f66aea53094624468caad15d2
subpackages:
- context
- proxy
- publicsuffix
- name: golang.org/x/sys
version: 9c60d1c508f5134d1ca726b4641db998f2523357
subpackages:
- unix
- windows
- name: gopkg.in/fsnotify.v1
version: 944cff21b3baf3ced9a880365682152ba577d348

33
integration/glide.yaml Normal file
View file

@ -0,0 +1,33 @@
package: github.com/containous/traefik/integration
import:
- package: github.com/cenk/backoff
testImport:
- package: github.com/containous/staert
version: 92329254783dc01174f03302d51d7cf2c9ff84cf
- package: github.com/docker/docker
version: 534753663161334baba06f13b8efa4cad22b5bc5
subpackages:
- pkg/namesgenerator
- package: github.com/docker/libkv
subpackages:
- store
- store/consul
- store/etcd
- package: github.com/go-check/check
- package: github.com/hashicorp/consul
subpackages:
- api
- package: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
subpackages:
- check
- package: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- package: github.com/libkermit/docker-check
- package: github.com/mattn/go-shellwords
- package: github.com/vdemeester/shakers
- package: golang.org/x/net
subpackages:
- context
- package: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842

View file

@ -1,296 +1,268 @@
package k8s
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"github.com/containous/traefik/log"
"github.com/parnurzeal/gorequest"
"net/http"
"net/url"
"strings"
"time"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/1.5/pkg/fields"
"k8s.io/client-go/1.5/pkg/labels"
"k8s.io/client-go/1.5/pkg/runtime"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
"k8s.io/client-go/1.5/tools/cache"
)
const (
// APIEndpoint defines the base path for kubernetes API resources.
APIEndpoint = "/api/v1"
extentionsEndpoint = "/apis/extensions/v1beta1"
defaultIngress = "/ingresses"
namespaces = "/namespaces/"
)
const resyncPeriod = time.Minute * 5
// Client is a client for the Kubernetes master.
// WatchAll starts the watch of the Kubernetes ressources and updates the stores.
// The stores can then be accessed via the Get* functions.
type Client interface {
GetIngresses(labelSelector string, predicate func(Ingress) bool) ([]Ingress, error)
GetService(name, namespace string) (Service, error)
GetEndpoints(name, namespace string) (Endpoints, error)
WatchAll(labelSelector string, stopCh <-chan bool) (chan interface{}, chan error, error)
GetIngresses(namespaces Namespaces) []*v1beta1.Ingress
GetService(namespace, name string) (*v1.Service, bool, error)
GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error)
WatchAll(labelSelector string, stopCh <-chan bool) (chan interface{}, error)
}
type clientImpl struct {
endpointURL string
tls *tls.Config
token string
caCert []byte
ingController *cache.Controller
svcController *cache.Controller
epController *cache.Controller
ingStore cache.Store
svcStore cache.Store
epStore cache.Store
clientset *kubernetes.Clientset
}
// NewClient returns a new Kubernetes client.
// The provided host is an url (scheme://hostname[:port]) of a
// Kubernetes master without any path.
// The provided client is an authorized http.Client used to perform requests to the Kubernetes API master.
func NewClient(baseURL string, caCert []byte, token string) (Client, error) {
validURL, err := url.Parse(baseURL)
// NewInClusterClient returns a new Kubernetes client that expect to run inside the cluster
func NewInClusterClient() (Client, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("failed to parse URL %q: %v", baseURL, err)
return nil, err
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return &clientImpl{
endpointURL: strings.TrimSuffix(validURL.String(), "/"),
token: token,
caCert: caCert,
clientset: clientset,
}, nil
}
func makeQueryString(baseParams map[string]string, labelSelector string) (string, error) {
if labelSelector != "" {
baseParams["labelSelector"] = labelSelector
}
queryData, err := json.Marshal(baseParams)
// NewInClusterClientWithEndpoint is the same as NewInClusterClient but uses the provided endpoint URL
func NewInClusterClientWithEndpoint(endpoint string) (Client, error) {
config, err := rest.InClusterConfig()
if err != nil {
return "", err
return nil, err
}
return string(queryData), nil
config.Host = endpoint
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return &clientImpl{
clientset: clientset,
}, nil
}
// GetIngresses returns all ingresses in the cluster
func (c *clientImpl) GetIngresses(labelSelector string, predicate func(Ingress) bool) ([]Ingress, error) {
getURL := c.endpointURL + extentionsEndpoint + defaultIngress
queryParams := map[string]string{}
queryData, err := makeQueryString(queryParams, labelSelector)
if err != nil {
return nil, fmt.Errorf("Had problems constructing query string %s : %v", queryParams, err)
func (c *clientImpl) GetIngresses(namespaces Namespaces) []*v1beta1.Ingress {
ingList := c.ingStore.List()
result := make([]*v1beta1.Ingress, 0, len(ingList))
for _, obj := range ingList {
ingress := obj.(*v1beta1.Ingress)
if HasNamespace(ingress, namespaces) {
result = append(result, ingress)
}
body, err := c.do(c.request(getURL, queryData))
if err != nil {
return nil, fmt.Errorf("failed to create ingresses request: GET %q : %v", getURL, err)
}
var ingressList IngressList
if err := json.Unmarshal(body, &ingressList); err != nil {
return nil, fmt.Errorf("failed to decode list of ingress resources: %v", err)
}
ingresses := ingressList.Items[:0]
for _, ingress := range ingressList.Items {
if predicate(ingress) {
ingresses = append(ingresses, ingress)
}
}
return ingresses, nil
return result
}
// WatchIngresses returns all ingresses in the cluster
func (c *clientImpl) WatchIngresses(labelSelector string, stopCh <-chan bool) (chan interface{}, chan error, error) {
getURL := c.endpointURL + extentionsEndpoint + defaultIngress
return c.watch(getURL, labelSelector, stopCh)
// WatchIngresses starts the watch of Kubernetes Ingresses resources and updates the corresponding store
func (c *clientImpl) WatchIngresses(labelSelector labels.Selector, stopCh <-chan struct{}) chan interface{} {
watchCh := make(chan interface{}, 10)
source := NewListWatchFromClient(
c.clientset.ExtensionsClient,
"ingresses",
api.NamespaceAll,
fields.Everything(),
labelSelector)
c.ingStore, c.ingController = cache.NewInformer(
source,
&v1beta1.Ingress{},
resyncPeriod,
newResourceEventHandlerFuncs(watchCh))
go c.ingController.Run(stopCh)
return watchCh
}
func newResourceEventHandlerFuncs(events chan interface{}) cache.ResourceEventHandlerFuncs {
return cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { events <- obj },
UpdateFunc: func(old, new interface{}) { events <- new },
DeleteFunc: func(obj interface{}) { events <- obj },
}
}
// GetService returns the named service from the named namespace
func (c *clientImpl) GetService(name, namespace string) (Service, error) {
getURL := c.endpointURL + APIEndpoint + namespaces + namespace + "/services/" + name
body, err := c.do(c.request(getURL, ""))
if err != nil {
return Service{}, fmt.Errorf("failed to create services request: GET %q : %v", getURL, err)
func (c *clientImpl) GetService(namespace, name string) (*v1.Service, bool, error) {
var service *v1.Service
item, exists, err := c.svcStore.GetByKey(namespace + "/" + name)
if item != nil {
service = item.(*v1.Service)
}
var service Service
if err := json.Unmarshal(body, &service); err != nil {
return Service{}, fmt.Errorf("failed to decode service resource: %v", err)
}
return service, nil
return service, exists, err
}
// WatchServices returns all services in the cluster
func (c *clientImpl) WatchServices(stopCh <-chan bool) (chan interface{}, chan error, error) {
getURL := c.endpointURL + APIEndpoint + "/services"
return c.watch(getURL, "", stopCh)
// WatchServices starts the watch of Kubernetes Service resources and updates the corresponding store
func (c *clientImpl) WatchServices(stopCh <-chan struct{}) chan interface{} {
watchCh := make(chan interface{}, 10)
source := cache.NewListWatchFromClient(
c.clientset.CoreClient,
"services",
api.NamespaceAll,
fields.Everything())
c.svcStore, c.svcController = cache.NewInformer(
source,
&v1.Service{},
resyncPeriod,
newResourceEventHandlerFuncs(watchCh))
go c.svcController.Run(stopCh)
return watchCh
}
// GetEndpoints returns the named Endpoints
// Endpoints have the same name as the coresponding service
func (c *clientImpl) GetEndpoints(name, namespace string) (Endpoints, error) {
getURL := c.endpointURL + APIEndpoint + namespaces + namespace + "/endpoints/" + name
func (c *clientImpl) GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error) {
var endpoint *v1.Endpoints
item, exists, err := c.epStore.GetByKey(namespace + "/" + name)
body, err := c.do(c.request(getURL, ""))
if err != nil {
return Endpoints{}, fmt.Errorf("failed to create endpoints request: GET %q : %v", getURL, err)
if item != nil {
endpoint = item.(*v1.Endpoints)
}
var endpoints Endpoints
if err := json.Unmarshal(body, &endpoints); err != nil {
return Endpoints{}, fmt.Errorf("failed to decode endpoints resources: %v", err)
}
return endpoints, nil
return endpoint, exists, err
}
// WatchEndpoints returns endpoints in the cluster
func (c *clientImpl) WatchEndpoints(stopCh <-chan bool) (chan interface{}, chan error, error) {
getURL := c.endpointURL + APIEndpoint + "/endpoints"
return c.watch(getURL, "", stopCh)
}
// WatchAll returns events in the cluster
func (c *clientImpl) WatchAll(labelSelector string, stopCh <-chan bool) (chan interface{}, chan error, error) {
// WatchEndpoints starts the watch of Kubernetes Endpoints resources and updates the corresponding store
func (c *clientImpl) WatchEndpoints(stopCh <-chan struct{}) chan interface{} {
watchCh := make(chan interface{}, 10)
errCh := make(chan error, 10)
stopIngresses := make(chan bool)
chanIngresses, chanIngressesErr, err := c.WatchIngresses(labelSelector, stopIngresses)
source := cache.NewListWatchFromClient(
c.clientset.CoreClient,
"endpoints",
api.NamespaceAll,
fields.Everything())
c.epStore, c.epController = cache.NewInformer(
source,
&v1.Endpoints{},
resyncPeriod,
newResourceEventHandlerFuncs(watchCh))
go c.epController.Run(stopCh)
return watchCh
}
// WatchAll returns events in the cluster and updates the stores via informer
// Filters ingresses by labelSelector
func (c *clientImpl) WatchAll(labelSelector string, stopCh <-chan bool) (chan interface{}, error) {
watchCh := make(chan interface{}, 100)
stopWatchCh := make(chan struct{}, 1)
kubeLabelSelector, err := labels.Parse(labelSelector)
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to create watch: %v", err)
}
stopServices := make(chan bool)
chanServices, chanServicesErr, err := c.WatchServices(stopServices)
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to create watch: %v", err)
}
stopEndpoints := make(chan bool)
chanEndpoints, chanEndpointsErr, err := c.WatchEndpoints(stopEndpoints)
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to create watch: %v", err)
return nil, err
}
chanIngresses := c.WatchIngresses(kubeLabelSelector, stopWatchCh)
chanServices := c.WatchServices(stopWatchCh)
chanEndpoints := c.WatchEndpoints(stopWatchCh)
go func() {
defer close(stopWatchCh)
defer close(watchCh)
defer close(errCh)
defer close(stopIngresses)
defer close(stopServices)
defer close(stopEndpoints)
for {
select {
case <-stopCh:
stopIngresses <- true
stopServices <- true
stopEndpoints <- true
return
case err := <-chanIngressesErr:
errCh <- err
case err := <-chanServicesErr:
errCh <- err
case err := <-chanEndpointsErr:
errCh <- err
case event := <-chanIngresses:
watchCh <- event
c.fireEvent(event, watchCh)
case event := <-chanServices:
watchCh <- event
c.fireEvent(event, watchCh)
case event := <-chanEndpoints:
c.fireEvent(event, watchCh)
}
}
}()
return watchCh, nil
}
// fireEvent checks if all controllers have synced before firing
// Used after startup or a reconnect
func (c *clientImpl) fireEvent(event interface{}, watchCh chan interface{}) {
if c.ingController.HasSynced() && c.svcController.HasSynced() && c.epController.HasSynced() {
watchCh <- event
}
}
}()
return watchCh, errCh, nil
}
func (c *clientImpl) do(request *gorequest.SuperAgent) ([]byte, error) {
res, body, errs := request.EndBytes()
if errs != nil {
return nil, fmt.Errorf("failed to create request: GET %q : %v", request.Url, errs)
// HasNamespace checks if the ingress is in one of the namespaces
func HasNamespace(ingress *v1beta1.Ingress, namespaces Namespaces) bool {
if len(namespaces) == 0 {
return true
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http error %d GET %q: %q", res.StatusCode, request.Url, string(body))
for _, n := range namespaces {
if ingress.ObjectMeta.Namespace == n {
return true
}
return body, nil
}
return false
}
func (c *clientImpl) request(reqURL string, queryContent interface{}) *gorequest.SuperAgent {
// Make request to Kubernetes API
parsedURL, parseErr := url.Parse(reqURL)
if parseErr != nil {
log.Errorf("Had issues parsing url %s. Trying anyway.", reqURL)
// NewListWatchFromClient creates a new ListWatch from the specified client, resource, namespace, field selector and label selector.
// Extends cache.NewListWatchFromClient to support labelSelector
func NewListWatchFromClient(c cache.Getter, resource string, namespace string, fieldSelector fields.Selector, labelSelector labels.Selector) *cache.ListWatch {
listFunc := func(options api.ListOptions) (runtime.Object, error) {
return c.Get().
Namespace(namespace).
Resource(resource).
VersionedParams(&options, api.ParameterCodec).
FieldsSelectorParam(fieldSelector).
LabelsSelectorParam(labelSelector).
Do().
Get()
}
request := gorequest.New().Get(reqURL)
request.Transport.DisableKeepAlives = true
if parsedURL.Scheme == "https" {
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(c.caCert)
c.tls = &tls.Config{RootCAs: pool}
request.TLSClientConfig(c.tls)
watchFunc := func(options api.ListOptions) (watch.Interface, error) {
return c.Get().
Prefix("watch").
Namespace(namespace).
Resource(resource).
VersionedParams(&options, api.ParameterCodec).
FieldsSelectorParam(fieldSelector).
LabelsSelectorParam(labelSelector).
Watch()
}
if len(c.token) > 0 {
request.Header["Authorization"] = "Bearer " + c.token
}
request.Query(queryContent)
return request
}
// GenericObject generic object
type GenericObject struct {
TypeMeta `json:",inline"`
ListMeta `json:"metadata,omitempty"`
}
func (c *clientImpl) watch(url string, labelSelector string, stopCh <-chan bool) (chan interface{}, chan error, error) {
watchCh := make(chan interface{}, 10)
errCh := make(chan error, 10)
// get version
body, err := c.do(c.request(url, ""))
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to do version request: GET %q : %v", url, err)
}
var generic GenericObject
if err := json.Unmarshal(body, &generic); err != nil {
return watchCh, errCh, fmt.Errorf("failed to decode version %v", err)
}
resourceVersion := generic.ResourceVersion
queryParams := map[string]string{"watch": "", "resourceVersion": resourceVersion}
queryData, err := makeQueryString(queryParams, labelSelector)
if err != nil {
return watchCh, errCh, fmt.Errorf("Unable to construct query args")
}
request := c.request(url, queryData)
req, err := request.MakeRequest()
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to make watch request: GET %q : %v", url, err)
}
request.Client.Transport = request.Transport
res, err := request.Client.Do(req)
if err != nil {
return watchCh, errCh, fmt.Errorf("failed to do watch request: GET %q: %v", url, err)
}
go func() {
finishCh := make(chan bool)
defer close(finishCh)
defer close(watchCh)
defer close(errCh)
go func() {
defer res.Body.Close()
for {
var eventList interface{}
if err := json.NewDecoder(res.Body).Decode(&eventList); err != nil {
if !strings.Contains(err.Error(), "net/http: request canceled") {
errCh <- fmt.Errorf("failed to decode watch event: GET %q : %v", url, err)
}
finishCh <- true
return
}
watchCh <- eventList
}
}()
select {
case <-stopCh:
go func() {
request.Transport.CancelRequest(req)
}()
<-finishCh
return
}
}()
return watchCh, errCh, nil
return &cache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc}
}

View file

@ -1,84 +0,0 @@
package k8s
// Endpoints is a collection of endpoints that implement the actual service. Example:
// Name: "mysvc",
// Subsets: [
// {
// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}],
// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}]
// },
// {
// Addresses: [{"ip": "10.10.3.3"}],
// Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}]
// },
// ]
type Endpoints struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`
// The set of all endpoints is the union of all subsets.
Subsets []EndpointSubset
}
// EndpointSubset is a group of addresses with a common set of ports. The
// expanded set of endpoints is the Cartesian product of Addresses x Ports.
// For example, given:
// {
// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}],
// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}]
// }
// The resulting set of endpoints can be viewed as:
// a: [ 10.10.1.1:8675, 10.10.2.2:8675 ],
// b: [ 10.10.1.1:309, 10.10.2.2:309 ]
type EndpointSubset struct {
Addresses []EndpointAddress
NotReadyAddresses []EndpointAddress
Ports []EndpointPort
}
// EndpointAddress is a tuple that describes single IP address.
type EndpointAddress struct {
// The IP of this endpoint.
// IPv6 is also accepted but not fully supported on all platforms. Also, certain
// kubernetes components, like kube-proxy, are not IPv6 ready.
// TODO: This should allow hostname or IP, see #4447.
IP string
// Optional: Hostname of this endpoint
// Meant to be used by DNS servers etc.
Hostname string `json:"hostname,omitempty"`
// Optional: The kubernetes object related to the entry point.
TargetRef *ObjectReference
}
// EndpointPort is a tuple that describes a single port.
type EndpointPort struct {
// The name of this port (corresponds to ServicePort.Name). Optional
// if only one port is defined. Must be a DNS_LABEL.
Name string
// The port number.
Port int32
// The IP protocol for this port.
Protocol Protocol
}
// ObjectReference contains enough information to let you inspect or modify the referred object.
type ObjectReference struct {
Kind string `json:"kind,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
UID UID `json:"uid,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
// Optional. If referring to a piece of an object instead of an entire object, this string
// should contain information to identify the sub-object. For example, if the object
// reference is to a container within a pod, this would take on a value like:
// "spec.containers{name}" (where "name" refers to the name of the container that triggered
// the event) or if no container name is specified "spec.containers[2]" (container with
// index 2 in this pod). This syntax is chosen only to have some well-defined way of
// referencing a part of an object.
// TODO: this design is not final and this field is subject to change in the future.
FieldPath string `json:"fieldPath,omitempty"`
}

View file

@ -1,151 +0,0 @@
package k8s
// Ingress is a collection of rules that allow inbound connections to reach the
// endpoints defined by a backend. An Ingress can be configured to give services
// externally-reachable urls, load balance traffic, terminate SSL, offer name
// based virtual hosting etc.
type Ingress struct {
TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
ObjectMeta `json:"metadata,omitempty"`
// Spec is the desired state of the Ingress.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
Spec IngressSpec `json:"spec,omitempty"`
// Status is the current state of the Ingress.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
Status IngressStatus `json:"status,omitempty"`
}
// IngressList is a collection of Ingress.
type IngressList struct {
TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
ListMeta `json:"metadata,omitempty"`
// Items is the list of Ingress.
Items []Ingress `json:"items"`
}
// IngressSpec describes the Ingress the user wishes to exist.
type IngressSpec struct {
// A default backend capable of servicing requests that don't match any
// rule. At least one of 'backend' or 'rules' must be specified. This field
// is optional to allow the loadbalancer controller or defaulting logic to
// specify a global default.
Backend *IngressBackend `json:"backend,omitempty"`
// TLS configuration. Currently the Ingress only supports a single TLS
// port, 443. If multiple members of this list specify different hosts, they
// will be multiplexed on the same port according to the hostname specified
// through the SNI TLS extension, if the ingress controller fulfilling the
// ingress supports SNI.
TLS []IngressTLS `json:"tls,omitempty"`
// A list of host rules used to configure the Ingress. If unspecified, or
// no rule matches, all traffic is sent to the default backend.
Rules []IngressRule `json:"rules,omitempty"`
// TODO: Add the ability to specify load-balancer IP through claims
}
// IngressTLS describes the transport layer security associated with an Ingress.
type IngressTLS struct {
// Hosts are a list of hosts included in the TLS certificate. The values in
// this list must match the name/s used in the tlsSecret. Defaults to the
// wildcard host setting for the loadbalancer controller fulfilling this
// Ingress, if left unspecified.
Hosts []string `json:"hosts,omitempty"`
// SecretName is the name of the secret used to terminate SSL traffic on 443.
// Field is left optional to allow SSL routing based on SNI hostname alone.
// If the SNI host in a listener conflicts with the "Host" header field used
// by an IngressRule, the SNI host is used for termination and value of the
// Host header is used for routing.
SecretName string `json:"secretName,omitempty"`
// TODO: Consider specifying different modes of termination, protocols etc.
}
// IngressStatus describe the current state of the Ingress.
type IngressStatus struct {
// LoadBalancer contains the current status of the load-balancer.
LoadBalancer LoadBalancerStatus `json:"loadBalancer,omitempty"`
}
// IngressRule represents the rules mapping the paths under a specified host to
// the related backend services. Incoming requests are first evaluated for a host
// match, then routed to the backend associated with the matching IngressRuleValue.
type IngressRule struct {
// Host is the fully qualified domain name of a network host, as defined
// by RFC 3986. Note the following deviations from the "host" part of the
// URI as defined in the RFC:
// 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the
// IP in the Spec of the parent Ingress.
// 2. The `:` delimiter is not respected because ports are not allowed.
// Currently the port of an Ingress is implicitly :80 for http and
// :443 for https.
// Both these may change in the future.
// Incoming requests are matched against the host before the IngressRuleValue.
// If the host is unspecified, the Ingress routes all traffic based on the
// specified IngressRuleValue.
Host string `json:"host,omitempty"`
// IngressRuleValue represents a rule to route requests for this IngressRule.
// If unspecified, the rule defaults to a http catch-all. Whether that sends
// just traffic matching the host to the default backend or all traffic to the
// default backend, is left to the controller fulfilling the Ingress. Http is
// currently the only supported IngressRuleValue.
IngressRuleValue `json:",inline,omitempty"`
}
// IngressRuleValue represents a rule to apply against incoming requests. If the
// rule is satisfied, the request is routed to the specified backend. Currently
// mixing different types of rules in a single Ingress is disallowed, so exactly
// one of the following must be set.
type IngressRuleValue struct {
//TODO:
// 1. Consider renaming this resource and the associated rules so they
// aren't tied to Ingress. They can be used to route intra-cluster traffic.
// 2. Consider adding fields for ingress-type specific global options
// usable by a loadbalancer, like http keep-alive.
HTTP *HTTPIngressRuleValue `json:"http,omitempty"`
}
// HTTPIngressRuleValue is a list of http selectors pointing to backends.
// In the example: http://<host>/<path>?<searchpart> -> backend where
// where parts of the url correspond to RFC 3986, this resource will be used
// to match against everything after the last '/' and before the first '?'
// or '#'.
type HTTPIngressRuleValue struct {
// A collection of paths that map requests to backends.
Paths []HTTPIngressPath `json:"paths"`
// TODO: Consider adding fields for ingress-type specific global
// options usable by a loadbalancer, like http keep-alive.
}
// HTTPIngressPath associates a path regex with a backend. Incoming urls matching
// the path are forwarded to the backend.
type HTTPIngressPath struct {
// Path is a extended POSIX regex as defined by IEEE Std 1003.1,
// (i.e this follows the egrep/unix syntax, not the perl syntax)
// matched against the path of an incoming request. Currently it can
// contain characters disallowed from the conventional "path"
// part of a URL as defined by RFC 3986. Paths must begin with
// a '/'. If unspecified, the path defaults to a catch all sending
// traffic to the backend.
Path string `json:"path,omitempty"`
// Backend defines the referenced service endpoint to which the traffic
// will be forwarded to.
Backend IngressBackend `json:"backend"`
}
// IngressBackend describes all endpoints for a given service and port.
type IngressBackend struct {
// Specifies the name of the referenced service.
ServiceName string `json:"serviceName"`
// Specifies the port of the referenced service.
ServicePort IntOrString `json:"servicePort"`
}

32
provider/k8s/namespace.go Normal file
View file

@ -0,0 +1,32 @@
package k8s
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 Namespaces(*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 = Namespaces(val.(Namespaces))
}

View file

@ -1,326 +0,0 @@
package k8s
import (
"encoding/json"
"strconv"
"time"
)
// TypeMeta describes an individual object in an API response or request
// with strings representing the type of the object and its API schema version.
// Structures that are versioned or persisted should inline TypeMeta.
type TypeMeta struct {
// Kind is a string value representing the REST resource this object represents.
// Servers may infer this from the endpoint the client submits requests to.
// Cannot be updated.
// In CamelCase.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
Kind string `json:"kind,omitempty"`
// APIVersion defines the versioned schema of this representation of an object.
// Servers should convert recognized schemas to the latest internal value, and
// may reject unrecognized values.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources
APIVersion string `json:"apiVersion,omitempty"`
}
// ObjectMeta is metadata that all persisted resources must have, which includes all objects
// users must create.
type ObjectMeta struct {
// Name is unique within a namespace. Name is required when creating resources, although
// some resources may allow a client to request the generation of an appropriate name
// automatically. Name is primarily intended for creation idempotence and configuration
// definition.
Name string `json:"name,omitempty"`
// GenerateName indicates that the name should be made unique by the server prior to persisting
// it. A non-empty value for the field indicates the name will be made unique (and the name
// returned to the client will be different than the name passed). The value of this field will
// be combined with a unique suffix on the server if the Name field has not been provided.
// The provided value must be valid within the rules for Name, and may be truncated by the length
// of the suffix required to make the value unique on the server.
//
// If this field is specified, and Name is not present, the server will NOT return a 409 if the
// generated name exists - instead, it will either return 201 Created or 500 with Reason
// ServerTimeout indicating a unique name could not be found in the time allotted, and the client
// should retry (optionally after the time indicated in the Retry-After header).
GenerateName string `json:"generateName,omitempty"`
// Namespace defines the space within which name must be unique. An empty namespace is
// equivalent to the "default" namespace, but "default" is the canonical representation.
// Not all objects are required to be scoped to a namespace - the value of this field for
// those objects will be empty.
Namespace string `json:"namespace,omitempty"`
// SelfLink is a URL representing this object.
SelfLink string `json:"selfLink,omitempty"`
// UID is the unique in time and space value for this object. It is typically generated by
// the server on successful creation of a resource and is not allowed to change on PUT
// operations.
UID UID `json:"uid,omitempty"`
// An opaque value that represents the version of this resource. May be used for optimistic
// concurrency, change detection, and the watch operation on a resource or set of resources.
// Clients must treat these values as opaque and values may only be valid for a particular
// resource or set of resources. Only servers will generate resource versions.
ResourceVersion string `json:"resourceVersion,omitempty"`
// A sequence number representing a specific generation of the desired state.
// Populated by the system. Read-only.
Generation int64 `json:"generation,omitempty"`
// CreationTimestamp is a timestamp representing the server time when this object was
// created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
CreationTimestamp Time `json:"creationTimestamp,omitempty"`
// DeletionTimestamp is the time after which this resource will be deleted. This
// field is set by the server when a graceful deletion is requested by the user, and is not
// directly settable by a client. The resource will be deleted (no longer visible from
// resource lists, and not reachable by name) after the time in this field. Once set, this
// value may not be unset or be set further into the future, although it may be shortened
// or the resource may be deleted prior to this time. For example, a user may request that
// a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination
// signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet
// will send a hard termination signal to the container.
DeletionTimestamp *Time `json:"deletionTimestamp,omitempty"`
// DeletionGracePeriodSeconds records the graceful deletion value set when graceful deletion
// was requested. Represents the most recent grace period, and may only be shortened once set.
DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"`
// Labels are key value pairs that may be used to scope and select individual resources.
// Label keys are of the form:
// label-key ::= prefixed-name | name
// prefixed-name ::= prefix '/' name
// prefix ::= DNS_SUBDOMAIN
// name ::= DNS_LABEL
// The prefix is optional. If the prefix is not specified, the key is assumed to be private
// to the user. Other system components that wish to use labels must specify a prefix. The
// "kubernetes.io/" prefix is reserved for use by kubernetes components.
// TODO: replace map[string]string with labels.LabelSet type
Labels map[string]string `json:"labels,omitempty"`
// Annotations are unstructured key value data stored with a resource that may be set by
// external tooling. They are not queryable and should be preserved when modifying
// objects. Annotation keys have the same formatting restrictions as Label keys. See the
// comments on Labels for details.
Annotations map[string]string `json:"annotations,omitempty"`
}
// UID is a type that holds unique ID values, including UUIDs. Because we
// don't ONLY use UUIDs, this is an alias to string. Being a type captures
// intent and helps make sure that UIDs and names do not get conflated.
type UID string
// Time is a wrapper around time.Time which supports correct
// marshaling to YAML and JSON. Wrappers are provided for many
// of the factory methods that the time package offers.
//
// +protobuf.options.marshal=false
// +protobuf.as=Timestamp
type Time struct {
time.Time `protobuf:"-"`
}
// Service is a named abstraction of software service (for example, mysql) consisting of local port
// (for example 3306) that the proxy listens on, and the selector that determines which pods
// will answer requests sent through the proxy.
type Service struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`
// Spec defines the behavior of a service.
Spec ServiceSpec `json:"spec,omitempty"`
// Status represents the current status of a service.
Status ServiceStatus `json:"status,omitempty"`
}
// ServiceSpec describes the attributes that a user creates on a service
type ServiceSpec struct {
// Type determines how the service will be exposed. Valid options: ClusterIP, NodePort, LoadBalancer
Type ServiceType `json:"type,omitempty"`
// Required: The list of ports that are exposed by this service.
Ports []ServicePort `json:"ports"`
// This service will route traffic to pods having labels matching this selector. If empty or not present,
// the service is assumed to have endpoints set by an external process and Kubernetes will not modify
// those endpoints.
Selector map[string]string `json:"selector"`
// ClusterIP is usually assigned by the master. If specified by the user
// we will try to respect it or else fail the request. This field can
// not be changed by updates.
// Valid values are None, empty string (""), or a valid IP address
// None can be specified for headless services when proxying is not required
ClusterIP string `json:"clusterIP,omitempty"`
// ExternalIPs are used by external load balancers, or can be set by
// users to handle external traffic that arrives at a node.
ExternalIPs []string `json:"externalIPs,omitempty"`
// Only applies to Service Type: LoadBalancer
// LoadBalancer will get created with the IP specified in this field.
// This feature depends on whether the underlying cloud-provider supports specifying
// the loadBalancerIP when a load balancer is created.
// This field will be ignored if the cloud-provider does not support the feature.
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
// Required: Supports "ClientIP" and "None". Used to maintain session affinity.
SessionAffinity ServiceAffinity `json:"sessionAffinity,omitempty"`
}
// ServicePort service port
type ServicePort struct {
// Optional if only one ServicePort is defined on this service: The
// name of this port within the service. This must be a DNS_LABEL.
// All ports within a ServiceSpec must have unique names. This maps to
// the 'Name' field in EndpointPort objects.
Name string `json:"name"`
// The IP protocol for this port. Supports "TCP" and "UDP".
Protocol Protocol `json:"protocol"`
// The port that will be exposed on the service.
Port int `json:"port"`
// Optional: The target port on pods selected by this service. If this
// is a string, it will be looked up as a named port in the target
// Pod's container ports. If this is not specified, the value
// of the 'port' field is used (an identity map).
// This field is ignored for services with clusterIP=None, and should be
// omitted or set equal to the 'port' field.
TargetPort IntOrString `json:"targetPort"`
// The port on each node on which this service is exposed.
// Default is to auto-allocate a port if the ServiceType of this Service requires one.
NodePort int `json:"nodePort"`
}
// ServiceStatus represents the current status of a service
type ServiceStatus struct {
// LoadBalancer contains the current status of the load-balancer,
// if one is present.
LoadBalancer LoadBalancerStatus `json:"loadBalancer,omitempty"`
}
// LoadBalancerStatus represents the status of a load-balancer
type LoadBalancerStatus struct {
// Ingress is a list containing ingress points for the load-balancer;
// traffic intended for the service should be sent to these ingress points.
Ingress []LoadBalancerIngress `json:"ingress,omitempty"`
}
// LoadBalancerIngress represents the status of a load-balancer ingress point:
// traffic intended for the service should be sent to an ingress point.
type LoadBalancerIngress struct {
// IP is set for load-balancer ingress points that are IP based
// (typically GCE or OpenStack load-balancers)
IP string `json:"ip,omitempty"`
// Hostname is set for load-balancer ingress points that are DNS based
// (typically AWS load-balancers)
Hostname string `json:"hostname,omitempty"`
}
// ServiceAffinity Session Affinity Type string
type ServiceAffinity string
// ServiceType Service Type string describes ingress methods for a service
type ServiceType string
// Protocol defines network protocols supported for things like container ports.
type Protocol string
// IntOrString is a type that can hold an int32 or a string. When used in
// JSON or YAML marshalling and unmarshalling, it produces or consumes the
// inner type. This allows you to have, for example, a JSON field that can
// accept a name or number.
// TODO: Rename to Int32OrString
//
// +protobuf=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
type IntOrString struct {
Type Type
IntVal int32
StrVal string
}
// FromInt creates an IntOrString object with an int32 value. It is
// your responsibility not to call this method with a value greater
// than int32.
// TODO: convert to (val int32)
func FromInt(val int) IntOrString {
return IntOrString{Type: Int, IntVal: int32(val)}
}
// FromString creates an IntOrString object with a string value.
func FromString(val string) IntOrString {
return IntOrString{Type: String, StrVal: val}
}
// String returns the string value, or the Itoa of the int value.
func (intstr *IntOrString) String() string {
if intstr.Type == String {
return intstr.StrVal
}
return strconv.Itoa(intstr.IntValue())
}
// IntValue returns the IntVal if type Int, or if
// it is a String, will attempt a conversion to int.
func (intstr *IntOrString) IntValue() int {
if intstr.Type == String {
i, _ := strconv.Atoi(intstr.StrVal)
return i
}
return int(intstr.IntVal)
}
// UnmarshalJSON implements the json.Unmarshaller interface.
func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
if value[0] == '"' {
intstr.Type = String
return json.Unmarshal(value, &intstr.StrVal)
}
intstr.Type = Int
return json.Unmarshal(value, &intstr.IntVal)
}
// Type represents the stored type of IntOrString.
type Type int
const (
// Int int
Int Type = iota // The IntOrString holds an int.
//String string
String // The IntOrString holds a string.
)
// ServiceList holds a list of services.
type ServiceList struct {
TypeMeta `json:",inline"`
ListMeta `json:"metadata,omitempty"`
Items []Service `json:"items"`
}
// ListMeta describes metadata that synthetic resources must have, including lists and
// various status objects. A resource may have only one of {ObjectMeta, ListMeta}.
type ListMeta struct {
// SelfLink is a URL representing this object.
// Populated by the system.
// Read-only.
SelfLink string `json:"selfLink,omitempty"`
// String that identifies the server's internal version of this object that
// can be used by clients to determine when objects have changed.
// Value must be treated as opaque by clients and passed unmodified back to the server.
// Populated by the system.
// Read-only.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency
ResourceVersion string `json:"resourceVersion,omitempty"`
}

View file

@ -1,55 +1,24 @@
package provider
import (
"fmt"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"text/template"
"time"
"k8s.io/client-go/1.5/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/util/intstr"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/cenk/backoff"
"github.com/containous/traefik/job"
)
const (
serviceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token"
serviceAccountCACert = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
defaultKubeEndpoint = "http://127.0.0.1:8080"
)
// 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 Namespaces(*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 = Namespaces(val.(Namespaces))
}
var _ Provider = (*Kubernetes)(nil)
// Kubernetes holds configurations of the Kubernetes provider.
@ -57,45 +26,24 @@ type Kubernetes struct {
BaseProvider `mapstructure:",squash"`
Endpoint string `description:"Kubernetes server endpoint"`
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers"`
Namespaces Namespaces `description:"Kubernetes namespaces"`
Namespaces k8s.Namespaces `description:"Kubernetes namespaces"`
LabelSelector string `description:"Kubernetes api label selector to use"`
lastConfiguration safe.Safe
}
func (provider *Kubernetes) createClient() (k8s.Client, error) {
var token string
tokenBytes, err := ioutil.ReadFile(serviceAccountToken)
if err == nil {
token = string(tokenBytes)
log.Debugf("Kubernetes token: %s", token)
} else {
log.Errorf("Kubernetes load token error: %s", err)
func (provider *Kubernetes) newK8sClient() (k8s.Client, error) {
if provider.Endpoint != "" {
log.Infof("Creating in cluster Kubernetes client with endpoint %", provider.Endpoint)
return k8s.NewInClusterClientWithEndpoint(provider.Endpoint)
}
caCert, err := ioutil.ReadFile(serviceAccountCACert)
if err == nil {
log.Debugf("Kubernetes CA cert: %s", serviceAccountCACert)
} else {
log.Errorf("Kubernetes load token error: %s", err)
}
kubernetesHost := os.Getenv("KUBERNETES_SERVICE_HOST")
kubernetesPort := os.Getenv("KUBERNETES_SERVICE_PORT_HTTPS")
// Prioritize user provided kubernetes endpoint since kube container runtime will almost always have it
if provider.Endpoint == "" && len(kubernetesPort) > 0 && len(kubernetesHost) > 0 {
log.Debugf("Using environment provided kubernetes endpoint")
provider.Endpoint = "https://" + kubernetesHost + ":" + kubernetesPort
}
if provider.Endpoint == "" {
log.Debugf("Using default kubernetes api endpoint")
provider.Endpoint = defaultKubeEndpoint
}
log.Debugf("Kubernetes endpoint: %s", provider.Endpoint)
return k8s.NewClient(provider.Endpoint, caCert, token)
log.Info("Creating in cluster Kubernetes client")
return k8s.NewInClusterClient()
}
// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
k8sClient, err := provider.createClient()
k8sClient, err := provider.newK8sClient()
if err != nil {
return err
}
@ -107,7 +55,7 @@ func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage
stopWatch := make(chan bool, 5)
defer close(stopWatch)
log.Debugf("Using label selector: '%s'", provider.LabelSelector)
eventsChan, errEventsChan, err := k8sClient.WatchAll(provider.LabelSelector, stopWatch)
eventsChan, err := k8sClient.WatchAll(provider.LabelSelector, stopWatch)
if err != nil {
log.Errorf("Error watching kubernetes events: %v", err)
timer := time.NewTimer(1 * time.Second)
@ -123,9 +71,6 @@ func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage
case <-stop:
stopWatch <- true
return nil
case err, _ := <-errEventsChan:
stopWatch <- true
return err
case event := <-eventsChan:
log.Debugf("Received event from kubernetes %+v", event)
templateObjects, err := provider.loadIngresses(k8sClient)
@ -155,39 +100,12 @@ func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage
}
})
templateObjects, err := provider.loadIngresses(k8sClient)
if err != nil {
return err
}
if reflect.DeepEqual(provider.lastConfiguration.Get(), templateObjects) {
log.Debugf("Skipping configuration from kubernetes %+v", templateObjects)
} else {
provider.lastConfiguration.Set(templateObjects)
configurationChan <- types.ConfigMessage{
ProviderName: "kubernetes",
Configuration: provider.loadConfig(*templateObjects),
}
}
return nil
}
func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configuration, error) {
ingresses, err := k8sClient.GetIngresses(provider.LabelSelector, func(ingress k8s.Ingress) bool {
if len(provider.Namespaces) == 0 {
return true
}
for _, n := range provider.Namespaces {
if ingress.ObjectMeta.Namespace == n {
return true
}
}
return false
})
if err != nil {
log.Errorf("Error retrieving ingresses: %+v", err)
return nil, err
}
ingresses := k8sClient.GetIngresses(provider.Namespaces)
templateObjects := types.Configuration{
map[string]*types.Backend{},
map[string]*types.Frontend{},
@ -239,28 +157,28 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur
Rule: ruleType + ":" + pa.Path,
}
}
service, err := k8sClient.GetService(pa.Backend.ServiceName, i.ObjectMeta.Namespace)
if err != nil {
log.Warnf("Error retrieving services: %v", err)
service, exists, err := k8sClient.GetService(i.ObjectMeta.Namespace, pa.Backend.ServiceName)
if err != nil || !exists {
log.Warnf("Error retrieving service %s/%s: %v", i.ObjectMeta.Namespace, pa.Backend.ServiceName, err)
delete(templateObjects.Frontends, r.Host+pa.Path)
log.Warnf("Error retrieving services %s", pa.Backend.ServiceName)
continue
}
protocol := "http"
for _, port := range service.Spec.Ports {
if equalPorts(port, pa.Backend.ServicePort) {
if port.Port == 443 {
protocol = "https"
}
endpoints, err := k8sClient.GetEndpoints(service.ObjectMeta.Name, service.ObjectMeta.Namespace)
if err != nil {
log.Errorf("Error retrieving endpoints: %v", err)
endpoints, exists, err := k8sClient.GetEndpoints(service.ObjectMeta.Namespace, service.ObjectMeta.Name)
if err != nil || !exists {
log.Errorf("Error retrieving endpoints %s/%s: %v", service.ObjectMeta.Namespace, service.ObjectMeta.Name, err)
continue
}
if len(endpoints.Subsets) == 0 {
log.Warnf("Endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name)
templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{
URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(port.Port),
URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(int(port.Port)),
Weight: 1,
}
} else {
@ -287,7 +205,7 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur
return &templateObjects, nil
}
func endpointPortNumber(servicePort k8s.ServicePort, endpointPorts []k8s.EndpointPort) int {
func endpointPortNumber(servicePort v1.ServicePort, endpointPorts []v1.EndpointPort) int {
if len(endpointPorts) > 0 {
//name is optional if there is only one port
port := endpointPorts[0]
@ -298,11 +216,11 @@ func endpointPortNumber(servicePort k8s.ServicePort, endpointPorts []k8s.Endpoin
}
return int(port.Port)
}
return servicePort.Port
return int(servicePort.Port)
}
func equalPorts(servicePort k8s.ServicePort, ingressPort k8s.IntOrString) bool {
if servicePort.Port == ingressPort.IntValue() {
func equalPorts(servicePort v1.ServicePort, ingressPort intstr.IntOrString) bool {
if int(servicePort.Port) == ingressPort.IntValue() {
return true
}
if servicePort.Name != "" && servicePort.Name == ingressPort.String() {

View file

@ -2,29 +2,34 @@ package provider
import (
"encoding/json"
"github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/types"
"reflect"
"testing"
"k8s.io/client-go/1.5/pkg/api/v1"
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/1.5/pkg/util/intstr"
"github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/types"
)
func TestLoadIngresses(t *testing.T) {
ingresses := []k8s.Ingress{{
ObjectMeta: k8s.ObjectMeta{
ingresses := []*v1beta1.Ingress{{
ObjectMeta: v1.ObjectMeta{
Namespace: "testing",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(80),
ServicePort: intstr.FromInt(80),
},
},
},
@ -33,19 +38,19 @@ func TestLoadIngresses(t *testing.T) {
},
{
Host: "bar",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service3",
ServicePort: k8s.FromString("https"),
ServicePort: intstr.FromString("https"),
},
},
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service2",
ServicePort: k8s.FromInt(802),
ServicePort: intstr.FromInt(802),
},
},
},
@ -55,16 +60,16 @@ func TestLoadIngresses(t *testing.T) {
},
},
}}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
UID: "1",
Namespace: "testing",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Port: 80,
},
@ -72,14 +77,14 @@ func TestLoadIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service2",
UID: "2",
Namespace: "testing",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.2",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Port: 802,
},
@ -87,14 +92,14 @@ func TestLoadIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service3",
UID: "3",
Namespace: "testing",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.3",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 80,
@ -107,33 +112,33 @@ func TestLoadIngresses(t *testing.T) {
},
},
}
endpoints := []k8s.Endpoints{
endpoints := []*v1.Endpoints{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
UID: "1",
Namespace: "testing",
},
Subsets: []k8s.EndpointSubset{
Subsets: []v1.EndpointSubset{
{
Addresses: []k8s.EndpointAddress{
Addresses: []v1.EndpointAddress{
{
IP: "10.10.0.1",
},
},
Ports: []k8s.EndpointPort{
Ports: []v1.EndpointPort{
{
Port: 8080,
},
},
},
{
Addresses: []k8s.EndpointAddress{
Addresses: []v1.EndpointAddress{
{
IP: "10.21.0.1",
},
},
Ports: []k8s.EndpointPort{
Ports: []v1.EndpointPort{
{
Port: 8080,
},
@ -142,19 +147,19 @@ func TestLoadIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service3",
UID: "3",
Namespace: "testing",
},
Subsets: []k8s.EndpointSubset{
Subsets: []v1.EndpointSubset{
{
Addresses: []k8s.EndpointAddress{
Addresses: []v1.EndpointAddress{
{
IP: "10.15.0.1",
},
},
Ports: []k8s.EndpointPort{
Ports: []v1.EndpointPort{
{
Name: "http",
Port: 8080,
@ -166,12 +171,12 @@ func TestLoadIngresses(t *testing.T) {
},
},
{
Addresses: []k8s.EndpointAddress{
Addresses: []v1.EndpointAddress{
{
IP: "10.15.0.2",
},
},
Ports: []k8s.EndpointPort{
Ports: []v1.EndpointPort{
{
Name: "http",
Port: 9080,
@ -267,23 +272,23 @@ func TestLoadIngresses(t *testing.T) {
}
func TestRuleType(t *testing.T) {
ingresses := []k8s.Ingress{
ingresses := []*v1beta1.Ingress{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Annotations: map[string]string{"traefik.frontend.rule.type": "PathPrefixStrip"}, //camel case
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo1",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar1",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -294,21 +299,21 @@ func TestRuleType(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Annotations: map[string]string{"traefik.frontend.rule.type": "path"}, //lower case
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo1",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar2",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -319,21 +324,21 @@ func TestRuleType(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Annotations: map[string]string{"traefik.frontend.rule.type": "PathPrefix"}, //path prefix
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo2",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar1",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -344,21 +349,21 @@ func TestRuleType(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Annotations: map[string]string{"traefik.frontend.rule.type": "PathStrip"}, //path strip
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo2",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar2",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -369,21 +374,21 @@ func TestRuleType(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Annotations: map[string]string{"traefik.frontend.rule.type": "PathXXStrip"}, //wrong rule
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo1",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar3",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -394,15 +399,15 @@ func TestRuleType(t *testing.T) {
},
},
}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -495,22 +500,22 @@ func TestRuleType(t *testing.T) {
}
func TestGetPassHostHeader(t *testing.T) {
ingresses := []k8s.Ingress{{
ObjectMeta: k8s.ObjectMeta{
ingresses := []*v1beta1.Ingress{{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -520,16 +525,16 @@ func TestGetPassHostHeader(t *testing.T) {
},
},
}}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
Namespace: "awesome",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -587,22 +592,22 @@ func TestGetPassHostHeader(t *testing.T) {
}
func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
ingresses := []k8s.Ingress{
ingresses := []*v1beta1.Ingress{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service",
ServicePort: k8s.FromInt(80),
ServicePort: intstr.FromInt(80),
},
},
},
@ -613,16 +618,16 @@ func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
},
},
}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service",
UID: "1",
Namespace: "awesome",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 80,
@ -631,14 +636,14 @@ func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service",
UID: "2",
Namespace: "not-awesome",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.2",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 80,
@ -693,23 +698,23 @@ func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
}
func TestLoadNamespacedIngresses(t *testing.T) {
ingresses := []k8s.Ingress{
ingresses := []*v1beta1.Ingress{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -718,19 +723,19 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
{
Host: "bar",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service3",
ServicePort: k8s.FromInt(443),
ServicePort: intstr.FromInt(443),
},
},
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service2",
ServicePort: k8s.FromInt(802),
ServicePort: intstr.FromInt(802),
},
},
},
@ -741,21 +746,21 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "not-awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "baz",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/baz",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -766,16 +771,16 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
},
}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
Name: "service1",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -784,14 +789,14 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
Namespace: "not-awesome",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -800,14 +805,14 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service2",
Namespace: "awesome",
UID: "2",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.2",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Port: 802,
},
@ -815,14 +820,14 @@ func TestLoadNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service3",
Namespace: "awesome",
UID: "3",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.3",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 443,
@ -906,23 +911,23 @@ func TestLoadNamespacedIngresses(t *testing.T) {
}
func TestLoadMultipleNamespacedIngresses(t *testing.T) {
ingresses := []k8s.Ingress{
ingresses := []*v1beta1.Ingress{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -931,19 +936,19 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
{
Host: "bar",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service3",
ServicePort: k8s.FromInt(443),
ServicePort: intstr.FromInt(443),
},
},
{
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service2",
ServicePort: k8s.FromInt(802),
ServicePort: intstr.FromInt(802),
},
},
},
@ -954,21 +959,21 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "somewhat-awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "awesome",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/quix",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -979,21 +984,21 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "not-awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "baz",
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/baz",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -1004,16 +1009,16 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
Namespace: "awesome",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -1022,14 +1027,14 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "somewhat-awesome",
Name: "service1",
UID: "17",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.4",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -1038,14 +1043,14 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
Name: "service2",
UID: "2",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.2",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Port: 802,
},
@ -1053,14 +1058,14 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
},
},
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
Name: "service3",
UID: "3",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.3",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 443,
@ -1167,21 +1172,21 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
}
func TestHostlessIngress(t *testing.T) {
ingresses := []k8s.Ingress{{
ObjectMeta: k8s.ObjectMeta{
ingresses := []*v1beta1.Ingress{{
ObjectMeta: v1.ObjectMeta{
Namespace: "awesome",
},
Spec: k8s.IngressSpec{
Rules: []k8s.IngressRule{
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
IngressRuleValue: k8s.IngressRuleValue{
HTTP: &k8s.HTTPIngressRuleValue{
Paths: []k8s.HTTPIngressPath{
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: k8s.IngressBackend{
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: k8s.FromInt(801),
ServicePort: intstr.FromInt(801),
},
},
},
@ -1191,16 +1196,16 @@ func TestHostlessIngress(t *testing.T) {
},
},
}}
services := []k8s.Service{
services := []*v1.Service{
{
ObjectMeta: k8s.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
Namespace: "awesome",
UID: "1",
},
Spec: k8s.ServiceSpec{
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Ports: []k8s.ServicePort{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 801,
@ -1255,42 +1260,45 @@ func TestHostlessIngress(t *testing.T) {
}
type clientMock struct {
ingresses []k8s.Ingress
services []k8s.Service
endpoints []k8s.Endpoints
ingresses []*v1beta1.Ingress
services []*v1.Service
endpoints []*v1.Endpoints
watchChan chan interface{}
}
func (c clientMock) GetIngresses(labelString string, predicate func(k8s.Ingress) bool) ([]k8s.Ingress, error) {
var ingresses []k8s.Ingress
func (c clientMock) GetIngresses(namespaces k8s.Namespaces) []*v1beta1.Ingress {
result := make([]*v1beta1.Ingress, 0, len(c.ingresses))
for _, ingress := range c.ingresses {
if predicate(ingress) {
ingresses = append(ingresses, ingress)
if k8s.HasNamespace(ingress, namespaces) {
result = append(result, ingress)
}
}
return ingresses, nil
return result
}
func (c clientMock) WatchIngresses(labelString string, predicate func(k8s.Ingress) bool, stopCh <-chan bool) (chan interface{}, chan error, error) {
return c.watchChan, make(chan error), nil
func (c clientMock) WatchIngresses(labelSelector string, stopCh <-chan struct{}) chan interface{} {
return c.watchChan
}
func (c clientMock) GetService(name, namespace string) (k8s.Service, error) {
func (c clientMock) GetService(namespace, name string) (*v1.Service, bool, error) {
for _, service := range c.services {
if service.Namespace == namespace && service.Name == name {
return service, nil
return service, true, nil
}
}
return k8s.Service{}, nil
return &v1.Service{}, true, nil
}
func (c clientMock) GetEndpoints(name, namespace string) (k8s.Endpoints, error) {
func (c clientMock) GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error) {
for _, endpoints := range c.endpoints {
if endpoints.Namespace == namespace && endpoints.Name == name {
return endpoints, nil
return endpoints, true, nil
}
}
return k8s.Endpoints{}, nil
return &v1.Endpoints{}, true, nil
}
func (c clientMock) WatchAll(labelString string, stopCh <-chan bool) (chan interface{}, chan error, error) {
return c.watchChan, make(chan error), nil
func (c clientMock) WatchAll(labelString string, stopCh <-chan bool) (chan interface{}, error) {
return c.watchChan, nil
}

View file

@ -19,7 +19,7 @@ import (
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/docker/libkv/store"
@ -144,7 +144,7 @@ Complete documentation is available at https://traefik.io`,
f.AddParser(reflect.TypeOf(EntryPoints{}), &EntryPoints{})
f.AddParser(reflect.TypeOf(DefaultEntryPoints{}), &DefaultEntryPoints{})
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
f.AddParser(reflect.TypeOf(provider.Namespaces{}), &provider.Namespaces{})
f.AddParser(reflect.TypeOf(k8s.Namespaces{}), &k8s.Namespaces{})
f.AddParser(reflect.TypeOf([]acme.Domain{}), &acme.Domains{})
//add commands