From 08928cfed83b70e3eca8c889434e15e628b60ca0 Mon Sep 17 00:00:00 2001 From: Manjunath A Kumatagi Date: Sat, 11 Aug 2018 18:13:48 +0530 Subject: [PATCH] Sync peer-finder code from contrib repo --- test/images/pets/peer-finder/README.md | 13 ++++-- test/images/pets/peer-finder/VERSION | 2 +- test/images/pets/peer-finder/peer-finder.go | 52 +++++++++++++++++++-- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/test/images/pets/peer-finder/README.md b/test/images/pets/peer-finder/README.md index 4c9a2c9c30..5c22e8f5d9 100644 --- a/test/images/pets/peer-finder/README.md +++ b/test/images/pets/peer-finder/README.md @@ -6,13 +6,13 @@ All it does is watch DNS for changes in the set of endpoints that are part of th of the PetSet. It periodically looks up the SRV record of the DNS entry that corresponds to a Kubernetes Service which enumerates the set of peers for this the specified service. -Be sure to use the `publishNotReadyAddresses` field on the governing service +Be sure to use the `service.alpha.kubernetes.io/tolerate-unready-endpoints` on the governing service of the StatefulSet so that all peers are listed in endpoints before any peers are started. There are several ways to bundle it with your main application. 1. In an [init container](http://kubernetes.io/docs/user-guide/pods/init-container/), - to help your pod determine its peers when it it first started (determine the desired set of + to help your pod determine its peers when it first started (determine the desired set of peers from the governing service of the StatefulSet. For this use case, the `--on-start` option can be used, but the `--on-change` option should not be used since the init container will no longer be running after the pod is started. An example of an `--on-start` script would be to @@ -33,7 +33,14 @@ Options 1 and 2 and 4 may be preferable since they do not require changes to the Option 3 is useful is signalling is necessary. The peer-finder tool is intended to help legacy applications run in containers on Kubernetes. -If possible, it may be preferable to modify an applications to poll DNS itself to determine its peer set. +If possible, it may be preferable to modify an application to poll its own DNS to determine its peer set. Not all StatefulSets are able to be scaled. For unscalable StatefulSets, only the on-start message is needed, and so option 1 is a good choice. + +## DNS Considerations +Unless specified by the `-domain` argument, `peer-finder` will determine the FQDN of the pod by examining the +`/etc/resolv.conf` file, looking for a `search` line and looking for the best match. + +If your pod is not using the default `dnsPolicy` value which is `ClusterFirst` as the DNS policy, you may need +to provide the `-domain` argument. In most common configurations, `-domain=cluster.local` will be the correct setting. diff --git a/test/images/pets/peer-finder/VERSION b/test/images/pets/peer-finder/VERSION index 9459d4ba2a..5625e59da8 100644 --- a/test/images/pets/peer-finder/VERSION +++ b/test/images/pets/peer-finder/VERSION @@ -1 +1 @@ -1.1 +1.2 diff --git a/test/images/pets/peer-finder/peer-finder.go b/test/images/pets/peer-finder/peer-finder.go index db71c1e224..6878fad454 100644 --- a/test/images/pets/peer-finder/peer-finder.go +++ b/test/images/pets/peer-finder/peer-finder.go @@ -25,6 +25,7 @@ import ( "net" "os" "os/exec" + "regexp" "sort" "strings" "time" @@ -41,7 +42,7 @@ var ( onStart = flag.String("on-start", "", "Script to run on start, must accept a new line separated list of peers via stdin.") svc = flag.String("service", "", "Governing service responsible for the DNS records of the domain this pod is in.") namespace = flag.String("ns", "", "The namespace this pod is running in. If unspecified, the POD_NAMESPACE env var is used.") - domain = flag.String("domain", "cluster.local", "The Cluster Domain which is used by the Cluster.") + domain = flag.String("domain", "", "The Cluster Domain which is used by the Cluster, if not set tries to determine it from /etc/resolv.conf file.") ) func lookup(svcName string) (sets.String, error) { @@ -99,9 +100,53 @@ func main() { if err != nil { log.Fatalf("Failed to get hostname: %s", err) } + var domainName string - svcLocalSuffix := strings.Join([]string{"svc", *domain}, ".") - myName := strings.Join([]string{hostname, *svc, ns, svcLocalSuffix}, ".") + // If domain is not provided, try to get it from resolv.conf + if *domain == "" { + resolvConfBytes, err := ioutil.ReadFile("/etc/resolv.conf") + resolvConf := string(resolvConfBytes) + if err != nil { + log.Fatal("Unable to read /etc/resolv.conf") + } + + var re *regexp.Regexp + if ns == "" { + // Looking for a domain that looks like with *.svc.** + re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?P[a-zA-Z0-9-]{1,63}.svc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`) + } else { + // Looking for a domain that looks like svc.** + re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?Psvc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`) + } + if err != nil { + log.Fatalf("Failed to create regular expression: %v", err) + } + + groupNames := re.SubexpNames() + result := re.FindStringSubmatch(resolvConf) + for k, v := range result { + if groupNames[k] == "goal" { + if ns == "" { + // Domain is complete if ns is empty + domainName = v + } else { + // Need to convert svc.** into ns.svc.** + domainName = ns + "." + v + } + break + } + } + log.Printf("Determined Domain to be %s", domainName) + + } else { + domainName = strings.Join([]string{ns, "svc", *domain}, ".") + } + + if *svc == "" || domainName == "" || (*onChange == "" && *onStart == "") { + log.Fatalf("Incomplete args, require -on-change and/or -on-start, -service and -ns or an env var for POD_NAMESPACE.") + } + + myName := strings.Join([]string{hostname, *svc, domainName}, ".") script := *onStart if script == "" { script = *onChange @@ -114,6 +159,7 @@ func main() { continue } if newPeers.Equal(peers) || !newPeers.Has(myName) { + log.Printf("Have not found myself in list yet.\nMy Hostname: %s\nHosts in list: %s", myName, strings.Join(newPeers.List(), ", ")) continue } peerList := newPeers.List()