1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
package setup
import (
"errors"
"fmt"
"log"
"strings"
"time"
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/middleware/kubernetes"
"github.com/miekg/coredns/middleware/kubernetes/nametemplate"
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
)
const (
defaultNameTemplate = "{service}.{namespace}.{zone}"
defaultResyncPeriod = 5 * time.Minute
)
// Kubernetes sets up the kubernetes middleware.
func Kubernetes(c *Controller) (middleware.Middleware, error) {
kubernetes, err := kubernetesParse(c)
if err != nil {
return nil, err
}
err = kubernetes.StartKubeCache()
if err != nil {
return nil, err
}
return func(next middleware.Handler) middleware.Handler {
kubernetes.Next = next
return kubernetes
}, nil
}
func kubernetesParse(c *Controller) (kubernetes.Kubernetes, error) {
var err error
template := defaultNameTemplate
k8s := kubernetes.Kubernetes{
ResyncPeriod: defaultResyncPeriod,
}
k8s.NameTemplate = new(nametemplate.NameTemplate)
k8s.NameTemplate.SetTemplate(template)
// TODO: expose resync period in Corefile
for c.Next() {
if c.Val() == "kubernetes" {
zones := c.RemainingArgs()
if len(zones) == 0 {
k8s.Zones = c.ServerBlockHosts
log.Printf("[debug] Zones(from ServerBlockHosts): %v", zones)
} else {
// Normalize requested zones
k8s.Zones = kubernetes.NormalizeZoneList(zones)
}
middleware.Zones(k8s.Zones).FullyQualify()
if k8s.Zones == nil || len(k8s.Zones) < 1 {
err = errors.New("Zone name must be provided for kubernetes middleware.")
log.Printf("[debug] %v\n", err)
return kubernetes.Kubernetes{}, err
}
for c.NextBlock() {
switch c.Val() {
case "template":
args := c.RemainingArgs()
if len(args) != 0 {
template := strings.Join(args, "")
err = k8s.NameTemplate.SetTemplate(template)
if err != nil {
return kubernetes.Kubernetes{}, err
}
} else {
log.Printf("[debug] 'template' keyword provided without any template value.")
return kubernetes.Kubernetes{}, c.ArgErr()
}
case "namespaces":
args := c.RemainingArgs()
if len(args) != 0 {
k8s.Namespaces = append(k8s.Namespaces, args...)
} else {
log.Printf("[debug] 'namespaces' keyword provided without any namespace values.")
return kubernetes.Kubernetes{}, c.ArgErr()
}
case "endpoint":
args := c.RemainingArgs()
if len(args) != 0 {
k8s.APIEndpoint = args[0]
} else {
log.Printf("[debug] 'endpoint' keyword provided without any endpoint url value.")
return kubernetes.Kubernetes{}, c.ArgErr()
}
case "resyncperiod":
args := c.RemainingArgs()
if len(args) != 0 {
k8s.ResyncPeriod, err = time.ParseDuration(args[0])
if err != nil {
err = errors.New(fmt.Sprintf("Unable to parse resync duration value. Value provided was '%v'. Example valid values: '15s', '5m', '1h'. Error was: %v", args[0], err))
log.Printf("[ERROR] %v", err)
return kubernetes.Kubernetes{}, err
}
} else {
log.Printf("[debug] 'resyncperiod' keyword provided without any duration value.")
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
}
}
err = errors.New("Kubernetes setup called without keyword 'kubernetes' in Corefile")
log.Printf("[ERROR] %v\n", err)
return kubernetes.Kubernetes{}, err
}
|