Add Source implementation for Istio Gateway (#694)

* add Istio Gateway Source

* add documentation for Istio Gateway Source

* make both istio namespace and ingress gateway service configurable

* prefix gateway types, constructors, and flags with 'istio-'

* fix: add missing sources to source flag docs
This commit is contained in:
Jonas Michel 2018-09-06 09:39:32 -05:00 committed by Martin Linkhorst
parent a7ac4f9b1e
commit b9b6842195
13 changed files with 2128 additions and 153 deletions

349
Gopkg.lock generated
View File

@ -2,7 +2,7 @@
[[projects]]
digest = "1:e94ea655a0038d2274be202f77a2ea0eb2d3f74dfee674fd5d1f541e81008039"
digest = "1:ae9d0182a5cf7dbb025a8fc5821234cc1f26ca342fc41d951a99f71b9adc1b87"
name = "cloud.google.com/go"
packages = [
"compute/metadata",
@ -12,7 +12,7 @@
revision = "3b1ae45394a234c385be014e9a488f2bb6eef821"
[[projects]]
digest = "1:b341fb465b057e991b166d073b35a224f5a84228e5ef7e40b4da7a70c152e7ec"
digest = "1:fd38e3b8c27cab6561a7d2e8557205c3ca5c57cbb6d3a79e10f22e73e84fd776"
name = "github.com/Azure/azure-sdk-for-go"
packages = ["arm/dns"]
pruneopts = ""
@ -20,7 +20,7 @@
version = "v10.0.4-beta"
[[projects]]
digest = "1:767f5f5dd4fa8e4f7f206726361d29aa0f7622b0bb8294b73d071864368c0d6b"
digest = "1:f719ef698feb8da2923ebda9a8d553b977320b02182f3797e185202e588a94b1"
name = "github.com/Azure/go-autorest"
packages = [
"autorest",
@ -34,7 +34,7 @@
version = "v10.9.0"
[[projects]]
digest = "1:283a95024c33e84b23f24b1b47e3157ff2df2517d786a2e17bb0e6e4955e94e4"
digest = "1:7dc69d1597e4773ec5f64e5c078d55f0f011bb05ec0435346d0649ad978a23fd"
name = "github.com/alecthomas/kingpin"
packages = ["."]
pruneopts = ""
@ -43,7 +43,7 @@
[[projects]]
branch = "master"
digest = "1:1399282ad03ac819f0e8a747c888407c5c98bb497d33821a7047c7bae667ede0"
digest = "1:a74730e052a45a3fab1d310fdef2ec17ae3d6af16228421e238320846f2aaec8"
name = "github.com/alecthomas/template"
packages = [
".",
@ -61,7 +61,7 @@
revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
[[projects]]
digest = "1:7b6c017b0290ccf1dd98c47a51e1db8b72b0863b6c7c52ddaa5a0d894aa3c2fc"
digest = "1:d2dc5d0ccc137594ea6fb3870964967b96b43daac19b8093930c7b02873fd5ca"
name = "github.com/aliyun/alibaba-cloud-sdk-go"
packages = [
"sdk",
@ -81,7 +81,7 @@
version = "1.27.7"
[[projects]]
digest = "1:f04a72eefe1c7adec1dce30e099cec1e5fea8903a66e2db25bbbdfa66915428d"
digest = "1:1c82dd6a02941a3c4f23a32eca182717ab79691939e97d6b971466b780f06eea"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
@ -121,14 +121,14 @@
[[projects]]
branch = "master"
digest = "1:d20bdb6bf44087574af3139835946875bb098440426785282c741865b7bc66d3"
digest = "1:0c5485088ce274fac2e931c1b979f2619345097b39d91af3239977114adf0320"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = ""
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
[[projects]]
digest = "1:d9d9c71f9776ef8f15b5c0a20246d5303071294743863ac3f4dde056f8c7b40a"
digest = "1:85fd00554a6ed5b33687684b76635d532c74141508b5bce2843d85e8a3c9dc91"
name = "github.com/cloudflare/cloudflare-go"
packages = ["."]
pruneopts = ""
@ -136,7 +136,7 @@
version = "v0.7.4"
[[projects]]
digest = "1:31259dbcb4c073aace59b951f5b471b3d5dbc4051b4a9d7e000f4392e143977e"
digest = "1:eaeede87b418b97f9dee473f8940fd9b65ca5cdac0503350c7c8f8965ea3cf4d"
name = "github.com/coreos/etcd"
packages = [
"client",
@ -158,7 +158,7 @@
version = "v0.2.0"
[[projects]]
digest = "1:0a39ec8bf5629610a4bc7873a92039ee509246da3cef1a0ea60f1ed7e5f9cea5"
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = ""
@ -167,7 +167,7 @@
[[projects]]
branch = "master"
digest = "1:64ee6871ef691c663f910e29bc2f7c10c8c342b06665920f1138b6aa8b11cb5a"
digest = "1:dc166ce7345c060c2153561130d6d49ac580c804226ac675e368d533b36eb169"
name = "github.com/denverdino/aliyungo"
packages = [
"metadata",
@ -177,7 +177,7 @@
revision = "69560d9530f5265ba00ffad2520d7ef01c2cddd4"
[[projects]]
digest = "1:2426da75f49e5b8507a6ed5d4c49b06b2ff795f4aec401c106b7db8fb2625cd7"
digest = "1:6098222470fe0172157ce9bbef5d2200df4edde17ee649c5d6e48330e4afa4c6"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = ""
@ -185,7 +185,7 @@
version = "v3.2.0"
[[projects]]
digest = "1:3da5806ef37ea163fee80ed179d40a5e013e671ccbe321a04c47c5aee3d5080a"
digest = "1:32d1941b093bb945de75b0276348494be318d34f3df39c4413d61e002c800bc6"
name = "github.com/digitalocean/godo"
packages = [
".",
@ -196,7 +196,7 @@
version = "v1.1.1"
[[projects]]
digest = "1:ca3b228bf258217cff2070f4045e53729886c66a27bf9cce30dcbf8a575ea86a"
digest = "1:5ffd39844bdd1259a6227d544f582c6686ce43c8c44399a46052fe3bd2bed93c"
name = "github.com/dnsimple/dnsimple-go"
packages = ["dnsimple"]
pruneopts = ""
@ -204,7 +204,7 @@
version = "v0.14.0"
[[projects]]
digest = "1:bfce2cc5b829073f93962e742275d45913948e22d182fbc5464104da1c5f2f89"
digest = "1:e17d18b233f506404061c27ac4a08624dad38dcd0d49f9cfdae67a7772a4fb8c"
name = "github.com/exoscale/egoscale"
packages = ["."]
pruneopts = ""
@ -213,21 +213,22 @@
[[projects]]
branch = "master"
digest = "1:bc12846e4bae094e01a33ef98cad0a1afa35da37090e5126513be6f747e074ab"
digest = "1:ae7fb2062735e966ab69d14d2a091f3778b0d676dc8d1f01d092bcb0fb8ed45b"
name = "github.com/ffledgling/pdns-go"
packages = ["."]
pruneopts = ""
revision = "524e7daccd99651cdb56426eb15b7d61f9597a5c"
[[projects]]
digest = "1:a31fbb19d2b38d50bc125d97b7c3e7a286d3f6f37d18756011eb6e7d1a9fa7d0"
digest = "1:b13707423743d41665fd23f0c36b2f37bb49c30e94adb813319c44188a51ba22"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = ""
revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
digest = "1:bbc763f3c703dc3c6a99a22c1318760099b52bc00a47a36dc4462e88eee7846b"
digest = "1:a00483fe4106b86fb1187a92b5cf6915c85f294ed4c129ccbe7cb1f1a06abd46"
name = "github.com/go-ini/ini"
packages = ["."]
pruneopts = ""
@ -235,7 +236,7 @@
version = "v1.32.0"
[[projects]]
digest = "1:cdeb6a9eb9f2356b2987c401d013d41e018b819ee1e8d5a1b32a5b714e53c392"
digest = "1:8e67153fc0a9fb0d6c9707e36cf80e217a012364307b222eb4ba6828f7e881e6"
name = "github.com/go-resty/resty"
packages = ["."]
pruneopts = ""
@ -243,11 +244,23 @@
version = "v1.8.0"
[[projects]]
digest = "1:673df1d02ca0c6f51458fe94bbb6fae0b05e54084a31db2288f1c4321255c2da"
digest = "1:54d5c6a784a9de9c836fc070d51d0689c3e99ee6d24dba8a36f0762039dae830"
name = "github.com/gogo/googleapis"
packages = ["google/rpc"]
pruneopts = ""
revision = "8558fb44d2f1fc223118afc694129d2c2d2924d1"
version = "v1.1.0"
[[projects]]
digest = "1:6e73003ecd35f4487a5e88270d3ca0a81bc80dc88053ac7e4dcfec5fba30d918"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
"jsonpb",
"proto",
"protoc-gen-gogo/descriptor",
"sortkeys",
"types",
]
pruneopts = ""
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
@ -261,17 +274,20 @@
revision = "44145f04b68cf362d9c4df2182967c2275eaefed"
[[projects]]
digest = "1:4321edcf693514c7a3811c9b58a19705ef0b4aaec5ee4e5baa2f5c07ad3b96ae"
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
name = "github.com/golang/protobuf"
packages = [
"jsonpb",
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/struct",
"ptypes/timestamp",
]
pruneopts = ""
revision = "8616e8ee5e20a1704615e6c8d7afcdac06087a67"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -297,7 +313,7 @@
revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c"
[[projects]]
digest = "1:1962b5d00f5285d08504697049627d45ad876912894528d31cdc1c05cdc853f6"
digest = "1:16b2837c8b3cf045fa2cdc82af0cf78b19582701394484ae76b2c3bc3c99ad73"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
@ -310,7 +326,7 @@
[[projects]]
branch = "master"
digest = "1:815036d12757902f85888f3cb0440c2e00220dd4177e4c2bb048e03259db077a"
digest = "1:54a44d48a24a104e078ef5f94d82f025a6be757e7c42b4370c621a3928d6ab7c"
name = "github.com/gophercloud/gophercloud"
packages = [
".",
@ -326,9 +342,25 @@
pruneopts = ""
revision = "bfc4756e1a693a850d7d459f4b28b21f35a24b5a"
[[projects]]
digest = "1:dbbeb8ddb0be949954c8157ee8439c2adfd8dc1c9510eb44a6e58cb68c3dce28"
name = "github.com/gorilla/context"
packages = ["."]
pruneopts = ""
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1"
[[projects]]
digest = "1:c2c8666b4836c81a1d247bdf21c6a6fc1ab586538ab56f74437c2e0df5c375e1"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = ""
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
branch = "master"
digest = "1:8c4d156acec272201ffc4d1bdb9302de1c48314e0451eb38c70150cf11bdb33a"
digest = "1:009a1928b8c096338b68b5822d838a72b4d8520715c1463614476359f3282ec8"
name = "github.com/gregjones/httpcache"
packages = [
".",
@ -337,6 +369,33 @@
pruneopts = ""
revision = "9cad4c3443a7200dd6400aef47183728de563a38"
[[projects]]
digest = "1:8e3bd93036b4a925fe2250d3e4f38f21cadb8ef623561cd80c3c50c114b13201"
name = "github.com/hashicorp/errwrap"
packages = ["."]
pruneopts = ""
revision = "8a6fb523712970c966eefc6b39ed2c5e74880354"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:72308fdd6d5ef61106a95be7ca72349a5565809042b6426a3cfb61d99483b824"
name = "github.com/hashicorp/go-multierror"
packages = ["."]
pruneopts = ""
revision = "886a7fbe3eb1c874d46f623bfa70af45f425b3d1"
[[projects]]
digest = "1:3313a63031ae281e5f6fd7b0bbca733dfa04d2429df86519e3b4d4c016ccb836"
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru",
]
pruneopts = ""
revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768"
version = "v0.5.0"
[[projects]]
digest = "1:af7e132906cb360f4d7c34a9e1434825467f21c4ff5c521ad4cc5b55352876a8"
name = "github.com/imdario/mergo"
@ -344,6 +403,14 @@
pruneopts = ""
revision = "6633656539c1639d9d78127b7d47c622b5d7b6dc"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = ""
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
branch = "master"
digest = "1:e0a13d0a368c028716e78448db972657b5292c7238d61405e8289f47c05c8706"
@ -353,14 +420,14 @@
revision = "61dc5f9b0a655ebf43026f0d8a837ad1e28e4b96"
[[projects]]
digest = "1:4f767a115bc8e08576f6d38ab73c376fc1b1cd3bb5041171c9e8668cc7739b52"
digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e"
name = "github.com/jmespath/go-jmespath"
packages = ["."]
pruneopts = ""
revision = "0b12d6b5"
[[projects]]
digest = "1:890dd7615573f096655600bbe7beb2f532a437f6d8ef237831894301fca31f23"
digest = "1:53ac4e911e12dde0ab68655e2006449d207a5a681f084974da2b06e5dbeaca72"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = ""
@ -368,14 +435,14 @@
version = "1.1.4"
[[projects]]
digest = "1:def40684a573560241c8344da452fa3574dfc2c7da525903992a3790d2262625"
digest = "1:1c88ec29544b281964ed7a9a365b2802a523cd06c50cdee87eb3eec89cd864f4"
name = "github.com/kubernetes/repo-infra"
packages = ["verify/boilerplate/test"]
pruneopts = ""
revision = "c2f9667a4c29e70a39b0e89db2d4f0cab907dbee"
[[projects]]
digest = "1:c3aa5f9d5119ca1cfdaa41a5084e3deceef0460eef3e6c71b58fa50e500f01a0"
digest = "1:7c23a751ce2f84663fa411acb87eae0da2d09c39a8e99b08bd8f65fae75d8928"
name = "github.com/linki/instrumented_http"
packages = ["."]
pruneopts = ""
@ -383,7 +450,7 @@
version = "v0.2.0"
[[projects]]
digest = "1:93d29291d0c37678592d77ee847031aec2ce1631f3ce4cf975b77216e8bd4a01"
digest = "1:1c41354ef11c9dbae2fe1ceee8369fcb2634977ba07e701e19ea53e8742c5420"
name = "github.com/linode/linodego"
packages = ["."]
pruneopts = ""
@ -392,7 +459,7 @@
[[projects]]
branch = "master"
digest = "1:49a8b01a6cd6558d504b65608214ca40a78000e1b343ed0da5c6a9ccd83d6d30"
digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = ""
@ -415,7 +482,15 @@
version = "1.0.1"
[[projects]]
digest = "1:7aef6d4ad1b4a613d66ed554010c552a249e9afabcb079f54528a298474549cc"
digest = "1:11c58e19ff7ce22740423bb933f1ddca3bf575def40d5ac3437ec12871b1648b"
name = "github.com/natefinch/lumberjack"
packages = ["."]
pruneopts = ""
revision = "a96e63847dc3c67d17befa69c303767e2f84e54f"
version = "v2.1"
[[projects]]
digest = "1:d8b5d0ecca348c835914a1ed8589f17a6a7f309befab7327b0470324531f7ac4"
name = "github.com/nesv/go-dynect"
packages = ["dynect"]
pruneopts = ""
@ -423,7 +498,7 @@
version = "v0.6.0"
[[projects]]
digest = "1:2062e45c462d0327f680340dce46fe11ae2d34bf802e15e397cb1d6c4d159b39"
digest = "1:70df8e71a953626770223d4982801fa73e7e99cbfcca068b95127f72af9b9edd"
name = "github.com/oracle/oci-go-sdk"
packages = [
"common",
@ -435,14 +510,14 @@
[[projects]]
branch = "master"
digest = "1:b7be9a944fe102bf466420fa8a064534dd12547a0482f5b684d228425b559b56"
digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc"
name = "github.com/petar/GoLLRB"
packages = ["llrb"]
pruneopts = ""
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]]
digest = "1:6db21ad64a13fe79220e47fcc895e13b8da923676a3a024f98210fca57a10d9a"
digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f"
name = "github.com/peterbourgon/diskv"
packages = ["."]
pruneopts = ""
@ -465,19 +540,19 @@
version = "v1.0.0"
[[projects]]
digest = "1:981835985f655d1d380cc6aa7d9fa9ad7abfaf40c75da200fd40d864cd05a7c3"
digest = "1:2f69dc6b2685b31a1a410ef697410aa8a669704fb201d45dbd8c1911728afa75"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/promhttp",
]
pruneopts = ""
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
revision = "967789050ba94deca04a5e84cce8ad472ce313c1"
version = "v0.9.0-pre1"
[[projects]]
branch = "master"
digest = "1:83bf37d060fca77e959fe5ceee81e58bbd1b01836f4addc70043a948e9912547"
digest = "1:60aca47f4eeeb972f1b9da7e7db51dee15ff6c59f7b401c1588b8e6771ba15ef"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = ""
@ -485,7 +560,7 @@
[[projects]]
branch = "master"
digest = "1:7221d79e41a24b2245d06f331d0825b479a9acd0bd05a8353806c7bf38395795"
digest = "1:e3aa5178be4fc4ae8cdb37d11c02f7490c00450a9f419e6aa84d02d3b47e90d2"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@ -496,7 +571,7 @@
revision = "2e54d0b93cba2fd133edc32211dcc32c06ef72ca"
[[projects]]
digest = "1:91345f4cce04248cf4998c4f70a82579c1468101767636acf5af2e1556904933"
digest = "1:a6a85fc81f2a06ccac3d45005523afbeee45138d781d4f3cb7ad9889d5c65aab"
name = "github.com/prometheus/procfs"
packages = [
".",
@ -514,7 +589,7 @@
version = "v1.2.0"
[[projects]]
digest = "1:75e2c10fd48881dc9400b7b70281270923e01c44f1f5cb4bbc5ba8cac8ca3026"
digest = "1:3ac248add5bb40a3c631c5334adcd09aa72d15af2768a5bc0274084ea7b2e5ba"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = ""
@ -522,14 +597,23 @@
version = "v1.0.3"
[[projects]]
digest = "1:11705e15791a8855c4b81839cbd71722b82f0304bf5e4225c878e6961c0d4c25"
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = ""
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[projects]]
digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = ""
revision = "9ff6c6923cfffbcd502984b8e0c80539a94968b7"
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
version = "v1.0.2"
[[projects]]
digest = "1:ba8fed52de60135b7efd5d832b997fb5b10fa09f227fa385174faa69f4219e4e"
digest = "1:306417ea2f31ea733df356a2b895de63776b6a5107085b33458e5cd6eb1d584d"
name = "github.com/stretchr/objx"
packages = ["."]
pruneopts = ""
@ -537,7 +621,7 @@
version = "v0.1"
[[projects]]
digest = "1:a70d585d45f695f2e8e6782569bdf181419667a35e6035ceb086706b495aa21a"
digest = "1:a30066593578732a356dc7e5d7f78d69184ca65aeeff5939241a3ab10559bb06"
name = "github.com/stretchr/testify"
packages = [
"assert",
@ -558,21 +642,53 @@
revision = "ac974c61c2f990f4115b119354b5e0b47550e888"
[[projects]]
digest = "1:f98e0b7c7bd110a49d8bb56c9eefcef4f547f5d789025d3bfe9bd6b83125221b"
digest = "1:cb2800cd5716e9d6172888e0e3ffe1f9c07b7f142eb83d49a391029bcf4f6cc1"
name = "github.com/ugorji/go"
packages = ["codec"]
pruneopts = ""
revision = "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74"
[[projects]]
digest = "1:d275cbe5049a91bd638e89ad365617be7eefc6d371fe8873fc658eba81dcfd24"
digest = "1:74f86c458e82e1c4efbab95233e0cf51b7cc02dc03193be9f62cd81224e10401"
name = "go.uber.org/atomic"
packages = ["."]
pruneopts = ""
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
version = "v1.3.2"
[[projects]]
digest = "1:22c7effcb4da0eacb2bb1940ee173fac010e9ef3c691f5de4b524d538bd980f5"
name = "go.uber.org/multierr"
packages = ["."]
pruneopts = ""
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0"
[[projects]]
digest = "1:246f378f80fba6fcf0f191c486b6613265abd2bc0f2fa55a36b928c67352021e"
name = "go.uber.org/zap"
packages = [
".",
"buffer",
"internal/bufferpool",
"internal/color",
"internal/exit",
"zapcore",
"zapgrpc",
]
pruneopts = ""
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
version = "v1.9.1"
[[projects]]
digest = "1:0f67b4bbcdf1caaee0450f225a53fd2c2f8793578cc7810eb09c290e008e33ac"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = ""
revision = "d172538b2cfce0c13cee31e647d0367aa8cd2486"
[[projects]]
digest = "1:4a5f1ce99f596fe9e26a9d47d61b87642701197ce610100ea628796af88a6544"
digest = "1:a18243d76a2a6a1ee8cfbbb1caea25fc61dffa4ca175ea7c8a9c2cf056336155"
name = "golang.org/x/net"
packages = [
"context",
@ -580,14 +696,16 @@
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"lex/httplex",
"publicsuffix",
"trace",
]
pruneopts = ""
revision = "e90d6d0afc4c315a0d87a568ae68577cc15149a0"
revision = "bb807669a61aca6092d8137da1fab2150bb96ad7"
[[projects]]
digest = "1:2fef2e19e90f29efd775d58d66b5e100139fedbe24cf749f1c085c0a5aee86d3"
digest = "1:dad5a319c4710358be1f2bf68f9fb7f90a71d7c641221b79801d5667b28f19e3"
name = "golang.org/x/oauth2"
packages = [
".",
@ -600,11 +718,11 @@
revision = "3c3a985cb79f52a3190fbc056984415ca6763d01"
[[projects]]
digest = "1:3830eb23292100e91d0fad721390e075e23f7ba34ac757d1c237d78ab74dcdb2"
digest = "1:39d88a855976e160babdd254802e1c2ae75ed380328c39742b57928852da6207"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = ""
revision = "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9"
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
[[projects]]
branch = "master"
@ -615,7 +733,7 @@
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
[[projects]]
digest = "1:ab84306e7e74b9f01b9f1480d46cca9325f8c512567a0e7b8888d04ff627a5ba"
digest = "1:2ad38d79865e33dde6157b7048debd6e7d47e0709df7b5e11bb888168e316908"
name = "google.golang.org/api"
packages = [
"dns/v1",
@ -627,7 +745,7 @@
revision = "a0ff90edab763c86aa88f2b1eb4f3301b82f6336"
[[projects]]
digest = "1:0b45fac4876cbd496ed7b95406b05c8c1eba559b43c82f2dda1b0e1bbe6cd1b6"
digest = "1:41e2b7e287117f6136f75286d48072ecf781ba54823ffeb2098e152e7dc45ef6"
name = "google.golang.org/appengine"
packages = [
".",
@ -644,6 +762,49 @@
pruneopts = ""
revision = "4f7eeb5305a4ba1966344836ba4af9996b7b4e05"
[[projects]]
branch = "master"
digest = "1:e43f1cb3f488a0c2be85939c2a594636f60b442a12a196c778bd2d6c9aca3df7"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = ""
revision = "11092d34479b07829b72e10713b159248caf5dad"
[[projects]]
digest = "1:ca75b3775a5d4e5d1fb48f57ef0865b4aaa8b3f00e6b52be68db991c4594e0a7"
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclog",
"internal",
"internal/backoff",
"internal/channelz",
"internal/envconfig",
"internal/grpcrand",
"internal/transport",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
]
pruneopts = ""
revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455"
version = "v1.14.0"
[[projects]]
digest = "1:e5d1fb981765b6f7513f793a3fcaac7158408cca77f75f7311ac82cc88e9c445"
name = "gopkg.in/inf.v0"
@ -653,15 +814,46 @@
version = "v0.9.0"
[[projects]]
digest = "1:10cf86195bddd2e0d686eec4fb35f35510baf6ce8393cbcfb664b9b88db7d747"
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = ""
revision = "53feefa2559fb8dfa8d81baad31be332c97d6c77"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
branch = "master"
digest = "1:6043867e27773bdc28ff2739d3743ad7d52472e356b6fc9406e4a175939a6ecc"
branch = "release-1.0"
digest = "1:bc43af6616d8ca12a7b8e806874387f0f1e181c08f547e9cd77f6cbac8cefd86"
name = "istio.io/api"
packages = [
"authentication/v1alpha1",
"mesh/v1alpha1",
"mixer/v1",
"mixer/v1/config/client",
"networking/v1alpha3",
"rbac/v1alpha1",
]
pruneopts = ""
revision = "76349c53b87f03f1e610b3aa3843dba3c38138d7"
[[projects]]
digest = "1:7eb25280e1f610470bb0c43ab6c91573cfc78672a58542106b9b71705581429a"
name = "istio.io/istio"
packages = [
"pilot/pkg/config/kube/crd",
"pilot/pkg/model",
"pilot/pkg/model/test",
"pilot/pkg/serviceregistry/kube",
"pkg/cache",
"pkg/kube",
"pkg/log",
]
pruneopts = ""
revision = "42773aacced474d97159902d20579a25b1f98106"
version = "1.0.1"
[[projects]]
digest = "1:f420c8548c93242d8e5dcfa5b34e0243883b4e660f65076e869daafac877144d"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
@ -695,15 +887,31 @@
"storage/v1beta1",
]
pruneopts = ""
revision = "183f3326a9353bd6d41430fc80f96259331d029c"
revision = "072894a440bdee3a891dea811fe42902311cd2a3"
version = "kubernetes-1.11.0"
[[projects]]
digest = "1:a855f74be59f83ed0950a9a2b70d8c8af01fb5782d060c7dec67ae39033f30dc"
digest = "1:66d1421ecff35bc48ee0b11a3f891f3af6f775ed6bb1d3e0deeaba221bf42490"
name = "k8s.io/apiextensions-apiserver"
packages = [
"pkg/apis/apiextensions",
"pkg/apis/apiextensions/v1beta1",
"pkg/client/clientset/clientset",
"pkg/client/clientset/clientset/scheme",
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1",
]
pruneopts = ""
revision = "8e7f43002fec5394a8d96ebca781aa9d4b37aaef"
version = "kubernetes-1.10.4"
[[projects]]
digest = "1:b6b2fb7b4da1ac973b64534ace2299a02504f16bc7820cb48edb8ca4077183e1"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apis/meta/internalversion",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1beta1",
@ -721,7 +929,9 @@
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/cache",
"pkg/util/clock",
"pkg/util/diff",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
@ -742,10 +952,10 @@
]
pruneopts = ""
revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae"
version = "kubernetes-1.11.1"
version = "kubernetes-1.11.0"
[[projects]]
digest = "1:3c4611c2b28fdc62391698bba7f212050f0f9ed75f3648f37ec3bcf8a83bf96d"
digest = "1:d04779a8de7d5465e0463bd986506348de5e89677c74777f695d3145a7a8d15e"
name = "k8s.io/client-go"
packages = [
"discovery",
@ -826,19 +1036,23 @@
"testing",
"third_party/forked/golang/template",
"tools/auth",
"tools/cache",
"tools/clientcmd",
"tools/clientcmd/api",
"tools/clientcmd/api/latest",
"tools/clientcmd/api/v1",
"tools/metrics",
"tools/pager",
"tools/reference",
"transport",
"util/buffer",
"util/cert",
"util/connrotation",
"util/flowcontrol",
"util/homedir",
"util/integer",
"util/jsonpath",
"util/retry",
]
pruneopts = ""
revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65"
@ -846,7 +1060,7 @@
[[projects]]
branch = "master"
digest = "1:d93d8bcb5f04d6b59eafdb9fa1a80f187d2542611670bfabc0ea8e031ab874a2"
digest = "1:526095379da1098c3f191a0008cc59c9bf9927492e63da7689e5de424219c162"
name = "k8s.io/kube-openapi"
packages = ["pkg/util/proto"]
pruneopts = ""
@ -906,6 +1120,9 @@
"google.golang.org/api/dns/v1",
"google.golang.org/api/googleapi",
"gopkg.in/yaml.v2",
"istio.io/api/networking/v1alpha3",
"istio.io/istio/pilot/pkg/config/kube/crd",
"istio.io/istio/pilot/pkg/model",
"k8s.io/api/core/v1",
"k8s.io/api/extensions/v1beta1",
"k8s.io/apimachinery/pkg/apis/meta/v1",

View File

@ -46,7 +46,7 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"]
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.8.0"
version = "0.9.0-pre1"
[[constraint]]
name = "github.com/sirupsen/logrus"
@ -56,10 +56,6 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"]
name = "github.com/stretchr/testify"
version = "~1.2.1"
[[constraint]]
name = "k8s.io/client-go"
version = "~8.0.0"
[[override]]
name = "github.com/kubernetes/repo-infra"
revision = "c2f9667a4c29e70a39b0e89db2d4f0cab907dbee"
@ -82,4 +78,36 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"]
[[constraint]]
name = "github.com/aliyun/alibaba-cloud-sdk-go"
version = "1.27.7"
version = "1.27.7"
[[constraint]]
name = "istio.io/istio"
version = "1.0.0"
[[override]]
name = "github.com/golang/protobuf"
version = "1.1.0"
[[constraint]]
name = "k8s.io/client-go"
version = "8.0.0"
[[override]]
name = "k8s.io/apimachinery"
version = "kubernetes-1.11.0"
[[override]]
name = "k8s.io/api"
version = "kubernetes-1.11.0"
[[override]]
name = "golang.org/x/sys"
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
[[override]]
name = "github.com/spf13/pflag"
version = "1.0.2"
[[override]]
name = "golang.org/x/net"
revision = "bb807669a61aca6092d8137da1fab2150bb96ad7"

View File

@ -21,6 +21,7 @@ All sources live in package `source`.
* `ServiceSource`: collects all Services that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to an annotation set on the Service or is compiled from the Service attributes via the FQDN Go template string.
* `IngressSource`: collects all Ingresses that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to the host rules defined in the Ingress object.
* `IstioGatewaySource`: collects all Istio Gateways and returns them as Endpoint objects. The desired DNS name corresponds to the hosts listed within the servers spec of each Gateway object.
* `FakeSource`: returns a random list of Endpoints for the purpose of testing providers without having access to a Kubernetes cluster.
* `ConnectorSource`: returns a list of Endpoint objects which are served by a tcp server configured through `connector-source-server` flag.
* `CRDSource`: returns a list of Endpoint objects sourced from the spec of CRD objects. For more details refer to [CRD source](../crd-source.md) documentation.

191
docs/tutorials/istio.md Normal file
View File

@ -0,0 +1,191 @@
# Configuring ExternalDNS to use the Istio Gateway Source
This tutorial describes how to configure ExternalDNS to use the Istio Gateway source.
It is meant to supplement the other provider-specific setup tutorials.
**Note:** Using the Istio Gateway source requires Istio >=1.0.0.
### Manifest (for clusters without RBAC enabled)
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --source=istio-gateway
- --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # omit to use the default (istio-system/istio-ingressgateway)
- --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
- --registry=txt
- --txt-owner-id=my-identifier
```
### Manifest (for clusters with RBAC enabled)
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list"]
- apiGroups: ["networking.istio.io"]
resources: ["gateways"]
verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --source=istio-gateway
- --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # omit to use the default (istio-system/istio-ingressgateway)
- --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
- --registry=txt
- --txt-owner-id=my-identifier
```
### Verify External DNS works (Gateway example)
Follow the [Istio ingress traffic tutorial](https://istio.io/docs/tasks/traffic-management/ingress/)
to deploy a sample service that will be exposed outside of the service mesh.
The following are relevant snippets from that tutorial.
#### Install a sample service
With automatic sidecar injection:
```bash
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.0/samples/httpbin/httpbin.yaml
```
Otherwise:
```bash
$ kubectl apply -f <(istioctl kube-inject -f https://raw.githubusercontent.com/istio/istio/release-1.0/samples/httpbin/httpbin.yaml)
```
#### Create an Istio Gateway:
```bash
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
```
#### Configure routes for traffic entering via the Gateway:
```bash
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
```
#### Access the sample service using `curl`
```bash
$ curl -I http://httpbin.example.com/status/200
HTTP/1.1 200 OK
server: envoy
date: Tue, 28 Aug 2018 15:26:47 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 5
```
Accessing any other URL that has not been explicitly exposed should return an HTTP 404 error:
```bash
$ curl -I http://httpbin.example.com/headers
HTTP/1.1 404 Not Found
date: Tue, 28 Aug 2018 15:27:48 GMT
server: envoy
transfer-encoding: chunked
```
**Note:** The `-H` flag in the original Istio tutorial is no longer necessary in the `curl` commands.

View File

@ -80,6 +80,7 @@ func main() {
KubeConfig: cfg.KubeConfig,
KubeMaster: cfg.Master,
ServiceTypeFilter: cfg.ServiceTypeFilter,
IstioIngressGateway: cfg.IstioIngressGateway,
}
// Lookup all the selected sources by names and pass them the desired configuration.

View File

@ -39,6 +39,7 @@ type Config struct {
Master string
KubeConfig string
RequestTimeout time.Duration
IstioIngressGateway string
Sources []string
Namespace string
AnnotationFilter string
@ -102,6 +103,7 @@ var defaultConfig = &Config{
Master: "",
KubeConfig: "",
RequestTimeout: time.Second * 30,
IstioIngressGateway: "istio-system/istio-ingressgateway",
Sources: nil,
Namespace: "",
AnnotationFilter: "",
@ -196,8 +198,11 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("kubeconfig", "Retrieve target cluster configuration from a Kubernetes configuration file (default: auto-detect)").Default(defaultConfig.KubeConfig).StringVar(&cfg.KubeConfig)
app.Flag("request-timeout", "Request timeout when calling Kubernetes APIs. 0s means no timeout").Default(defaultConfig.RequestTimeout.String()).DurationVar(&cfg.RequestTimeout)
// Flags related to Istio
app.Flag("istio-ingress-gateway", "The fully-qualified name of the Istio ingress gateway service (default: istio-system/istio-ingressgateway)").Default(defaultConfig.IstioIngressGateway).StringVar(&cfg.IstioIngressGateway)
// Flags related to processing sources
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "fake", "connector", "crd")
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector, istio-gateway, crd").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "fake", "connector", "crd")
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)

View File

@ -32,6 +32,7 @@ var (
Master: "",
KubeConfig: "",
RequestTimeout: time.Second * 30,
IstioIngressGateway: "istio-system/istio-ingressgateway",
Sources: []string{"service"},
Namespace: "",
FQDNTemplate: "",
@ -81,6 +82,7 @@ var (
Master: "http://127.0.0.1:8080",
KubeConfig: "/some/path",
RequestTimeout: time.Second * 77,
IstioIngressGateway: "istio-other/istio-otheringressgateway",
Sources: []string{"service", "ingress", "connector"},
Namespace: "namespace",
FQDNTemplate: "{{.Name}}.service.example.com",
@ -153,6 +155,7 @@ func TestParseFlags(t *testing.T) {
"--master=http://127.0.0.1:8080",
"--kubeconfig=/some/path",
"--request-timeout=77s",
"--istio-ingress-gateway=istio-other/istio-otheringressgateway",
"--source=service",
"--source=ingress",
"--source=connector",
@ -215,6 +218,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_MASTER": "http://127.0.0.1:8080",
"EXTERNAL_DNS_KUBECONFIG": "/some/path",
"EXTERNAL_DNS_REQUEST_TIMEOUT": "77s",
"EXTERNAL_DNS_ISTIO_INGRESS_GATEWAY": "istio-other/istio-otheringressgateway",
"EXTERNAL_DNS_SOURCE": "service\ningress\nconnector",
"EXTERNAL_DNS_NAMESPACE": "namespace",
"EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com",

285
source/gateway.go Normal file
View File

@ -0,0 +1,285 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package source
import (
"bytes"
"fmt"
"sort"
"strings"
"text/template"
log "github.com/sirupsen/logrus"
istionetworking "istio.io/api/networking/v1alpha3"
istiomodel "istio.io/istio/pilot/pkg/model"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"github.com/kubernetes-incubator/external-dns/endpoint"
"k8s.io/client-go/kubernetes"
)
// gatewaySource is an implementation of Source for Istio Gateway objects.
// The gateway implementation uses the spec.servers.hosts values for the hostnames.
// Use targetAnnotationKey to explicitly set Endpoint.
type gatewaySource struct {
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
istioNamespace string
istioIngressGatewayName string
namespace string
annotationFilter string
fqdnTemplate *template.Template
combineFQDNAnnotation bool
}
// NewIstioGatewaySource creates a new gatewaySource with the given config.
func NewIstioGatewaySource(
kubeClient kubernetes.Interface,
istioClient istiomodel.ConfigStore,
istioIngressGateway string,
namespace string,
annotationFilter string,
fqdnTemplate string,
combineFqdnAnnotation bool,
) (Source, error) {
var (
tmpl *template.Template
err error
)
istioNamespace, istioIngressGatewayName, err := parseIngressGateway(istioIngressGateway)
if err != nil {
return nil, err
}
if fqdnTemplate != "" {
tmpl, err = template.New("endpoint").Funcs(template.FuncMap{
"trimPrefix": strings.TrimPrefix,
}).Parse(fqdnTemplate)
if err != nil {
return nil, err
}
}
return &gatewaySource{
kubeClient: kubeClient,
istioClient: istioClient,
istioNamespace: istioNamespace,
istioIngressGatewayName: istioIngressGatewayName,
namespace: namespace,
annotationFilter: annotationFilter,
fqdnTemplate: tmpl,
combineFQDNAnnotation: combineFqdnAnnotation,
}, nil
}
// Endpoints returns endpoint objects for each host-target combination that should be processed.
// Retrieves all gateway resources in the source's namespace(s).
func (sc *gatewaySource) Endpoints() ([]*endpoint.Endpoint, error) {
configs, err := sc.istioClient.List(istiomodel.Gateway.Type, sc.namespace)
if err != nil {
return nil, err
}
configs, err = sc.filterByAnnotations(configs)
if err != nil {
return nil, err
}
endpoints := []*endpoint.Endpoint{}
for _, config := range configs {
// Check controller annotation to see if we are responsible.
controller, ok := config.Annotations[controllerAnnotationKey]
if ok && controller != controllerAnnotationValue {
log.Debugf("Skipping gateway %s/%s because controller value does not match, found: %s, required: %s",
config.Namespace, config.Name, controller, controllerAnnotationValue)
continue
}
gwEndpoints, err := sc.endpointsFromGatewayConfig(config)
if err != nil {
return nil, err
}
// apply template if host is missing on gateway
if (sc.combineFQDNAnnotation || len(gwEndpoints) == 0) && sc.fqdnTemplate != nil {
iEndpoints, err := sc.endpointsFromTemplate(&config)
if err != nil {
return nil, err
}
if sc.combineFQDNAnnotation {
gwEndpoints = append(gwEndpoints, iEndpoints...)
} else {
gwEndpoints = iEndpoints
}
}
if len(gwEndpoints) == 0 {
log.Debugf("No endpoints could be generated from gateway %s/%s", config.Namespace, config.Name)
continue
}
log.Debugf("Endpoints generated from gateway: %s/%s: %v", config.Namespace, config.Name, gwEndpoints)
sc.setResourceLabel(config, gwEndpoints)
endpoints = append(endpoints, gwEndpoints...)
}
for _, ep := range endpoints {
sort.Sort(ep.Targets)
}
return endpoints, nil
}
func (sc *gatewaySource) endpointsFromTemplate(config *istiomodel.Config) ([]*endpoint.Endpoint, error) {
// Process the whole template string
var buf bytes.Buffer
err := sc.fqdnTemplate.Execute(&buf, config)
if err != nil {
return nil, fmt.Errorf("failed to apply template on istio config %s: %v", config, err)
}
hostnames := buf.String()
ttl, err := getTTLFromAnnotations(config.Annotations)
if err != nil {
log.Warn(err)
}
targets := getTargetsFromTargetAnnotation(config.Annotations)
if len(targets) == 0 {
targets, err = sc.targetsFromIstioIngressStatus()
if err != nil {
return nil, err
}
}
var endpoints []*endpoint.Endpoint
// splits the FQDN template and removes the trailing periods
hostnameList := strings.Split(strings.Replace(hostnames, " ", "", -1), ",")
for _, hostname := range hostnameList {
hostname = strings.TrimSuffix(hostname, ".")
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl)...)
}
return endpoints, nil
}
// filterByAnnotations filters a list of configs by a given annotation selector.
func (sc *gatewaySource) filterByAnnotations(configs []istiomodel.Config) ([]istiomodel.Config, error) {
labelSelector, err := metav1.ParseToLabelSelector(sc.annotationFilter)
if err != nil {
return nil, err
}
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
if err != nil {
return nil, err
}
// empty filter returns original list
if selector.Empty() {
return configs, nil
}
filteredList := []istiomodel.Config{}
for _, config := range configs {
// convert the annotations to an equivalent label selector
annotations := labels.Set(config.Annotations)
// include if the annotations match the selector
if selector.Matches(annotations) {
filteredList = append(filteredList, config)
}
}
return filteredList, nil
}
func (sc *gatewaySource) setResourceLabel(config istiomodel.Config, endpoints []*endpoint.Endpoint) {
for _, ep := range endpoints {
ep.Labels[endpoint.ResourceLabelKey] = fmt.Sprintf("gateway/%s/%s", config.Namespace, config.Name)
}
}
func (sc *gatewaySource) targetsFromIstioIngressStatus() (targets endpoint.Targets, err error) {
if svc, e := sc.kubeClient.CoreV1().Services(sc.istioNamespace).Get(sc.istioIngressGatewayName, metav1.GetOptions{}); e != nil {
err = e
} else {
for _, lb := range svc.Status.LoadBalancer.Ingress {
if lb.IP != "" {
targets = append(targets, lb.IP)
}
if lb.Hostname != "" {
targets = append(targets, lb.Hostname)
}
}
}
return
}
// endpointsFromGatewayConfig extracts the endpoints from an Istio Gateway Config object
func (sc *gatewaySource) endpointsFromGatewayConfig(config istiomodel.Config) ([]*endpoint.Endpoint, error) {
var endpoints []*endpoint.Endpoint
ttl, err := getTTLFromAnnotations(config.Annotations)
if err != nil {
log.Warn(err)
}
targets := getTargetsFromTargetAnnotation(config.Annotations)
if len(targets) == 0 {
targets, err = sc.targetsFromIstioIngressStatus()
if err != nil {
return nil, err
}
}
gateway := config.Spec.(*istionetworking.Gateway)
for _, server := range gateway.Servers {
for _, host := range server.Hosts {
if host == "" {
continue
}
endpoints = append(endpoints, endpointsForHostname(host, targets, ttl)...)
}
}
hostnameList := getHostnamesFromAnnotations(config.Annotations)
for _, hostname := range hostnameList {
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl)...)
}
return endpoints, nil
}
func parseIngressGateway(ingressGateway string) (namespace, name string, err error) {
parts := strings.Split(ingressGateway, "/")
if len(parts) != 2 {
err = fmt.Errorf("invalid ingress gateway service (namespace/name) found '%v'", ingressGateway)
} else {
namespace, name = parts[0], parts[1]
}
return
}

1159
source/gateway_test.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -125,24 +125,6 @@ func (sc *ingressSource) Endpoints() ([]*endpoint.Endpoint, error) {
return endpoints, nil
}
// get endpoints from optional "target" annotation
// Returns empty endpoints array if none are found.
func getTargetsFromTargetAnnotation(ing *v1beta1.Ingress) endpoint.Targets {
var targets endpoint.Targets
// Get the desired hostname of the ingress from the annotation.
targetAnnotation, exists := ing.Annotations[targetAnnotationKey]
if exists && targetAnnotation != "" {
// splits the hostname annotation and removes the trailing periods
targetsList := strings.Split(strings.Replace(targetAnnotation, " ", "", -1), ",")
for _, targetHostname := range targetsList {
targetHostname = strings.TrimSuffix(targetHostname, ".")
targets = append(targets, targetHostname)
}
}
return targets
}
func (sc *ingressSource) endpointsFromTemplate(ing *v1beta1.Ingress) ([]*endpoint.Endpoint, error) {
// Process the whole template string
var buf bytes.Buffer
@ -158,7 +140,7 @@ func (sc *ingressSource) endpointsFromTemplate(ing *v1beta1.Ingress) ([]*endpoin
log.Warn(err)
}
targets := getTargetsFromTargetAnnotation(ing)
targets := getTargetsFromTargetAnnotation(ing.Annotations)
if len(targets) == 0 {
targets = targetsFromIngressStatus(ing.Status)
@ -220,7 +202,7 @@ func endpointsFromIngress(ing *v1beta1.Ingress) []*endpoint.Endpoint {
log.Warn(err)
}
targets := getTargetsFromTargetAnnotation(ing)
targets := getTargetsFromTargetAnnotation(ing.Annotations)
if len(targets) == 0 {
targets = targetsFromIngressStatus(ing.Status)
@ -250,46 +232,6 @@ func endpointsFromIngress(ing *v1beta1.Ingress) []*endpoint.Endpoint {
return endpoints
}
func endpointsForHostname(hostname string, targets endpoint.Targets, ttl endpoint.TTL) []*endpoint.Endpoint {
var endpoints []*endpoint.Endpoint
var aTargets endpoint.Targets
var cnameTargets endpoint.Targets
for _, t := range targets {
switch suitableType(t) {
case endpoint.RecordTypeA:
aTargets = append(aTargets, t)
default:
cnameTargets = append(cnameTargets, t)
}
}
if len(aTargets) > 0 {
epA := &endpoint.Endpoint{
DNSName: strings.TrimSuffix(hostname, "."),
Targets: aTargets,
RecordTTL: ttl,
RecordType: endpoint.RecordTypeA,
Labels: endpoint.NewLabels(),
}
endpoints = append(endpoints, epA)
}
if len(cnameTargets) > 0 {
epCNAME := &endpoint.Endpoint{
DNSName: strings.TrimSuffix(hostname, "."),
Targets: cnameTargets,
RecordTTL: ttl,
RecordType: endpoint.RecordTypeCNAME,
Labels: endpoint.NewLabels(),
}
endpoints = append(endpoints, epCNAME)
}
return endpoints
}
func targetsFromIngressStatus(status v1beta1.IngressStatus) endpoint.Targets {
var targets endpoint.Targets

View File

@ -74,6 +74,24 @@ func getHostnamesFromAnnotations(annotations map[string]string) []string {
return strings.Split(strings.Replace(hostnameAnnotation, " ", "", -1), ",")
}
// getTargetsFromTargetAnnotation gets endpoints from optional "target" annotation.
// Returns empty endpoints array if none are found.
func getTargetsFromTargetAnnotation(annotations map[string]string) endpoint.Targets {
var targets endpoint.Targets
// Get the desired hostname of the ingress from the annotation.
targetAnnotation, exists := annotations[targetAnnotationKey]
if exists && targetAnnotation != "" {
// splits the hostname annotation and removes the trailing periods
targetsList := strings.Split(strings.Replace(targetAnnotation, " ", "", -1), ",")
for _, targetHostname := range targetsList {
targetHostname = strings.TrimSuffix(targetHostname, ".")
targets = append(targets, targetHostname)
}
}
return targets
}
// suitableType returns the DNS resource record type suitable for the target.
// In this case type A for IPs and type CNAME for everything else.
func suitableType(target string) string {
@ -82,3 +100,44 @@ func suitableType(target string) string {
}
return endpoint.RecordTypeCNAME
}
// endpointsForHostname returns the endpoint objects for each host-target combination.
func endpointsForHostname(hostname string, targets endpoint.Targets, ttl endpoint.TTL) []*endpoint.Endpoint {
var endpoints []*endpoint.Endpoint
var aTargets endpoint.Targets
var cnameTargets endpoint.Targets
for _, t := range targets {
switch suitableType(t) {
case endpoint.RecordTypeA:
aTargets = append(aTargets, t)
default:
cnameTargets = append(cnameTargets, t)
}
}
if len(aTargets) > 0 {
epA := &endpoint.Endpoint{
DNSName: strings.TrimSuffix(hostname, "."),
Targets: aTargets,
RecordTTL: ttl,
RecordType: endpoint.RecordTypeA,
Labels: endpoint.NewLabels(),
}
endpoints = append(endpoints, epA)
}
if len(cnameTargets) > 0 {
epCNAME := &endpoint.Endpoint{
DNSName: strings.TrimSuffix(hostname, "."),
Targets: cnameTargets,
RecordTTL: ttl,
RecordType: endpoint.RecordTypeCNAME,
Labels: endpoint.NewLabels(),
}
endpoints = append(endpoints, epCNAME)
}
return endpoints
}

View File

@ -27,6 +27,8 @@ import (
"github.com/linki/instrumented_http"
log "github.com/sirupsen/logrus"
istiocrd "istio.io/istio/pilot/pkg/config/kube/crd"
istiomodel "istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
@ -49,11 +51,13 @@ type Config struct {
KubeConfig string
KubeMaster string
ServiceTypeFilter []string
IstioIngressGateway string
}
// ClientGenerator provides clients
type ClientGenerator interface {
KubeClient() (kubernetes.Interface, error)
IstioClient() (istiomodel.ConfigStore, error)
}
// SingletonClientGenerator stores provider clients and guarantees that only one instance of client
@ -62,17 +66,28 @@ type SingletonClientGenerator struct {
KubeConfig string
KubeMaster string
RequestTimeout time.Duration
client kubernetes.Interface
sync.Once
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
kubeOnce sync.Once
istioOnce sync.Once
}
// KubeClient generates a kube client if it was not created before
func (p *SingletonClientGenerator) KubeClient() (kubernetes.Interface, error) {
var err error
p.Once.Do(func() {
p.client, err = NewKubeClient(p.KubeConfig, p.KubeMaster, p.RequestTimeout)
p.kubeOnce.Do(func() {
p.kubeClient, err = NewKubeClient(p.KubeConfig, p.KubeMaster, p.RequestTimeout)
})
return p.client, err
return p.kubeClient, err
}
// IstioClient generates an istio client if it was not created before
func (p *SingletonClientGenerator) IstioClient() (istiomodel.ConfigStore, error) {
var err error
p.istioOnce.Do(func() {
p.istioClient, err = NewIstioClient(p.KubeConfig)
})
return p.istioClient, err
}
// ByNames returns multiple Sources given multiple names.
@ -104,6 +119,16 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
return nil, err
}
return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation)
case "istio-gateway":
kubernetesClient, err := p.KubeClient()
if err != nil {
return nil, err
}
istioClient, err := p.IstioClient()
if err != nil {
return nil, err
}
return NewIstioGatewaySource(kubernetesClient, istioClient, cfg.IstioIngressGateway, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation)
case "fake":
return NewFakeSource(cfg.FQDNTemplate)
case "connector":
@ -153,7 +178,37 @@ func NewKubeClient(kubeConfig, kubeMaster string, requestTimeout time.Duration)
return nil, err
}
log.Infof("Connected to cluster at %s", config.Host)
log.Infof("Created Kubernetes client %s", config.Host)
return client, nil
}
// NewIstioClient returns a new Istio client object. It uses the configured
// KubeConfig attribute to connect to the cluster. If KubeConfig isn't provided
// it defaults to using the recommended default.
// NB: Istio controls the creation of the underlying Kubernetes client, so we
// have no ability to tack on transport wrappers (e.g., Prometheus request
// wrappers) to the client's config at this level. Furthermore, the Istio client
// constructor does not expose the ability to override the Kubernetes master,
// so the Master config attribute has no effect.
func NewIstioClient(kubeConfig string) (*istiocrd.Client, error) {
if kubeConfig == "" {
if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil {
kubeConfig = clientcmd.RecommendedHomeFile
}
}
client, err := istiocrd.NewClient(
kubeConfig,
"",
istiomodel.ConfigDescriptor{istiomodel.Gateway},
"",
)
if err != nil {
return nil, err
}
log.Info("Created Istio client")
return client, nil
}

View File

@ -20,6 +20,7 @@ import (
"errors"
"testing"
istiomodel "istio.io/istio/pilot/pkg/model"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
@ -29,14 +30,24 @@ import (
type MockClientGenerator struct {
mock.Mock
client kubernetes.Interface
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
}
func (m *MockClientGenerator) KubeClient() (kubernetes.Interface, error) {
args := m.Called()
if args.Error(1) == nil {
m.client = args.Get(0).(kubernetes.Interface)
return m.client, nil
m.kubeClient = args.Get(0).(kubernetes.Interface)
return m.kubeClient, nil
}
return nil, args.Error(1)
}
func (m *MockClientGenerator) IstioClient() (istiomodel.ConfigStore, error) {
args := m.Called()
if args.Error(1) == nil {
m.istioClient = args.Get(0).(istiomodel.ConfigStore)
return m.istioClient, nil
}
return nil, args.Error(1)
}
@ -48,28 +59,29 @@ type ByNamesTestSuite struct {
func (suite *ByNamesTestSuite) TestAllInitialized() {
mockClientGenerator := new(MockClientGenerator)
mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
mockClientGenerator.On("IstioClient").Return(NewFakeConfigStore(), nil)
sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "fake"}, &Config{})
sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "istio-gateway", "fake"}, minimalConfig)
suite.NoError(err, "should not generate errors")
suite.Len(sources, 3, "should generate all three sources")
suite.Len(sources, 4, "should generate all four sources")
}
func (suite *ByNamesTestSuite) TestOnlyFake() {
mockClientGenerator := new(MockClientGenerator)
mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
sources, err := ByNames(mockClientGenerator, []string{"fake"}, &Config{})
sources, err := ByNames(mockClientGenerator, []string{"fake"}, minimalConfig)
suite.NoError(err, "should not generate errors")
suite.Len(sources, 1, "should generate all three sources")
suite.Nil(mockClientGenerator.client, "client should not be created")
suite.Len(sources, 1, "should generate fake source")
suite.Nil(mockClientGenerator.kubeClient, "client should not be created")
}
func (suite *ByNamesTestSuite) TestSourceNotFound() {
mockClientGenerator := new(MockClientGenerator)
mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
sources, err := ByNames(mockClientGenerator, []string{"foo"}, &Config{})
suite.Equal(err, ErrSourceNotFound, "should return sourcen not found")
sources, err := ByNames(mockClientGenerator, []string{"foo"}, minimalConfig)
suite.Equal(err, ErrSourceNotFound, "should return source not found")
suite.Len(sources, 0, "should not returns any source")
}
@ -77,13 +89,29 @@ func (suite *ByNamesTestSuite) TestKubeClientFails() {
mockClientGenerator := new(MockClientGenerator)
mockClientGenerator.On("KubeClient").Return(nil, errors.New("foo"))
_, err := ByNames(mockClientGenerator, []string{"service"}, &Config{})
suite.Error(err, "should return an error if client cannot be created")
_, err := ByNames(mockClientGenerator, []string{"service"}, minimalConfig)
suite.Error(err, "should return an error if kubernetes client cannot be created")
_, err = ByNames(mockClientGenerator, []string{"ingress"}, &Config{})
suite.Error(err, "should return an error if client cannot be created")
_, err = ByNames(mockClientGenerator, []string{"ingress"}, minimalConfig)
suite.Error(err, "should return an error if kubernetes client cannot be created")
_, err = ByNames(mockClientGenerator, []string{"istio-gateway"}, minimalConfig)
suite.Error(err, "should return an error if kubernetes client cannot be created")
}
func (suite *ByNamesTestSuite) TestIstioClientFails() {
mockClientGenerator := new(MockClientGenerator)
mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
mockClientGenerator.On("IstioClient").Return(nil, errors.New("foo"))
_, err := ByNames(mockClientGenerator, []string{"istio-gateway"}, minimalConfig)
suite.Error(err, "should return an error if istio client cannot be created")
}
func TestByNames(t *testing.T) {
suite.Run(t, new(ByNamesTestSuite))
}
var minimalConfig = &Config{
IstioIngressGateway: "istio-system/istio-ingressgateway",
}