Commit 52c07683 authored by Tim Hockin's avatar Tim Hockin Committed by GitHub

Merge pull request #39448 from bowei/remove-dns

Remove dns
parents 66a60202 75c29adb
### Version 1.9 (Fri November 18 2016 Bowei Du <bowei@google.com>)
- Add limited ConfigMap support (pr #36775)
### Version 1.8 (Thu September 29 2016 Zihong Zheng <zihongz@google.com>)
- Add support for graceful termination (issue #31807)
### Version 1.7 (Wed August 24 2016 Zihong Zheng <zihongz@google.com>)
- Add support for ExternalName services (pr #31159)
### Version 1.6 (Wed June 29 2016 Girish Kalele <gkalele@google.com>)
- Godeps update for vendor code (skydns/mux)
### Version 1.5 (Thu June 23 2016 Nikhil Jindal <nikhiljindal@google.com>)
- Adding support to return local service (pr #27708)
### Version 1.4 (Tue June 21 2016 Nikhil Jindal <nikhiljindal@google.com>)
- Initialising nodesStore (issue #27820)
### Version 1.3 (Fri June 3 2016 Prashanth.B <beeps@google.com>)
- Fixed SRV record lookup (issue #26116)
### Version 1.2 (Fri May 27 2016 Tim Hockin <thockin@google.com>)
- First Changelog entry
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/build/kube-dns/CHANGELOG.md?pixel)]()
# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM BASEIMAGE
ADD kube-dns /
ENTRYPOINT ["/kube-dns"]
# Maintainers
Tim Hockin <thockin@google.com>
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/build/kube-dns/MAINTAINERS.md?pixel)]()
# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Makefile for the Docker image gcr.io/google_containers/kubedns-<ARCH>
# MAINTAINER: Tim Hockin <thockin@google.com>
# If you update this image please bump the tag value before pushing.
#
# Usage:
# [ARCH=amd64] [TAG=1.6] [REGISTRY=gcr.io/google_containers] [BASEIMAGE=busybox] make (container|push)
# Default registry, arch and tag. This can be overwritten by arguments to make
PLATFORM?=linux
ARCH?=amd64
TAG?=1.9
REGISTRY?=gcr.io/google_containers
GOLANG_VERSION=1.6
KUBE_ROOT=$(shell pwd)/../..
TEMP_DIR:=$(shell mktemp -d)
ifeq ($(ARCH),amd64)
BASEIMAGE?=busybox
endif
ifeq ($(ARCH),arm)
BASEIMAGE?=armel/busybox
endif
ifeq ($(ARCH),arm64)
BASEIMAGE?=aarch64/busybox
endif
ifeq ($(ARCH),ppc64le)
BASEIMAGE?=ppc64le/busybox
endif
ifeq ($(ARCH),s390x)
BASEIMAGE?=s390x/busybox
endif
all: container
container:
# Copy the content in this dir to the temp dir
cp $(KUBE_ROOT)/_output/dockerized/bin/$(PLATFORM)/$(ARCH)/kube-dns $(TEMP_DIR)
cp $(KUBE_ROOT)/build/kube-dns/Dockerfile $(TEMP_DIR)
# Replace BASEIMAGE with the real base image
cd $(TEMP_DIR) && sed -i "s|BASEIMAGE|$(BASEIMAGE)|g" Dockerfile
# And build the image
docker build -t $(REGISTRY)/kubedns-$(ARCH):$(TAG) $(TEMP_DIR)
# delete temp dir
rm -rf $(TEMP_DIR)
push: container
gcloud docker -- push $(REGISTRY)/kubedns-$(ARCH):$(TAG)
.PHONY: all container push
approvers:
- thockin
- boweidu
- mrhohn
reviewers:
- mikedanese
- nikhiljindal
- bprashanth
- luxas
- jessfraz
- david-mcmahon
# DNS in Kubernetes
Kubernetes offers a DNS cluster addon, which most of the supported environments
enable by default. The source code is in [cmd/kube-dns][kube-dns].
The [Kubernetes DNS Admin Guide][dns-admin] provides further details on this plugin.
[kube-dns]: https://github.com/kubernetes/kubernetes/tree/master/cmd/kube-dns
[dns-admin]: http://kubernetes.io/docs/admin/dns/
## Making Changes
The container containing the kube-dns binary needs to be built for every
architecture and pushed to the registry manually whenever the kube-dns binary
has code changes. Every significant change to the functionality should result
in a bump of the TAG in the Makefile.
Any significant changes to the YAML template for `kube-dns` should result a bump
of the version number for the `kube-dns` replication controller and well as the
`version` label. This will permit a rolling update of `kube-dns`.
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/build/kube-dns/README.md?pixel)]()
# Cutting a release
Until we have a proper setup for building this automatically with every binary
release, here are the steps for making a release. We make releases when they
are ready, not on every PR.
1. Build the container for testing:
```
make release
cd build/kube-dns
make container PREFIX=<your-docker-hub> TAG=rc
```
2. Manually deploy this to your own cluster by updating the replication
controller and deleting the running pod(s).
3. Verify it works.
4. Update the TAG version in `Makefile` and update the `Changelog`. Update the
`*.yaml.in` to point to the new tag. Send a PR but mark it as "DO NOT MERGE".
5. Once the PR is approved, build and push the container for real **for all architectures**:
```console
# Build for linux/amd64 (default)
$ make push ARCH=amd64
# ---> gcr.io/google_containers/kube-dns-amd64:TAG
$ make push ARCH=arm
# ---> gcr.io/google_containers/kube-dns-arm:TAG
$ make push ARCH=arm64
# ---> gcr.io/google_containers/kube-dns-arm64:TAG
$ make push ARCH=ppc64le
# ---> gcr.io/google_containers/kube-dns-ppc64le:TAG
$ make push ARCH=s390x
# ---> gcr.io/google_containers/kube-dns-s390x:TAG
```
6. Manually deploy this to your own cluster by updating the replication
controller and deleting the running pod(s).
7. Verify it works.
8. Allow the PR to be merged.
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/build/kube-dns/RELEASES.md?pixel)]()
# kube-dns
kube-dns schedules DNS Pods and Service on the cluster, other pods in cluster can
use the DNS Service’s IP to resolve DNS names.
More details on http://kubernetes.io/docs/admin/dns/.
`kube-dns` schedules DNS Pods and Service on the cluster, other pods in cluster
can use the DNS Service’s IP to resolve DNS names.
* [Administrators guide](http://kubernetes.io/docs/admin/dns/)
* [Code repository](http://www.github.com/kubernetes/dns)
## Manually scale kube-dns Deployment
kube-dns creates only one DNS Pod by default. If
[dns-horizontal-autoscaler](../dns-horizontal-autoscaler/)
is not enabled, you may need to manually scale kube-dns Deployment.
......@@ -14,27 +17,28 @@ Please use below `kubectl scale` command to scale:
kubectl --namespace=kube-system scale deployment kube-dns --replicas=<NUM_YOU_WANT>
```
Do not use `kubectl edit` to modify kube-dns Deployment object if it is controlled by
[Addon Manager](../addon-manager/). Otherwise the modifications will be clobbered,
in addition the replicas count for kube-dns Deployment will be reset to 1. See
[Cluster add-ons README](../README.md) and [#36411](https://github.com/kubernetes/kubernetes/issues/36411)
for reference.
Do not use `kubectl edit` to modify kube-dns Deployment object if it is
controlled by [Addon Manager](../addon-manager/). Otherwise the modifications
will be clobbered, in addition the replicas count for kube-dns Deployment will
be reset to 1. See [Cluster add-ons README](../README.md) and
[#36411](https://github.com/kubernetes/kubernetes/issues/36411) for reference.
## kube-dns Deployment and Service templates
This directory contains the base UNDERSCORE templates that can be used
to generate the kubedns-controller.yaml.in and kubedns.controller.yaml.in needed in Salt format.
This directory contains the base UNDERSCORE templates that can be used to
generate the kubedns-controller.yaml.in and kubedns.controller.yaml.in needed in
Salt format.
Due to a varied preference in templating language choices, the transform
Makefile in this directory should be enhanced to generate all required
formats from the base underscore templates.
Makefile in this directory should be enhanced to generate all required formats
from the base underscore templates.
**N.B.**: When you add a parameter you should also update the various scripts
that supply values for your new parameter. Here is one way you might find those
scripts:
**NOTE WELL**: Developers, when you add a parameter you should also
update the various scripts that supply values for your new parameter.
Here is one way you might find those scripts:
```
cd kubernetes
find [a-zA-Z0-9]* -type f -exec grep kubedns-controller.yaml \{\} \; -print -exec echo \;
cd kubernetes && git grep 'kubedns-controller.yaml'
```
### Base Template files
......@@ -42,17 +46,23 @@ find [a-zA-Z0-9]* -type f -exec grep kubedns-controller.yaml \{\} \; -print -exe
These are the authoritative base templates.
Run 'make' to generate the Salt and Sed yaml templates from these.
```
kubedns-controller.yaml.base
kubedns-svc.yaml.base
```
### Generated Salt files
```
kubedns-controller.yaml.in
kubedns-svc.yaml.in
```
### Generated Sed files
```
kubedns-controller.yaml.sed
kubedns-svc.yaml.sed
```
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/cluster/addons/dns/README.md?pixel)]()
......@@ -47,7 +47,7 @@ spec:
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.9
image: gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.10.1
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
......@@ -96,7 +96,7 @@ spec:
name: metrics
protocol: TCP
- name: dnsmasq
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
image: gcr.io/google_containers/k8s-dns-dnsmasq-amd64:1.10.1
livenessProbe:
httpGet:
path: /healthcheck/dnsmasq
......@@ -124,7 +124,7 @@ spec:
cpu: 150m
memory: 10Mi
- name: sidecar
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.0
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.1
livenessProbe:
httpGet:
path: /metrics
......
......@@ -47,7 +47,7 @@ spec:
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.9
image: gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.10.1
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
......@@ -96,7 +96,7 @@ spec:
name: metrics
protocol: TCP
- name: dnsmasq
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
image: gcr.io/google_containers/k8s-dns-dnsmasq-amd64:1.10.1
livenessProbe:
httpGet:
path: /healthcheck/dnsmasq
......@@ -124,7 +124,7 @@ spec:
cpu: 150m
memory: 10Mi
- name: sidecar
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.0
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.1
livenessProbe:
httpGet:
path: /metrics
......
......@@ -47,7 +47,7 @@ spec:
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.9
image: gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.10.1
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
......@@ -95,7 +95,7 @@ spec:
name: metrics
protocol: TCP
- name: dnsmasq
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
image: gcr.io/google_containers/k8s-dns-dnsmasq-amd64:1.10.1
livenessProbe:
httpGet:
path: /healthcheck/dnsmasq
......@@ -123,7 +123,7 @@ spec:
cpu: 150m
memory: 10Mi
- name: sidecar
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.0
image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.10.1
livenessProbe:
httpGet:
path: /metrics
......
......@@ -26,7 +26,6 @@ filegroup(
"//cmd/kube-apiserver:all-srcs",
"//cmd/kube-controller-manager:all-srcs",
"//cmd/kube-discovery:all-srcs",
"//cmd/kube-dns:all-srcs",
"//cmd/kube-proxy:all-srcs",
"//cmd/kubeadm:all-srcs",
"//cmd/kubectl:all-srcs",
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "kube-dns",
library = ":go_default_library",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["dns.go"],
tags = ["automanaged"],
deps = [
"//cmd/kube-dns/app:go_default_library",
"//cmd/kube-dns/app/options:go_default_library",
"//pkg/client/metrics/prometheus:go_default_library",
"//pkg/util/flag:go_default_library",
"//pkg/util/logs:go_default_library",
"//pkg/version:go_default_library",
"//pkg/version/prometheus:go_default_library",
"//pkg/version/verflag:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/pflag",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//cmd/kube-dns/app:all-srcs",
],
tags = ["automanaged"],
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
tags = ["automanaged"],
deps = [
"//cmd/kube-dns/app/options:go_default_library",
"//pkg/dns:go_default_library",
"//pkg/dns/config:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/skynetservices/skydns/metrics",
"//vendor:github.com/skynetservices/skydns/server",
"//vendor:github.com/spf13/pflag",
"//vendor:k8s.io/client-go/kubernetes",
"//vendor:k8s.io/client-go/rest",
"//vendor:k8s.io/client-go/tools/clientcmd",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//cmd/kube-dns/app/options:all-srcs",
],
tags = ["automanaged"],
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["options.go"],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/dns/federation:go_default_library",
"//pkg/util/validation:go_default_library",
"//vendor:github.com/spf13/pflag",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package options contains flags for initializing a proxy.
package options
import (
"fmt"
_ "net/http/pprof"
"net/url"
"os"
"strings"
"time"
"github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/api"
fed "k8s.io/kubernetes/pkg/dns/federation"
"k8s.io/kubernetes/pkg/util/validation"
)
type KubeDNSConfig struct {
ClusterDomain string
KubeConfigFile string
KubeMasterURL string
InitialSyncTimeout time.Duration
HealthzPort int
DNSBindAddress string
DNSPort int
Federations map[string]string
ConfigMapNs string
ConfigMap string
}
func NewKubeDNSConfig() *KubeDNSConfig {
return &KubeDNSConfig{
ClusterDomain: "cluster.local.",
HealthzPort: 8081,
DNSBindAddress: "0.0.0.0",
DNSPort: 53,
InitialSyncTimeout: 60 * time.Second,
Federations: make(map[string]string),
ConfigMapNs: api.NamespaceSystem,
ConfigMap: "", // default to using command line flags
}
}
type clusterDomainVar struct {
val *string
}
func (m clusterDomainVar) Set(v string) error {
v = strings.TrimSuffix(v, ".")
segments := strings.Split(v, ".")
for _, segment := range segments {
if errs := validation.IsDNS1123Label(segment); len(errs) > 0 {
return fmt.Errorf("Not a valid DNS label. %v", errs)
}
}
if !strings.HasSuffix(v, ".") {
v = fmt.Sprintf("%s.", v)
}
*m.val = v
return nil
}
func (m clusterDomainVar) String() string {
return *m.val
}
func (m clusterDomainVar) Type() string {
return "string"
}
type kubeMasterURLVar struct {
val *string
}
func (m kubeMasterURLVar) Set(v string) error {
parsedURL, err := url.Parse(os.ExpandEnv(v))
if err != nil {
return fmt.Errorf("failed to parse kube-master-url")
}
if parsedURL.Scheme == "" || parsedURL.Host == "" || parsedURL.Host == ":" {
return fmt.Errorf("invalid kube-master-url specified")
}
*m.val = v
return nil
}
func (m kubeMasterURLVar) String() string {
return *m.val
}
func (m kubeMasterURLVar) Type() string {
return "string"
}
type federationsVar struct {
nameDomainMap map[string]string
}
func (fv federationsVar) Set(keyVal string) error {
return fed.ParseFederationsFlag(keyVal, fv.nameDomainMap)
}
func (fv federationsVar) String() string {
var splits []string
for name, domain := range fv.nameDomainMap {
splits = append(splits, fmt.Sprintf("%s=%s", name, domain))
}
return strings.Join(splits, ",")
}
func (fv federationsVar) Type() string {
return "[]string"
}
func (s *KubeDNSConfig) AddFlags(fs *pflag.FlagSet) {
fs.Var(clusterDomainVar{&s.ClusterDomain}, "domain",
"domain under which to create names")
fs.StringVar(&s.KubeConfigFile, "kubecfg-file", s.KubeConfigFile,
"Location of kubecfg file for access to kubernetes master service;"+
" --kube-master-url overrides the URL part of this; if neither this nor"+
" --kube-master-url are provided, defaults to service account tokens")
fs.Var(kubeMasterURLVar{&s.KubeMasterURL}, "kube-master-url",
"URL to reach kubernetes master. Env variables in this flag will be expanded.")
fs.IntVar(&s.HealthzPort, "healthz-port", s.HealthzPort,
"port on which to serve a kube-dns HTTP readiness probe.")
fs.StringVar(&s.DNSBindAddress, "dns-bind-address", s.DNSBindAddress,
"address on which to serve DNS requests.")
fs.IntVar(&s.DNSPort, "dns-port", s.DNSPort, "port on which to serve DNS requests.")
fs.Var(federationsVar{s.Federations}, "federations",
"a comma separated list of the federation names and their corresponding"+
" domain names to which this cluster belongs. Example:"+
" \"myfederation1=example.com,myfederation2=example2.com,myfederation3=example.com\"."+
" It is an error to set both the federations and config-map flags.")
fs.MarkDeprecated("federations", "use config-map instead. Will be removed in future version")
fs.StringVar(&s.ConfigMapNs, "config-map-namespace", s.ConfigMapNs,
"namespace for the config-map")
fs.StringVar(&s.ConfigMap, "config-map", s.ConfigMap,
"config-map name. If empty, then the config-map will not used. Cannot be "+
" used in conjunction with federations flag. config-map contains "+
"dynamically adjustable configuration.")
fs.DurationVar(&s.InitialSyncTimeout, "initial-sync-timeout", s.InitialSyncTimeout,
"Timeout for initial resource sync.")
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/golang/glog"
"github.com/skynetservices/skydns/metrics"
"github.com/skynetservices/skydns/server"
"github.com/spf13/pflag"
"k8s.io/kubernetes/cmd/kube-dns/app/options"
"k8s.io/kubernetes/pkg/dns"
dnsconfig "k8s.io/kubernetes/pkg/dns/config"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
type KubeDNSServer struct {
// DNS domain name.
domain string
healthzPort int
dnsBindAddress string
dnsPort int
kd *dns.KubeDNS
}
func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer {
kubeClient, err := newKubeClient(config)
if err != nil {
glog.Fatalf("Failed to create a kubernetes client: %v", err)
}
var configSync dnsconfig.Sync
if config.ConfigMap == "" {
glog.V(0).Infof("ConfigMap not configured, using values from command line flags")
configSync = dnsconfig.NewNopSync(
&dnsconfig.Config{Federations: config.Federations})
} else {
glog.V(0).Infof("Using configuration read from ConfigMap: %v:%v",
config.ConfigMapNs, config.ConfigMap)
configSync = dnsconfig.NewSync(
kubeClient, config.ConfigMapNs, config.ConfigMap)
}
return &KubeDNSServer{
domain: config.ClusterDomain,
healthzPort: config.HealthzPort,
dnsBindAddress: config.DNSBindAddress,
dnsPort: config.DNSPort,
kd: dns.NewKubeDNS(kubeClient, config.ClusterDomain, config.InitialSyncTimeout, configSync),
}
}
func newKubeClient(dnsConfig *options.KubeDNSConfig) (kubernetes.Interface, error) {
var config *rest.Config
var err error
if dnsConfig.KubeConfigFile == "" {
config, err = rest.InClusterConfig()
if err != nil {
return nil, err
}
} else {
config, err = clientcmd.BuildConfigFromFlags(
dnsConfig.KubeMasterURL, dnsConfig.KubeConfigFile)
if err != nil {
return nil, err
}
}
return kubernetes.NewForConfig(config)
}
func (server *KubeDNSServer) Run() {
pflag.VisitAll(func(flag *pflag.Flag) {
glog.V(0).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
})
setupSignalHandlers()
server.startSkyDNSServer()
server.kd.Start()
server.setupHandlers()
glog.V(0).Infof("Status HTTP port %v", server.healthzPort)
glog.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", server.healthzPort), nil))
}
// setupHealthzHandlers sets up a readiness and liveness endpoint for kube2sky.
func (server *KubeDNSServer) setupHandlers() {
glog.V(0).Infof("Setting up Healthz Handler (/readiness)")
http.HandleFunc("/readiness", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "ok\n")
})
glog.V(0).Infof("Setting up cache handler (/cache)")
http.HandleFunc("/cache", func(w http.ResponseWriter, req *http.Request) {
serializedJSON, err := server.kd.GetCacheAsJSON()
if err == nil {
fmt.Fprint(w, serializedJSON)
} else {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, err)
}
})
}
// setupSignalHandlers installs signal handler to ignore SIGINT and
// SIGTERM. This daemon will be killed by SIGKILL after the grace
// period to allow for some manner of graceful shutdown.
func setupSignalHandlers() {
sigChan := make(chan os.Signal)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
glog.V(0).Infof("Ignoring signal %v (can only be terminated by SIGKILL)", <-sigChan)
}()
}
func (d *KubeDNSServer) startSkyDNSServer() {
glog.V(0).Infof("Starting SkyDNS server (%v:%v)", d.dnsBindAddress, d.dnsPort)
skydnsConfig := &server.Config{
Domain: d.domain,
DnsAddr: fmt.Sprintf("%s:%d", d.dnsBindAddress, d.dnsPort),
}
server.SetDefaults(skydnsConfig)
s := server.New(d.kd, skydnsConfig)
if err := metrics.Metrics(); err != nil {
glog.Fatalf("Skydns metrics error: %s", err)
} else if metrics.Port != "" {
glog.V(0).Infof("Skydns metrics enabled (%v:%v)", metrics.Path, metrics.Port)
} else {
glog.V(0).Infof("Skydns metrics not enabled")
}
go s.Run()
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/golang/glog"
"github.com/spf13/pflag"
"k8s.io/kubernetes/cmd/kube-dns/app"
"k8s.io/kubernetes/cmd/kube-dns/app/options"
"k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs"
"k8s.io/kubernetes/pkg/version"
"k8s.io/kubernetes/pkg/version/verflag"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
)
func main() {
config := options.NewKubeDNSConfig()
config.AddFlags(pflag.CommandLine)
flag.InitFlags()
logs.InitLogs()
defer logs.FlushLogs()
verflag.PrintAndExitIfRequested()
glog.V(0).Infof("version: %+v", version.Get())
server := app.NewKubeDNSServerDefault(config)
server.Run()
}
......@@ -15,7 +15,6 @@ cmd/kube-apiserver/app/options
cmd/kube-controller-manager
cmd/kube-controller-manager/app/options
cmd/kube-discovery
cmd/kube-dns
cmd/kube-proxy
cmd/kubeadm
cmd/kubeadm
......
......@@ -23,7 +23,6 @@ readonly KUBE_GOPATH="${KUBE_OUTPUT}/go"
# kube::build::source_targets in build/common.sh as well.
kube::golang::server_targets() {
local targets=(
cmd/kube-dns
cmd/kube-proxy
cmd/kube-apiserver
cmd/kube-controller-manager
......@@ -189,7 +188,6 @@ readonly KUBE_ALL_BINARIES=("${KUBE_ALL_TARGETS[@]##*/}")
readonly KUBE_STATIC_LIBRARIES=(
kube-apiserver
kube-controller-manager
kube-dns
kube-scheduler
kube-proxy
kube-discovery
......
......@@ -85,7 +85,6 @@ filegroup(
"//pkg/controller:all-srcs",
"//pkg/conversion:all-srcs",
"//pkg/credentialprovider:all-srcs",
"//pkg/dns:all-srcs",
"//pkg/fieldpath:all-srcs",
"//pkg/fields:all-srcs",
"//pkg/generated:all-srcs",
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dns.go",
"doc.go",
],
tags = ["automanaged"],
deps = [
"//pkg/dns/config:go_default_library",
"//pkg/dns/treecache:go_default_library",
"//pkg/dns/util:go_default_library",
"//pkg/util/validation:go_default_library",
"//pkg/util/wait:go_default_library",
"//vendor:github.com/coreos/etcd/client",
"//vendor:github.com/golang/glog",
"//vendor:github.com/miekg/dns",
"//vendor:github.com/skynetservices/skydns/msg",
"//vendor:k8s.io/client-go/kubernetes",
"//vendor:k8s.io/client-go/pkg/api/v1",
"//vendor:k8s.io/client-go/pkg/apis/meta/v1",
"//vendor:k8s.io/client-go/pkg/runtime",
"//vendor:k8s.io/client-go/pkg/watch",
"//vendor:k8s.io/client-go/tools/cache",
],
)
go_test(
name = "go_default_test",
srcs = ["dns_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/dns/config:go_default_library",
"//pkg/dns/treecache:go_default_library",
"//pkg/dns/util:go_default_library",
"//pkg/util/sets:go_default_library",
"//vendor:github.com/coreos/etcd/client",
"//vendor:github.com/miekg/dns",
"//vendor:github.com/skynetservices/skydns/msg",
"//vendor:github.com/skynetservices/skydns/server",
"//vendor:github.com/stretchr/testify/assert",
"//vendor:github.com/stretchr/testify/require",
"//vendor:k8s.io/client-go/kubernetes/fake",
"//vendor:k8s.io/client-go/pkg/api/v1",
"//vendor:k8s.io/client-go/pkg/apis/meta/v1",
"//vendor:k8s.io/client-go/tools/cache",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/dns/config:all-srcs",
"//pkg/dns/federation:all-srcs",
"//pkg/dns/treecache:all-srcs",
"//pkg/dns/util:all-srcs",
],
tags = ["automanaged"],
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"config.go",
"mocksync.go",
"nopsync.go",
"sync.go",
],
tags = ["automanaged"],
deps = [
"//pkg/dns/federation:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/client-go/kubernetes",
"//vendor:k8s.io/client-go/pkg/api/v1",
"//vendor:k8s.io/client-go/pkg/apis/meta/v1",
"//vendor:k8s.io/client-go/pkg/fields",
"//vendor:k8s.io/client-go/pkg/runtime",
"//vendor:k8s.io/client-go/pkg/util/wait",
"//vendor:k8s.io/client-go/pkg/watch",
"//vendor:k8s.io/client-go/tools/cache",
],
)
go_test(
name = "go_default_test",
srcs = ["config_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = ["//vendor:github.com/stretchr/testify/assert"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
types "k8s.io/client-go/pkg/apis/meta/v1"
fed "k8s.io/kubernetes/pkg/dns/federation"
)
// Config populated either from the configuration source (command
// line flags or via the config map mechanism).
type Config struct {
// The inclusion of TypeMeta is to ensure future compatibility if the
// Config object was populated directly via a Kubernetes API mechanism.
//
// For example, instead of the custom implementation here, the
// configuration could be obtained from an API that unifies
// command-line flags, config-map, etc mechanisms.
types.TypeMeta
// Map of federation names that the cluster in which this kube-dns
// is running belongs to, to the corresponding domain names.
Federations map[string]string `json:"federations"`
}
func NewDefaultConfig() *Config {
return &Config{
Federations: make(map[string]string),
}
}
// IsValid returns whether or not the configuration is valid.
func (config *Config) Validate() error {
if err := config.validateFederations(); err != nil {
return err
}
return nil
}
func (config *Config) validateFederations() error {
for name, domain := range config.Federations {
if err := fed.ValidateName(name); err != nil {
return err
}
if err := fed.ValidateDomain(domain); err != nil {
return err
}
}
return nil
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidate(t *testing.T) {
for _, testCase := range []struct {
config *Config
hasError bool
}{
{
config: &Config{Federations: map[string]string{}},
},
{
config: &Config{
Federations: map[string]string{
"abc": "d.e.f",
},
},
},
{
config: &Config{
Federations: map[string]string{
"a.b": "cdef",
},
},
hasError: true,
},
} {
err := testCase.config.Validate()
if !testCase.hasError {
assert.Nil(t, err, "should be valid", testCase)
} else {
assert.NotNil(t, err, "should not be valid", testCase)
}
}
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
// MockSync is a testing mock.
type MockSync struct {
// Config that will be returned from Once().
Config *Config
// Error that will be returned from Once().
Error error
// Chan to send new configurations on.
Chan chan *Config
}
var _ Sync = (*MockSync)(nil)
func NewMockSync(config *Config, error error) *MockSync {
return &MockSync{
Config: config,
Error: error,
Chan: make(chan *Config),
}
}
func (sync *MockSync) Once() (*Config, error) {
return sync.Config, sync.Error
}
func (sync *MockSync) Periodic() <-chan *Config {
return sync.Chan
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
// nopSync does no synchronization, used when the DNS server is
// started without a ConfigMap configured.
type nopSync struct {
config *Config
}
var _ Sync = (*nopSync)(nil)
func NewNopSync(config *Config) Sync {
return &nopSync{config: config}
}
func (sync *nopSync) Once() (*Config, error) {
return sync.config, nil
}
func (sync *nopSync) Periodic() <-chan *Config {
return make(chan *Config)
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
metav1 "k8s.io/client-go/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/pkg/runtime"
"k8s.io/client-go/pkg/util/wait"
"k8s.io/client-go/pkg/watch"
"k8s.io/client-go/tools/cache"
fed "k8s.io/kubernetes/pkg/dns/federation"
"time"
"github.com/golang/glog"
)
// Sync manages synchronization of the config map.
type Sync interface {
// Once does a blocking synchronization of the config map. If the
// ConfigMap fails to validate, this method will return nil, err.
Once() (*Config, error)
// Start a periodic synchronization of the configuration map. When a
// successful configuration map update is detected, the
// configuration will be sent to the channel.
//
// It is an error to call this more than once.
Periodic() <-chan *Config
}
// NewSync for ConfigMap from namespace `ns` and `name`.
func NewSync(client kubernetes.Interface, ns string, name string) Sync {
sync := &kubeSync{
ns: ns,
name: name,
client: client,
channel: make(chan *Config),
}
listWatch := &cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
options.FieldSelector = fields.Set{"metadata.name": name}.AsSelector().String()
return client.Core().ConfigMaps(ns).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
options.FieldSelector = fields.Set{"metadata.name": name}.AsSelector().String()
return client.Core().ConfigMaps(ns).Watch(options)
},
}
store, controller := cache.NewInformer(
listWatch,
&v1.ConfigMap{},
time.Duration(0),
cache.ResourceEventHandlerFuncs{
AddFunc: sync.onAdd,
DeleteFunc: sync.onDelete,
UpdateFunc: sync.onUpdate,
})
sync.store = store
sync.controller = controller
return sync
}
// kubeSync implements Sync for the Kubernetes API.
type kubeSync struct {
ns string
name string
client kubernetes.Interface
store cache.Store
controller *cache.Controller
channel chan *Config
latestVersion string
}
var _ Sync = (*kubeSync)(nil)
func (sync *kubeSync) Once() (*Config, error) {
cm, err := sync.client.Core().ConfigMaps(sync.ns).Get(sync.name, metav1.GetOptions{})
if err != nil {
glog.Errorf("Error getting ConfigMap %v:%v err: %v",
sync.ns, sync.name, err)
return nil, err
}
config, _, err := sync.processUpdate(cm)
return config, err
}
func (sync *kubeSync) Periodic() <-chan *Config {
go sync.controller.Run(wait.NeverStop)
return sync.channel
}
func (sync *kubeSync) toConfigMap(obj interface{}) *v1.ConfigMap {
cm, ok := obj.(*v1.ConfigMap)
if !ok {
glog.Fatalf("Expected ConfigMap, got %T", obj)
}
return cm
}
func (sync *kubeSync) onAdd(obj interface{}) {
cm := sync.toConfigMap(obj)
glog.V(2).Infof("ConfigMap %s:%s was created", sync.ns, sync.name)
config, updated, err := sync.processUpdate(cm)
if updated && err == nil {
sync.channel <- config
}
}
func (sync *kubeSync) onDelete(_ interface{}) {
glog.V(2).Infof("ConfigMap %s:%s was deleted, reverting to default configuration",
sync.ns, sync.name)
sync.latestVersion = ""
sync.channel <- NewDefaultConfig()
}
func (sync *kubeSync) onUpdate(_, obj interface{}) {
cm := sync.toConfigMap(obj)
glog.V(2).Infof("ConfigMap %s:%s was updated", sync.ns, sync.name)
config, changed, err := sync.processUpdate(cm)
if changed && err == nil {
sync.channel <- config
}
}
func (sync *kubeSync) processUpdate(cm *v1.ConfigMap) (config *Config, changed bool, err error) {
glog.V(4).Infof("processUpdate ConfigMap %+v", *cm)
if cm.ObjectMeta.ResourceVersion != sync.latestVersion {
glog.V(3).Infof("Updating config to version %v (was %v)",
cm.ObjectMeta.ResourceVersion, sync.latestVersion)
changed = true
sync.latestVersion = cm.ObjectMeta.ResourceVersion
} else {
glog.V(4).Infof("Config was unchanged (version %v)", sync.latestVersion)
return
}
config = &Config{}
if err = sync.updateFederations(cm, config); err != nil {
glog.Errorf("Invalid configuration, ignoring update")
return
}
if err = config.Validate(); err != nil {
glog.Errorf("Invalid onfiguration: %v (value was %+v), ignoring update",
err, config)
config = nil
return
}
return
}
func (sync *kubeSync) updateFederations(cm *v1.ConfigMap, config *Config) (err error) {
if flagValue, ok := cm.Data["federations"]; ok {
config.Federations = make(map[string]string)
if err = fed.ParseFederationsFlag(flagValue, config.Federations); err != nil {
glog.Errorf("Invalid federations value: %v (value was %q)",
err, cm.Data["federations"])
return
}
glog.V(2).Infof("Updated federations to %v", config.Federations)
} else {
glog.V(2).Infof("No federations present")
}
return
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package DNS provides a backend for the skydns DNS server started by the
// kubedns cluster addon. It exposes the 2 interface method: Records and
// ReverseRecord, which skydns invokes according to the DNS queries it
// receives. It serves these records by consulting an in memory tree
// populated with Kubernetes Services and Endpoints received from the Kubernetes
// API server.
package dns // import "k8s.io/kubernetes/pkg/dns"
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["federation.go"],
tags = ["automanaged"],
deps = ["//pkg/util/validation:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["federation_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = ["//vendor:github.com/stretchr/testify/assert"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Fed contains federation specific DNS code.
package fed
import (
"errors"
"fmt"
"strings"
"k8s.io/kubernetes/pkg/util/validation"
)
var ErrExpectedKeyEqualsValue = errors.New("invalid format, must be key=value")
// ParseFederationsFlag parses the federations command line flag. The
// flag is a comma-separated list of zero or more "name=label" pairs,
// e.g. "a=b,c=d".
func ParseFederationsFlag(str string, federations map[string]string) error {
if strings.TrimSpace(str) == "" {
return nil
}
for _, val := range strings.Split(str, ",") {
splits := strings.SplitN(strings.TrimSpace(val), "=", 2)
if len(splits) != 2 {
return ErrExpectedKeyEqualsValue
}
name := strings.TrimSpace(splits[0])
domain := strings.TrimSpace(splits[1])
if err := ValidateName(name); err != nil {
return err
}
if err := ValidateDomain(domain); err != nil {
return err
}
federations[name] = domain
}
return nil
}
// ValidateName checks the validity of a federation name.
func ValidateName(name string) error {
if errs := validation.IsDNS1123Label(name); len(errs) != 0 {
return fmt.Errorf("%q not a valid federation name: %q", name, errs)
}
return nil
}
// ValidateDomain checks the validity of a federation label.
func ValidateDomain(name string) error {
// The federation domain name need not strictly be domain names, we
// accept valid dns names with subdomain components.
if errs := validation.IsDNS1123Subdomain(name); len(errs) != 0 {
return fmt.Errorf("%q not a valid domain name: %q", name, errs)
}
return nil
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fed
import (
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)
func TestParseFederationsFlag(t *testing.T) {
type TestCase struct {
input string
hasError bool
expected map[string]string
}
for _, testCase := range []TestCase{
{input: "", expected: make(map[string]string)},
{input: "a=b", expected: map[string]string{"a": "b"}},
{input: "a=b,cc=dd", expected: map[string]string{"a": "b", "cc": "dd"}},
{input: "abc=d.e.f", expected: map[string]string{"abc": "d.e.f"}},
{input: "ccdd", hasError: true},
{input: "a=b,ccdd", hasError: true},
{input: "-", hasError: true},
{input: "a.b.c=d.e.f", hasError: true},
} {
output := make(map[string]string)
err := ParseFederationsFlag(testCase.input, output)
if !testCase.hasError {
assert.Nil(t, err, "unexpected err", testCase)
assert.True(t, reflect.DeepEqual(
testCase.expected, output), output, testCase)
} else {
assert.NotNil(t, err, testCase)
}
}
}
func TestValidateName(t *testing.T) {
// More complete testing is done in validation.IsDNS1123Label. These
// tests are to catch issues specific to the implementation of
// kube-dns.
assert.NotNil(t, ValidateName(""))
assert.NotNil(t, ValidateName("."))
assert.NotNil(t, ValidateName("ab.cd"))
assert.Nil(t, ValidateName("abcd"))
}
func TestValidateDomain(t *testing.T) {
// More complete testing is done in
// validation.IsDNS1123Subdomain. These tests are to catch issues
// specific to the implementation of kube-dns.
assert.NotNil(t, ValidateDomain(""))
assert.NotNil(t, ValidateDomain("."))
assert.Nil(t, ValidateDomain("ab.cd"))
assert.Nil(t, ValidateDomain("abcd"))
assert.Nil(t, ValidateDomain("a.b.c.d"))
}
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["treecache.go"],
tags = ["automanaged"],
deps = ["//vendor:github.com/skynetservices/skydns/msg"],
)
go_test(
name = "go_default_test",
srcs = ["treecache_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = ["//vendor:github.com/skynetservices/skydns/msg"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package treecache
import (
"encoding/json"
"strings"
skymsg "github.com/skynetservices/skydns/msg"
)
type TreeCache interface {
// GetEntry with the given key for the given path.
GetEntry(key string, path ...string) (interface{}, bool)
// Get a list of values including wildcards labels (e.g. "*").
GetValuesForPathWithWildcards(path ...string) []*skymsg.Service
// SetEntry creates the entire path if it doesn't already exist in
// the cache, then sets the given service record under the given
// key. The path this entry would have occupied in an etcd datastore
// is computed from the given fqdn and stored as the "Key" of the
// skydns service; this is only required because skydns expects the
// service record to contain a key in a specific format (presumably
// for legacy compatibility). Note that the fqnd string typically
// contains both the key and all elements in the path.
SetEntry(key string, val *skymsg.Service, fqdn string, path ...string)
// SetSubCache inserts the given subtree under the given
// path:key. Usually the key is the name of a Kubernetes Service,
// and the path maps to the cluster subdomains matching the Service.
SetSubCache(key string, subCache TreeCache, path ...string)
// DeletePath removes all entries associated with a given path.
DeletePath(path ...string) bool
// Serialize dumps a JSON representation of the cache.
Serialize() (string, error)
}
type treeCache struct {
ChildNodes map[string]*treeCache
Entries map[string]interface{}
}
func NewTreeCache() TreeCache {
return &treeCache{
ChildNodes: make(map[string]*treeCache),
Entries: make(map[string]interface{}),
}
}
func (cache *treeCache) Serialize() (string, error) {
prettyJSON, err := json.MarshalIndent(cache, "", "\t")
if err != nil {
return "", err
}
return string(prettyJSON), nil
}
func (cache *treeCache) SetEntry(key string, val *skymsg.Service, fqdn string, path ...string) {
// TODO: Consolidate setEntry and setSubCache into a single method with a
// type switch.
// TODO: Instead of passing the fqdn as an argument, we can reconstruct
// it from the path, provided callers always pass the full path to the
// object. This is currently *not* the case, since callers first create
// a new, empty node, populate it, then parent it under the right path.
// So we don't know the full key till the final parenting operation.
node := cache.ensureChildNode(path...)
// This key is used to construct the "target" for SRV record lookups.
// For normal service/endpoint lookups, this will result in a key like:
// /skydns/local/cluster/svc/svcNS/svcName/record-hash
// but for headless services that govern pods requesting a specific
// hostname (as used by petset), this will end up being:
// /skydns/local/cluster/svc/svcNS/svcName/pod-hostname
val.Key = skymsg.Path(fqdn)
node.Entries[key] = val
}
func (cache *treeCache) getSubCache(path ...string) *treeCache {
childCache := cache
for _, subpath := range path {
childCache = childCache.ChildNodes[subpath]
if childCache == nil {
return nil
}
}
return childCache
}
func (cache *treeCache) SetSubCache(key string, subCache TreeCache, path ...string) {
node := cache.ensureChildNode(path...)
node.ChildNodes[key] = subCache.(*treeCache)
}
func (cache *treeCache) GetEntry(key string, path ...string) (interface{}, bool) {
childNode := cache.getSubCache(path...)
if childNode == nil {
return nil, false
}
val, ok := childNode.Entries[key]
return val, ok
}
func (cache *treeCache) GetValuesForPathWithWildcards(path ...string) []*skymsg.Service {
retval := []*skymsg.Service{}
nodesToExplore := []*treeCache{cache}
for idx, subpath := range path {
nextNodesToExplore := []*treeCache{}
if idx == len(path)-1 {
// if path ends on an entry, instead of a child node, add the entry
for _, node := range nodesToExplore {
if subpath == "*" {
nextNodesToExplore = append(nextNodesToExplore, node)
} else {
if val, ok := node.Entries[subpath]; ok {
retval = append(retval, val.(*skymsg.Service))
} else {
childNode := node.ChildNodes[subpath]
if childNode != nil {
nextNodesToExplore = append(nextNodesToExplore, childNode)
}
}
}
}
nodesToExplore = nextNodesToExplore
break
}
if subpath == "*" {
for _, node := range nodesToExplore {
for subkey, subnode := range node.ChildNodes {
if !strings.HasPrefix(subkey, "_") {
nextNodesToExplore = append(nextNodesToExplore, subnode)
}
}
}
} else {
for _, node := range nodesToExplore {
childNode := node.ChildNodes[subpath]
if childNode != nil {
nextNodesToExplore = append(nextNodesToExplore, childNode)
}
}
}
nodesToExplore = nextNodesToExplore
}
for _, node := range nodesToExplore {
for _, val := range node.Entries {
retval = append(retval, val.(*skymsg.Service))
}
}
return retval
}
func (cache *treeCache) DeletePath(path ...string) bool {
if len(path) == 0 {
return false
}
if parentNode := cache.getSubCache(path[:len(path)-1]...); parentNode != nil {
name := path[len(path)-1]
if _, ok := parentNode.ChildNodes[name]; ok {
delete(parentNode.ChildNodes, name)
return true
}
// ExternalName services are stored with their name as the leaf key
if _, ok := parentNode.Entries[name]; ok {
delete(parentNode.Entries, name)
return true
}
}
return false
}
func (cache *treeCache) appendValues(recursive bool, ref [][]interface{}) {
for _, value := range cache.Entries {
ref[0] = append(ref[0], value)
}
if recursive {
for _, node := range cache.ChildNodes {
node.appendValues(recursive, ref)
}
}
}
func (cache *treeCache) ensureChildNode(path ...string) *treeCache {
childNode := cache
for _, subpath := range path {
newNode, ok := childNode.ChildNodes[subpath]
if !ok {
newNode = NewTreeCache().(*treeCache)
childNode.ChildNodes[subpath] = newNode
}
childNode = newNode
}
return childNode
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package treecache
import (
"testing"
"github.com/skynetservices/skydns/msg"
)
func TestTreeCache(t *testing.T) {
tc := NewTreeCache()
{
_, ok := tc.GetEntry("key1", "p1", "p2")
if ok {
t.Errorf("key should not exist")
}
}
checkExists := func(key string, expectedSvc *msg.Service, path ...string) {
svc, ok := tc.GetEntry(key, path...)
if !ok {
t.Fatalf("key %v should exist", key)
}
if svc := svc.(*msg.Service); svc != nil {
if svc != expectedSvc {
t.Errorf("value is not correct (%v != %v)", svc, expectedSvc)
}
} else {
t.Errorf("entry is not of the right type: %T", svc)
}
}
setEntryTC := []struct {
key string
svc *msg.Service
fqdn string
path []string
}{
{"key1", &msg.Service{}, "key1.p2.p1.", []string{"p1", "p2"}},
{"key2", &msg.Service{}, "key2.p2.p1.", []string{"p1", "p2"}},
{"key3", &msg.Service{}, "key3.p2.p1.", []string{"p1", "p3"}},
}
for _, testCase := range setEntryTC {
tc.SetEntry(testCase.key, testCase.svc, testCase.fqdn, testCase.path...)
checkExists(testCase.key, testCase.svc, testCase.path...)
}
wildcardTC := []struct {
path []string
count int
}{
{[]string{"p1"}, 0},
{[]string{"p1", "p2"}, 2},
{[]string{"p1", "p3"}, 1},
{[]string{"p1", "p2", "key1"}, 1},
{[]string{"p1", "p2", "key2"}, 1},
{[]string{"p1", "p2", "key3"}, 0},
{[]string{"p1", "p3", "key3"}, 1},
{[]string{"p1", "p2", "*"}, 2},
{[]string{"p1", "*", "*"}, 3},
}
for _, testCase := range wildcardTC {
services := tc.GetValuesForPathWithWildcards(testCase.path...)
if len(services) != testCase.count {
t.Fatalf("Expected %v services for path %v, got %v",
testCase.count, testCase.path, len(services))
}
}
// Delete some paths
if !tc.DeletePath("p1", "p2") {
t.Fatal("should delete path p2.p1.")
}
if _, ok := tc.GetEntry("key3", "p1", "p3"); !ok {
t.Error("should not affect p3.p1.")
}
if tc.DeletePath("p1", "p2") {
t.Fatalf("should not be able to delete p2.p1")
}
if !tc.DeletePath("p1", "p3") {
t.Fatalf("should be able to delete p3.p1")
}
if tc.DeletePath("p1", "p3") {
t.Fatalf("should not be able to delete p3.t1")
}
for _, testCase := range []struct {
k string
p []string
}{
{"key1", []string{"p1", "p2"}},
{"key2", []string{"p1", "p2"}},
{"key3", []string{"p1", "p3"}},
} {
if _, ok := tc.GetEntry(testCase.k, testCase.p...); ok {
t.Error("path should not exist")
}
}
}
func TestTreeCacheSetSubCache(t *testing.T) {
tc := NewTreeCache()
m := &msg.Service{}
branch := NewTreeCache()
branch.SetEntry("key1", m, "key", "p2")
tc.SetSubCache("p1", branch, "p0")
if _, ok := tc.GetEntry("key1", "p0", "p1", "p2"); !ok {
t.Errorf("should be able to get entry p0.p1.p2.key1")
}
}
func TestTreeCacheSerialize(t *testing.T) {
tc := NewTreeCache()
tc.SetEntry("key1", &msg.Service{}, "key1.p2.p1.", "p1", "p2")
const expected = `{
"ChildNodes": {
"p1": {
"ChildNodes": {
"p2": {
"ChildNodes": {},
"Entries": {
"key1": {}
}
}
},
"Entries": {}
}
},
"Entries": {}
}`
actual, err := tc.Serialize()
if err != nil {
}
if actual != expected {
t.Errorf("expected %q, got %q", expected, actual)
}
}
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["util.go"],
tags = ["automanaged"],
deps = [
"//vendor:github.com/golang/glog",
"//vendor:github.com/skynetservices/skydns/msg",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"fmt"
"hash/fnv"
"strings"
"github.com/golang/glog"
"github.com/skynetservices/skydns/msg"
)
const (
// ArpaSuffix is the standard suffix for PTR IP reverse lookups.
ArpaSuffix = ".in-addr.arpa."
// defaultPriority used for service records
defaultPriority = 10
// defaultWeight used for service records
defaultWeight = 10
// defaultTTL used for service records
defaultTTL = 30
)
// extractIP turns a standard PTR reverse record lookup name
// into an IP address
func ExtractIP(reverseName string) (string, bool) {
if !strings.HasSuffix(reverseName, ArpaSuffix) {
return "", false
}
search := strings.TrimSuffix(reverseName, ArpaSuffix)
// reverse the segments and then combine them
segments := ReverseArray(strings.Split(search, "."))
return strings.Join(segments, "."), true
}
// ReverseArray reverses an array.
func ReverseArray(arr []string) []string {
for i := 0; i < len(arr)/2; i++ {
j := len(arr) - i - 1
arr[i], arr[j] = arr[j], arr[i]
}
return arr
}
// Returns record in a format that SkyDNS understands.
// Also return the hash of the record.
func GetSkyMsg(ip string, port int) (*msg.Service, string) {
msg := NewServiceRecord(ip, port)
hash := HashServiceRecord(msg)
glog.V(5).Infof("Constructed new DNS record: %s, hash:%s",
fmt.Sprintf("%v", msg), hash)
return msg, fmt.Sprintf("%x", hash)
}
// NewServiceRecord creates a new service DNS message.
func NewServiceRecord(ip string, port int) *msg.Service {
return &msg.Service{
Host: ip,
Port: port,
Priority: defaultPriority,
Weight: defaultWeight,
Ttl: defaultTTL,
}
}
// HashServiceRecord hashes the string representation of a DNS
// message.
func HashServiceRecord(msg *msg.Service) string {
s := fmt.Sprintf("%v", msg)
h := fnv.New32a()
h.Write([]byte(s))
return fmt.Sprintf("%x", h.Sum32())
}
......@@ -151,7 +151,6 @@ go_library(
"//pkg/controller/petset:go_default_library",
"//pkg/controller/replicaset:go_default_library",
"//pkg/controller/replication:go_default_library",
"//pkg/dns/federation:go_default_library",
"//pkg/fields:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
......
......@@ -24,7 +24,6 @@ import (
"k8s.io/kubernetes/pkg/api/v1"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
fed "k8s.io/kubernetes/pkg/dns/federation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/intstr"
......@@ -43,6 +42,7 @@ type dnsConfigMapTest struct {
labels []string
cm *v1.ConfigMap
fedMap map[string]string
isValid bool
dnsPod *v1.Pod
......@@ -90,23 +90,25 @@ func (t *dnsConfigMapTest) run() {
t.labels = []string{"abc", "ghi"}
valid1 := map[string]string{"federations": t.labels[0] + "=def"}
valid1m := map[string]string{t.labels[0]: "def"}
valid2 := map[string]string{"federations": t.labels[1] + "=xyz"}
valid2m := map[string]string{t.labels[1]: "xyz"}
invalid := map[string]string{"federations": "invalid.map=xyz"}
By("empty -> valid1")
t.setConfigMap(&v1.ConfigMap{Data: valid1}, true)
t.setConfigMap(&v1.ConfigMap{Data: valid1}, valid1m, true)
t.validate()
By("valid1 -> valid2")
t.setConfigMap(&v1.ConfigMap{Data: valid2}, true)
t.setConfigMap(&v1.ConfigMap{Data: valid2}, valid2m, true)
t.validate()
By("valid2 -> invalid")
t.setConfigMap(&v1.ConfigMap{Data: invalid}, false)
t.setConfigMap(&v1.ConfigMap{Data: invalid}, nil, false)
t.validate()
By("invalid -> valid1")
t.setConfigMap(&v1.ConfigMap{Data: valid1}, true)
t.setConfigMap(&v1.ConfigMap{Data: valid1}, valid1m, true)
t.validate()
By("valid1 -> deleted")
......@@ -114,7 +116,7 @@ func (t *dnsConfigMapTest) run() {
t.validate()
By("deleted -> invalid")
t.setConfigMap(&v1.ConfigMap{Data: invalid}, false)
t.setConfigMap(&v1.ConfigMap{Data: invalid}, nil, false)
t.validate()
}
......@@ -123,11 +125,7 @@ func (t *dnsConfigMapTest) validate() {
}
func (t *dnsConfigMapTest) validateFederation() {
federations := make(map[string]string)
if t.cm != nil {
err := fed.ParseFederationsFlag(t.cm.Data["federations"], federations)
Expect(err).NotTo(HaveOccurred())
}
federations := t.fedMap
if len(federations) == 0 {
By(fmt.Sprintf("Validating federation labels %v do not exist", t.labels))
......@@ -210,9 +208,10 @@ func (t *dnsConfigMapTest) runDig(dnsName string) []string {
}
}
func (t *dnsConfigMapTest) setConfigMap(cm *v1.ConfigMap, isValid bool) {
func (t *dnsConfigMapTest) setConfigMap(cm *v1.ConfigMap, fedMap map[string]string, isValid bool) {
if isValid {
t.cm = cm
t.fedMap = fedMap
}
t.isValid = isValid
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment