Adding label selector support to Corefile (#208)
* Adding parsing for label selector to Corefile * Updating comment typo in k8sCorefile * Adding implementation of label support to filter exposed objects * Updating TODO list
This commit is contained in:
parent
3b7b9b49d5
commit
ad2838b916
6 changed files with 194 additions and 47 deletions
|
@ -11,6 +11,13 @@
|
||||||
template {service}.{namespace}.{zone}
|
template {service}.{namespace}.{zone}
|
||||||
# Only expose the k8s namespace "demo"
|
# Only expose the k8s namespace "demo"
|
||||||
namespaces demo
|
namespaces demo
|
||||||
|
# Only expose the records for kubernetes objects
|
||||||
|
# that matches this label selector. The label
|
||||||
|
# selector syntax is described in the kubernetes
|
||||||
|
# API documentation: http://kubernetes.io/docs/user-guide/labels/
|
||||||
|
# Example selector below only exposes objects tagged as
|
||||||
|
# "application=nginx" in the staging or qa environments.
|
||||||
|
#labels environment in (staging, qa),application=nginx
|
||||||
}
|
}
|
||||||
# Perform DNS response caching for the coredns.local zone
|
# Perform DNS response caching for the coredns.local zone
|
||||||
# Cache timeout is provided by the integer in seconds
|
# Cache timeout is provided by the integer in seconds
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/miekg/coredns/middleware"
|
"github.com/miekg/coredns/middleware"
|
||||||
"github.com/miekg/coredns/middleware/kubernetes"
|
"github.com/miekg/coredns/middleware/kubernetes"
|
||||||
"github.com/miekg/coredns/middleware/kubernetes/nametemplate"
|
"github.com/miekg/coredns/middleware/kubernetes/nametemplate"
|
||||||
|
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -109,6 +110,20 @@ func kubernetesParse(c *Controller) (kubernetes.Kubernetes, error) {
|
||||||
log.Printf("[debug] 'resyncperiod' keyword provided without any duration value.")
|
log.Printf("[debug] 'resyncperiod' keyword provided without any duration value.")
|
||||||
return kubernetes.Kubernetes{}, c.ArgErr()
|
return kubernetes.Kubernetes{}, c.ArgErr()
|
||||||
}
|
}
|
||||||
|
case "labels":
|
||||||
|
args := c.RemainingArgs()
|
||||||
|
if len(args) != 0 {
|
||||||
|
labelSelectorString := strings.Join(args, " ")
|
||||||
|
k8s.LabelSelector, err = unversionedapi.ParseToLabelSelector(labelSelectorString)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.New(fmt.Sprintf("Unable to parse label selector. Value provided was '%v'. Error was: %v", labelSelectorString, err))
|
||||||
|
log.Printf("[ERROR] %v", err)
|
||||||
|
return kubernetes.Kubernetes{}, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("[debug] 'labels' keyword provided without any selector value.")
|
||||||
|
return kubernetes.Kubernetes{}, c.ArgErr()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return k8s, nil
|
return k8s, nil
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestKubernetesParse(t *testing.T) {
|
func TestKubernetesParse(t *testing.T) {
|
||||||
|
@ -16,6 +18,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
expectedNTValid bool // NameTemplate to be initialized and valid
|
expectedNTValid bool // NameTemplate to be initialized and valid
|
||||||
expectedNSCount int // expected count of namespaces.
|
expectedNSCount int // expected count of namespaces.
|
||||||
expectedResyncPeriod time.Duration // expected resync period value
|
expectedResyncPeriod time.Duration // expected resync period value
|
||||||
|
expectedLabelSelector string // expected label selector value
|
||||||
}{
|
}{
|
||||||
// positive
|
// positive
|
||||||
{
|
{
|
||||||
|
@ -27,6 +30,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kubernetes keyword with multiple zones",
|
"kubernetes keyword with multiple zones",
|
||||||
|
@ -37,6 +41,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kubernetes keyword with zone and empty braces",
|
"kubernetes keyword with zone and empty braces",
|
||||||
|
@ -48,6 +53,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"endpoint keyword with url",
|
"endpoint keyword with url",
|
||||||
|
@ -60,6 +66,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"template keyword with valid template",
|
"template keyword with valid template",
|
||||||
|
@ -72,6 +79,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"namespaces keyword with one namespace",
|
"namespaces keyword with one namespace",
|
||||||
|
@ -84,6 +92,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
1,
|
1,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"namespaces keyword with multiple namespaces",
|
"namespaces keyword with multiple namespaces",
|
||||||
|
@ -96,6 +105,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
2,
|
2,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resync period in seconds",
|
"resync period in seconds",
|
||||||
|
@ -108,6 +118,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
30 * time.Second,
|
30 * time.Second,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resync period in minutes",
|
"resync period in minutes",
|
||||||
|
@ -120,6 +131,33 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
15 * time.Minute,
|
15 * time.Minute,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"basic label selector",
|
||||||
|
`kubernetes coredns.local {
|
||||||
|
labels environment=prod
|
||||||
|
}`,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
defaultResyncPeriod,
|
||||||
|
"environment=prod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multi-label selector",
|
||||||
|
`kubernetes coredns.local {
|
||||||
|
labels environment in (production, staging, qa),application=nginx
|
||||||
|
}`,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
defaultResyncPeriod,
|
||||||
|
"application=nginx,environment in (production,qa,staging)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fully specified valid config",
|
"fully specified valid config",
|
||||||
|
@ -128,6 +166,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
endpoint http://localhost:8080
|
endpoint http://localhost:8080
|
||||||
template {service}.{namespace}.{zone}
|
template {service}.{namespace}.{zone}
|
||||||
namespaces demo test
|
namespaces demo test
|
||||||
|
labels environment in (production, staging, qa),application=nginx
|
||||||
}`,
|
}`,
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
@ -135,6 +174,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
2,
|
2,
|
||||||
15 * time.Minute,
|
15 * time.Minute,
|
||||||
|
"application=nginx,environment in (production,qa,staging)",
|
||||||
},
|
},
|
||||||
// negative
|
// negative
|
||||||
{
|
{
|
||||||
|
@ -146,6 +186,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
-1,
|
-1,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kubernetes keyword without a zone",
|
"kubernetes keyword without a zone",
|
||||||
|
@ -156,6 +197,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"endpoint keyword without an endpoint value",
|
"endpoint keyword without an endpoint value",
|
||||||
|
@ -168,6 +210,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
-1,
|
-1,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"template keyword without a template value",
|
"template keyword without a template value",
|
||||||
|
@ -180,6 +223,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"template keyword with an invalid template value",
|
"template keyword with an invalid template value",
|
||||||
|
@ -192,6 +236,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"namespace keyword without a namespace value",
|
"namespace keyword without a namespace value",
|
||||||
|
@ -204,6 +249,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
-1,
|
-1,
|
||||||
defaultResyncPeriod,
|
defaultResyncPeriod,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resyncperiod keyword without a duration value",
|
"resyncperiod keyword without a duration value",
|
||||||
|
@ -216,6 +262,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
0 * time.Minute,
|
0 * time.Minute,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resync period no units",
|
"resync period no units",
|
||||||
|
@ -228,6 +275,7 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
0 * time.Second,
|
0 * time.Second,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resync period invalid",
|
"resync period invalid",
|
||||||
|
@ -240,6 +288,33 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
0 * time.Second,
|
0 * time.Second,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"labels with no selector value",
|
||||||
|
`kubernetes coredns.local {
|
||||||
|
labels
|
||||||
|
}`,
|
||||||
|
true,
|
||||||
|
"Wrong argument count or unexpected line ending after 'labels'",
|
||||||
|
-1,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
0 * time.Second,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"labels with invalid selector value",
|
||||||
|
`kubernetes coredns.local {
|
||||||
|
labels environment in (production, qa
|
||||||
|
}`,
|
||||||
|
true,
|
||||||
|
"Unable to parse label selector. Value provided was",
|
||||||
|
-1,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
0 * time.Second,
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +375,15 @@ func TestKubernetesParse(t *testing.T) {
|
||||||
// ResyncPeriod
|
// ResyncPeriod
|
||||||
foundResyncPeriod := k8sController.ResyncPeriod
|
foundResyncPeriod := k8sController.ResyncPeriod
|
||||||
if foundResyncPeriod != test.expectedResyncPeriod {
|
if foundResyncPeriod != test.expectedResyncPeriod {
|
||||||
t.Errorf("Test %d: Expected kubernetes controller to be initialized with resync period '%s'. Instead found period '%s' for input '%s'", test.expectedResyncPeriod, foundResyncPeriod, test.input)
|
t.Errorf("Test %d: Expected kubernetes controller to be initialized with resync period '%s'. Instead found period '%s' for input '%s'", i, test.expectedResyncPeriod, foundResyncPeriod, test.input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Labels
|
||||||
|
if k8sController.LabelSelector != nil {
|
||||||
|
foundLabelSelectorString := unversionedapi.FormatLabelSelector(k8sController.LabelSelector)
|
||||||
|
if foundLabelSelectorString != test.expectedLabelSelector {
|
||||||
|
t.Errorf("Test %d: Expected kubernetes controller to be initialized with label selector '%s'. Instead found selector '%s' for input '%s'", i, test.expectedLabelSelector, foundLabelSelectorString, test.input)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,13 @@ This is the default kubernetes setup, with everything specified in full:
|
||||||
template {service}.{namespace}.{zone}
|
template {service}.{namespace}.{zone}
|
||||||
# Only expose the k8s namespace "demo"
|
# Only expose the k8s namespace "demo"
|
||||||
namespaces demo
|
namespaces demo
|
||||||
|
# Only expose the records for kubernetes objects
|
||||||
|
# that matches this label selector. The label
|
||||||
|
# selector syntax is described in the kubernetes
|
||||||
|
# API documentation: http://kubernetes.io/docs/user-guide/labels/
|
||||||
|
# Example selector below only exposes objects tagged as
|
||||||
|
# "application=nginx" in the staging or qa environments.
|
||||||
|
#labels environment in (staging, qa),application=nginx
|
||||||
}
|
}
|
||||||
# Perform DNS response caching for the coredns.local zone
|
# Perform DNS response caching for the coredns.local zone
|
||||||
# Cache timeout is provided by the integer in seconds
|
# Cache timeout is provided by the integer in seconds
|
||||||
|
@ -51,10 +58,13 @@ This is the default kubernetes setup, with everything specified in full:
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Notes:
|
Defaults:
|
||||||
* If the `namespaces` keyword is omitted, all kubernetes namespaces are exposed.
|
* If the `namespaces` keyword is omitted, all kubernetes namespaces are exposed.
|
||||||
* If the `template` keyword is omitted, the default template of "{service}.{namespace}.{zone}" is used.
|
* If the `template` keyword is omitted, the default template of "{service}.{namespace}.{zone}" is used.
|
||||||
* If the `resyncperiod` keyword is omitted, the default resync period is 5 minutes.
|
* If the `resyncperiod` keyword is omitted, the default resync period is 5 minutes.
|
||||||
|
* The `labels` keyword is only used when filtering of results based on kubernetes label selector syntax
|
||||||
|
is required. The label selector syntax is described in the kubernetes API documentation at:
|
||||||
|
http://kubernetes.io/docs/user-guide/labels/
|
||||||
|
|
||||||
### Basic Setup
|
### Basic Setup
|
||||||
|
|
||||||
|
@ -191,7 +201,7 @@ mynginx.demo.coredns.local. 0 IN A 10.0.0.10
|
||||||
|
|
||||||
## Implementation Notes/Ideas
|
## Implementation Notes/Ideas
|
||||||
|
|
||||||
### Basic Zone Mapping (implemented)
|
### Basic Zone Mapping
|
||||||
The middleware is configured with a "zone" string. For
|
The middleware is configured with a "zone" string. For
|
||||||
example: "zone = coredns.local".
|
example: "zone = coredns.local".
|
||||||
|
|
||||||
|
@ -200,8 +210,8 @@ to: "myservice.mynamespace.coredns.local".
|
||||||
|
|
||||||
The middleware should publish an A record for that service and a service record.
|
The middleware should publish an A record for that service and a service record.
|
||||||
|
|
||||||
Initial implementation just performs the above simple mapping. Subsequent
|
If multiple zone names are specified, the records for kubernetes objects are
|
||||||
revisions should allow different namespaces to be published under different zones.
|
exposed in all listed zones.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -262,11 +272,6 @@ return the IP addresses for all services with "nginx" in the service name.
|
||||||
|
|
||||||
TBD:
|
TBD:
|
||||||
* How does this relate the the k8s load-balancer configuration?
|
* How does this relate the the k8s load-balancer configuration?
|
||||||
* Do wildcards search across namespaces? (Yes)
|
|
||||||
* Initial implementation assumes that a namespace maps to the first DNS label
|
|
||||||
below the zone managed by the kubernetes middleware. This assumption may
|
|
||||||
need to be revised. (Template scheme for record names removes this assumption.)
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* SkyDNS compatibility/equivalency:
|
* SkyDNS compatibility/equivalency:
|
||||||
|
@ -318,19 +323,19 @@ TBD:
|
||||||
* Additional features:
|
* Additional features:
|
||||||
* Reverse IN-ADDR entries for services. (Is there any value in supporting
|
* Reverse IN-ADDR entries for services. (Is there any value in supporting
|
||||||
reverse lookup records?) (need tests, functionality should work based on @aledbf's code.)
|
reverse lookup records?) (need tests, functionality should work based on @aledbf's code.)
|
||||||
* How to support label specification in Corefile to allow use of labels to
|
* (done) ~~How to support label specification in Corefile to allow use of labels to
|
||||||
indicate zone? (Is this even useful?) For example, the following
|
indicate zone? For example, the following
|
||||||
configuration exposes all services labeled for the "staging" environment
|
configuration exposes all services labeled for the "staging" environment
|
||||||
and tenant "customerB" in the zone "customerB.stage.local":
|
and tenant "customerB" in the zone "customerB.stage.local":
|
||||||
|
|
||||||
kubernetes customerB.stage.local {
|
kubernetes customerB.stage.local {
|
||||||
# Use url for k8s API endpoint
|
# Use url for k8s API endpoint
|
||||||
endpoint http://localhost:8080
|
endpoint http://localhost:8080
|
||||||
label "environment" : "staging", "tenant" : "customerB"
|
labels environment in (staging),tenant=customerB
|
||||||
}
|
}
|
||||||
|
|
||||||
Note: label specification/selection is a killer feature for segmenting
|
Note: label specification/selection is a killer feature for segmenting
|
||||||
test vs staging vs prod environments.
|
test vs staging vs prod environments.~~ Need label testing.
|
||||||
* Implement IP selection and ordering (internal/external). Related to
|
* Implement IP selection and ordering (internal/external). Related to
|
||||||
wildcards and SkyDNS use of CNAMES.
|
wildcards and SkyDNS use of CNAMES.
|
||||||
* Flatten service and namespace names to valid DNS characters. (service names
|
* Flatten service and namespace names to valid DNS characters. (service names
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/controller/framework"
|
"k8s.io/kubernetes/pkg/controller/framework"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
)
|
)
|
||||||
|
@ -23,6 +24,8 @@ var (
|
||||||
type dnsController struct {
|
type dnsController struct {
|
||||||
client *client.Client
|
client *client.Client
|
||||||
|
|
||||||
|
selector *labels.Selector
|
||||||
|
|
||||||
endpController *framework.Controller
|
endpController *framework.Controller
|
||||||
svcController *framework.Controller
|
svcController *framework.Controller
|
||||||
nsController *framework.Controller
|
nsController *framework.Controller
|
||||||
|
@ -40,68 +43,87 @@ type dnsController struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newDNSController creates a controller for coredns
|
// newDNSController creates a controller for coredns
|
||||||
func newdnsController(kubeClient *client.Client, resyncPeriod time.Duration) *dnsController {
|
func newdnsController(kubeClient *client.Client, resyncPeriod time.Duration, lselector *labels.Selector) *dnsController {
|
||||||
dns := dnsController{
|
dns := dnsController{
|
||||||
client: kubeClient,
|
client: kubeClient,
|
||||||
|
selector: lselector,
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
dns.endpLister.Store, dns.endpController = framework.NewInformer(
|
dns.endpLister.Store, dns.endpController = framework.NewInformer(
|
||||||
&cache.ListWatch{
|
&cache.ListWatch{
|
||||||
ListFunc: endpointsListFunc(dns.client, namespace),
|
ListFunc: endpointsListFunc(dns.client, namespace, dns.selector),
|
||||||
WatchFunc: endpointsWatchFunc(dns.client, namespace),
|
WatchFunc: endpointsWatchFunc(dns.client, namespace, dns.selector),
|
||||||
},
|
},
|
||||||
&api.Endpoints{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
&api.Endpoints{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
||||||
|
|
||||||
dns.svcLister.Store, dns.svcController = framework.NewInformer(
|
dns.svcLister.Store, dns.svcController = framework.NewInformer(
|
||||||
&cache.ListWatch{
|
&cache.ListWatch{
|
||||||
ListFunc: serviceListFunc(dns.client, namespace),
|
ListFunc: serviceListFunc(dns.client, namespace, dns.selector),
|
||||||
WatchFunc: serviceWatchFunc(dns.client, namespace),
|
WatchFunc: serviceWatchFunc(dns.client, namespace, dns.selector),
|
||||||
},
|
},
|
||||||
&api.Service{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
&api.Service{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
||||||
|
|
||||||
dns.nsLister.Store, dns.nsController = framework.NewInformer(
|
dns.nsLister.Store, dns.nsController = framework.NewInformer(
|
||||||
&cache.ListWatch{
|
&cache.ListWatch{
|
||||||
ListFunc: namespaceListFunc(dns.client),
|
ListFunc: namespaceListFunc(dns.client, dns.selector),
|
||||||
WatchFunc: namespaceWatchFunc(dns.client),
|
WatchFunc: namespaceWatchFunc(dns.client, dns.selector),
|
||||||
},
|
},
|
||||||
&api.Namespace{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
&api.Namespace{}, resyncPeriod, framework.ResourceEventHandlerFuncs{})
|
||||||
|
|
||||||
return &dns
|
return &dns
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceListFunc(c *client.Client, ns string) func(api.ListOptions) (runtime.Object, error) {
|
func serviceListFunc(c *client.Client, ns string, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) {
|
||||||
return func(opts api.ListOptions) (runtime.Object, error) {
|
return func(opts api.ListOptions) (runtime.Object, error) {
|
||||||
|
if s != nil {
|
||||||
|
opts.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Services(ns).List(opts)
|
return c.Services(ns).List(opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceWatchFunc(c *client.Client, ns string) func(options api.ListOptions) (watch.Interface, error) {
|
func serviceWatchFunc(c *client.Client, ns string, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) {
|
||||||
return func(options api.ListOptions) (watch.Interface, error) {
|
return func(options api.ListOptions) (watch.Interface, error) {
|
||||||
|
if s != nil {
|
||||||
|
options.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Services(ns).Watch(options)
|
return c.Services(ns).Watch(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func endpointsListFunc(c *client.Client, ns string) func(api.ListOptions) (runtime.Object, error) {
|
func endpointsListFunc(c *client.Client, ns string, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) {
|
||||||
return func(opts api.ListOptions) (runtime.Object, error) {
|
return func(opts api.ListOptions) (runtime.Object, error) {
|
||||||
|
if s != nil {
|
||||||
|
opts.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Endpoints(ns).List(opts)
|
return c.Endpoints(ns).List(opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func endpointsWatchFunc(c *client.Client, ns string) func(options api.ListOptions) (watch.Interface, error) {
|
func endpointsWatchFunc(c *client.Client, ns string, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) {
|
||||||
return func(options api.ListOptions) (watch.Interface, error) {
|
return func(options api.ListOptions) (watch.Interface, error) {
|
||||||
|
if s != nil {
|
||||||
|
options.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Endpoints(ns).Watch(options)
|
return c.Endpoints(ns).Watch(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespaceListFunc(c *client.Client) func(api.ListOptions) (runtime.Object, error) {
|
func namespaceListFunc(c *client.Client, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) {
|
||||||
return func(opts api.ListOptions) (runtime.Object, error) {
|
return func(opts api.ListOptions) (runtime.Object, error) {
|
||||||
|
if s != nil {
|
||||||
|
opts.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Namespaces().List(opts)
|
return c.Namespaces().List(opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespaceWatchFunc(c *client.Client) func(options api.ListOptions) (watch.Interface, error) {
|
func namespaceWatchFunc(c *client.Client, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) {
|
||||||
return func(options api.ListOptions) (watch.Interface, error) {
|
return func(options api.ListOptions) (watch.Interface, error) {
|
||||||
|
if s != nil {
|
||||||
|
options.LabelSelector = *s
|
||||||
|
}
|
||||||
return c.Namespaces().Watch(options)
|
return c.Namespaces().Watch(options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +171,6 @@ func (dns *dnsController) GetNamespaceList() *api.NamespaceList {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dns *dnsController) GetServiceList() *api.ServiceList {
|
func (dns *dnsController) GetServiceList() *api.ServiceList {
|
||||||
log.Printf("[debug] here in GetServiceList")
|
|
||||||
svcList, err := dns.svcLister.List()
|
svcList, err := dns.svcLister.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &api.ServiceList{}
|
return &api.ServiceList{}
|
||||||
|
|
|
@ -15,7 +15,9 @@ import (
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned"
|
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
unversionedclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
)
|
)
|
||||||
|
@ -29,6 +31,8 @@ type Kubernetes struct {
|
||||||
ResyncPeriod time.Duration
|
ResyncPeriod time.Duration
|
||||||
NameTemplate *nametemplate.NameTemplate
|
NameTemplate *nametemplate.NameTemplate
|
||||||
Namespaces []string
|
Namespaces []string
|
||||||
|
LabelSelector *unversionedapi.LabelSelector
|
||||||
|
Selector *labels.Selector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Kubernetes) StartKubeCache() error {
|
func (g *Kubernetes) StartKubeCache() error {
|
||||||
|
@ -45,14 +49,26 @@ func (g *Kubernetes) StartKubeCache() error {
|
||||||
log.Printf("[debug] error connecting to the client: %v", err)
|
log.Printf("[debug] error connecting to the client: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
kubeClient, err := unversioned.New(config)
|
kubeClient, err := unversionedclient.New(config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed to create kubernetes notification controller: %v", err)
|
log.Printf("[ERROR] Failed to create kubernetes notification controller: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if g.LabelSelector == nil {
|
||||||
|
log.Printf("[INFO] Kubernetes middleware configured without a label selector. No label-based filtering will be operformed.")
|
||||||
|
} else {
|
||||||
|
var selector labels.Selector
|
||||||
|
selector, err = unversionedapi.LabelSelectorAsSelector(g.LabelSelector)
|
||||||
|
g.Selector = &selector
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Unable to create Selector for LabelSelector '%s'.Error was: %s", g.LabelSelector, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] Kubernetes middleware configured with the label selector '%s'. Only kubernetes objects matching this label selector will be exposed.", unversionedapi.FormatLabelSelector(g.LabelSelector))
|
||||||
|
}
|
||||||
log.Printf("[debug] Starting kubernetes middleware with k8s API resync period: %s", g.ResyncPeriod)
|
log.Printf("[debug] Starting kubernetes middleware with k8s API resync period: %s", g.ResyncPeriod)
|
||||||
g.APIConn = newdnsController(kubeClient, g.ResyncPeriod)
|
g.APIConn = newdnsController(kubeClient, g.ResyncPeriod, g.Selector)
|
||||||
|
|
||||||
go g.APIConn.Run()
|
go g.APIConn.Run()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue