From 662bee21c20b8345fd325d7322150d15ff179526 Mon Sep 17 00:00:00 2001 From: angelnu Date: Sun, 6 Jun 2021 18:12:01 +0000 Subject: [PATCH] Add options --- go.mod | 1 - go.sum | 4 - internal/http/webhook/handler.go | 2 +- internal/mutation/gatewayPodMutator.go | 35 +++++-- internal/mutation/gatewayPodMutator_test.go | 40 +++++++- internal/resolv/resolv.go | 108 ++++++++++++++++++++ 6 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 internal/resolv/resolv.go diff --git a/go.mod b/go.mod index 693725e..f989e3b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/k8s-at-home/gateway-admision-controller go 1.16 require ( - github.com/fiskeben/resolv v0.0.0-20200701110541-c310f0881e4b github.com/oklog/run v1.1.0 github.com/sirupsen/logrus v1.8.1 github.com/slok/kubewebhook/v2 v2.1.0 diff --git a/go.sum b/go.sum index b95e563..a2f1933 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,6 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fiskeben/resolv v0.0.0-20200701110541-c310f0881e4b h1:F0oOgXwG5M9trhoBAzI/p/WdyznxKYjKdUOnbthHAKs= -github.com/fiskeben/resolv v0.0.0-20200701110541-c310f0881e4b/go.mod h1:mfzp4KVyI1aKyqzrA3txM3p0I/h0dXHIpC9y8207odc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= @@ -123,8 +121,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.6 h1:UHSEyLZUwX9Qoi99vVwvewiMC8mM2bf7XEM2nqvzEn8= -github.com/go-test/deep v1.0.6/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/internal/http/webhook/handler.go b/internal/http/webhook/handler.go index 48469a0..5e92ef3 100644 --- a/internal/http/webhook/handler.go +++ b/internal/http/webhook/handler.go @@ -34,7 +34,7 @@ func (h handler) gatewayPodMutator() (http.Handler, error) { logger := kubewebhookLogger{Logger: h.logger.WithKV(log.KV{"lib": "kubewebhook", "webhook": "gatewayPodMutator"})} // Create our mutator - gwPodMutator, err := gatewayPodMutator.NewGatewayPodMutator(h.cmdConfig) + gwPodMutator, err := gatewayPodMutator.NewGatewayPodMutator(h.cmdConfig, logger) if err != nil { return nil, fmt.Errorf("error creating webhook mutator: %w", err) } diff --git a/internal/mutation/gatewayPodMutator.go b/internal/mutation/gatewayPodMutator.go index b3c3f31..6c01abc 100644 --- a/internal/mutation/gatewayPodMutator.go +++ b/internal/mutation/gatewayPodMutator.go @@ -9,11 +9,12 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/fiskeben/resolv" + "github.com/k8s-at-home/gateway-admision-controller/internal/resolv" kwhmodel "github.com/slok/kubewebhook/v2/pkg/model" kwhmutating "github.com/slok/kubewebhook/v2/pkg/webhook/mutating" "github.com/k8s-at-home/gateway-admision-controller/internal/config" + "github.com/k8s-at-home/gateway-admision-controller/internal/log" ) const ( @@ -31,7 +32,9 @@ type GatewayPodMutator interface { } // NewLabelMarker returns a new marker that will mark with labels. -func NewGatewayPodMutator(cmdConfig config.CmdConfig) (GatewayPodMutator, error) { +func NewGatewayPodMutator(cmdConfig config.CmdConfig, logger log.Logger) (GatewayPodMutator, error) { + + logger.Infof("Command config is %#v", cmdConfig) if cmdConfig.Gateway != "" { //Check we got a valid Gateway @@ -53,14 +56,24 @@ func NewGatewayPodMutator(cmdConfig config.CmdConfig) (GatewayPodMutator, error) if error != nil { return nil, error } + logger.Infof("Current DNS config is %#v", DNS_config) + + podDNSConfigOptions := make([]corev1.PodDNSConfigOption, 0) + for i := range DNS_config.Options { + podDNSConfigOptions = append(podDNSConfigOptions, corev1.PodDNSConfigOption{ + Name: DNS_config.Options[i].Name, + Value: DNS_config.Options[i].Value, + }) + } return gatewayPodMutatorCfg{ cmdConfig: cmdConfig, staticDNS: corev1.PodDNSConfig{ Nameservers: DNS_config.Nameservers, Searches: DNS_config.Search, - //Options: DNS_config.Options, #Libray does not support it + Options: podDNSConfigOptions, }, + logger: logger, }, nil } @@ -77,6 +90,7 @@ func (cfg gatewayPodMutatorCfg) getDNSIP() (string, error) { type gatewayPodMutatorCfg struct { cmdConfig config.CmdConfig staticDNS corev1.PodDNSConfig + logger log.Logger } func (cfg gatewayPodMutatorCfg) GatewayPodMutator(_ context.Context, _ *kwhmodel.AdmissionReview, obj metav1.Object) (*kwhmutating.MutatorResult, error) { @@ -128,13 +142,13 @@ func (cfg gatewayPodMutatorCfg) GatewayPodMutator(_ context.Context, _ *kwhmodel copied := cfg.staticDNS.DeepCopy() //fix the first search to match the pod namespace - firstSearch := copied.Searches[0] - if strings.Contains(firstSearch, ".svc.") { - firstSearchParts := strings.Split(firstSearch, ".") - firstSearchParts[0] = pod.Namespace - firstSearch = strings.Join(firstSearchParts, ".") + for i := range copied.Searches { + searchParts := strings.Split(copied.Searches[i], ".") + if len(searchParts) > 2 && searchParts[1] == "svc" { + searchParts[0] = pod.Namespace + copied.Searches[i] = strings.Join(searchParts, ".") + } } - copied.Searches[0] = firstSearch pod.Spec.DNSConfig.Searches = copied.Searches pod.Spec.DNSConfig.Options = copied.Options @@ -305,6 +319,9 @@ func (cfg gatewayPodMutatorCfg) GatewayPodMutator(_ context.Context, _ *kwhmodel } } + cfg.logger.Infof("Mutated pod %s", pod.Name) + cfg.logger.Debugf("%s", pod.String()) + return &kwhmutating.MutatorResult{ MutatedObject: pod, }, nil diff --git a/internal/mutation/gatewayPodMutator_test.go b/internal/mutation/gatewayPodMutator_test.go index e01770b..d1d1dd8 100644 --- a/internal/mutation/gatewayPodMutator_test.go +++ b/internal/mutation/gatewayPodMutator_test.go @@ -6,14 +6,16 @@ import ( "strings" "testing" - "github.com/fiskeben/resolv" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/k8s-at-home/gateway-admision-controller/internal/config" + "github.com/k8s-at-home/gateway-admision-controller/internal/log" mutator "github.com/k8s-at-home/gateway-admision-controller/internal/mutation" + "github.com/k8s-at-home/gateway-admision-controller/internal/resolv" ) const ( @@ -31,6 +33,7 @@ const ( testSidecarCmd = "sidecarCmd" testSidecarMountPoint = "/mnt" testConfigmapName = "settings" + testNamespace = "myNameSpace" ) func getExpectedPodSpec_gateway(gateway string, DNS string, initImage string, sidecarImage string) corev1.PodSpec { @@ -44,6 +47,15 @@ func getExpectedPodSpec_gateway(gateway string, DNS string, initImage string, si k8s_DNS_config, _ := resolv.Config() k8s_DNS_ips := strings.Join(k8s_DNS_config.Nameservers, " ") + //fix the first search to match the pod namespace + for i := range k8s_DNS_config.Search { + searchParts := strings.Split(k8s_DNS_config.Search[i], ".") + if len(searchParts) > 2 && searchParts[1] == "svc" { + searchParts[0] = testNamespace + k8s_DNS_config.Search[i] = strings.Join(searchParts, ".") + } + } + var initContainers []corev1.Container if initImage != "" { initContainers = append(initContainers, corev1.Container{ @@ -143,6 +155,15 @@ func getExpectedPodSpec_gateway(gateway string, DNS string, initImage string, si if testDNSPolicy == "None" { // Copy my own webhook settings spec.DNSConfig.Searches = k8s_DNS_config.Search + + podDNSConfigOptions := make([]corev1.PodDNSConfigOption, 0) + for i := range k8s_DNS_config.Options { + podDNSConfigOptions = append(podDNSConfigOptions, corev1.PodDNSConfigOption{ + Name: k8s_DNS_config.Options[i].Name, + Value: k8s_DNS_config.Options[i].Value, + }) + } + spec.DNSConfig.Options = podDNSConfigOptions } } @@ -195,7 +216,6 @@ func TestGatewayPodMutator(t *testing.T) { obj metav1.Object expObj metav1.Object }{ - "Empty - NOP": { cmdConfig: config.CmdConfig{ SetGatewayDefault: true, @@ -401,7 +421,7 @@ func TestGatewayPodMutator(t *testing.T) { Spec: getExpectedPodSpec_DNSPolicy(testDNSPolicy), }, }, - "DNSPolicy, Gateway IP, init image ": { + "DNSPolicy, Gateway IP, init image": { cmdConfig: config.CmdConfig{ SetGatewayDefault: true, Gateway: testGatewayIP, @@ -413,19 +433,29 @@ func TestGatewayPodMutator(t *testing.T) { ConfigmapName: testConfigmapName, DNSPolicy: testDNSPolicy, }, - obj: &corev1.Pod{}, + obj: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + }, + }, expObj: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + }, Spec: getExpectedPodSpec_gateway_DNSPolicy(testGatewayIP, testDNSIP, testInitImage, "", testDNSPolicy), }, }, } + logrusLog := logrus.New() + logrusLogEntry := logrus.NewEntry(logrusLog).WithField("app", "gatewayPodMutator Test") + for name, test := range tests { t.Run(name, func(t *testing.T) { assert := assert.New(t) require := require.New(t) - m, err := mutator.NewGatewayPodMutator(test.cmdConfig) + m, err := mutator.NewGatewayPodMutator(test.cmdConfig, log.NewLogrus(logrusLogEntry).WithKV(log.KV{"test": name})) require.NoError(err) _, err = m.GatewayPodMutator(context.TODO(), nil, test.obj) diff --git a/internal/resolv/resolv.go b/internal/resolv/resolv.go new file mode 100644 index 0000000..594d99e --- /dev/null +++ b/internal/resolv/resolv.go @@ -0,0 +1,108 @@ +package resolv + +import ( + "bufio" + "io" + "os" + "strings" +) + +// Resolver contains the data from resolv.conf +type Resolver struct { + Domains []string + Nameservers []string + Search []string + Sortlist []string + Options []ResolverOption +} + +type ResolverOption struct { + Name string + Value *string +} + +// Config reads /etc/resolv.conf and returns it as a Resolver +func Config() (Resolver, error) { + f, err := os.Open("/etc/resolv.conf") + if err != nil { + return Resolver{}, err + } + defer f.Close() + return parse(f) +} + +func parse(f io.Reader) (Resolver, error) { + domains := make([]string, 0) + nameservers := make([]string, 0) + search := make([]string, 0) + options := make([]ResolverOption, 0) + sortlist := make([]string, 0) + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "#") { + continue + } + + parts := strings.Split(line, " ") + if len(parts) < 2 { + continue + } + + kind := parts[0] + rest := parts[1:] + + switch kind { + case "domain": + for _, d := range rest { + d := strings.TrimSpace(d) + if d != "" { + domains = append(domains, d) + } + } + case "nameserver": + n := strings.Join(rest, "") + n = strings.TrimSpace(n) + nameservers = append(nameservers, n) + case "search": + for _, s := range rest { + s := strings.TrimSpace(s) + if s != "" { + search = append(search, s) + } + } + case "options": + for _, s := range rest { + s := strings.TrimSpace(s) + s_parts := strings.SplitN(line, ":", 2) + + option := ResolverOption{ + Name: s_parts[0], + } + if len(s_parts) == 2 { + option.Value = &s_parts[1] + } + + if s != "" { + options = append(options, option) + } + } + case "sortlist": + for _, s := range rest { + s := strings.TrimSpace(s) + if s != "" { + sortlist = append(sortlist, s) + } + } + } + } + + return Resolver{ + Domains: domains, + Nameservers: nameservers, + Search: search, + Options: options, + Sortlist: sortlist, + }, nil +}