summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-01-29 14:15:21 -0500
committerGitHub <noreply@github.com>2021-01-29 14:15:21 -0500
commitf3a7bc1a7b80cbf556f04f8ad839b86ba7acb9e2 (patch)
tree764cf3ef227786201c836b7b0dd35726a7f32944
parent8f3bcf62474bbfba26982bae88febecd4fa630c2 (diff)
parentca0dd76bf3b98d1ebe25813a8b15361d58dc75ed (diff)
downloadpodman-f3a7bc1a7b80cbf556f04f8ad839b86ba7acb9e2.tar.gz
podman-f3a7bc1a7b80cbf556f04f8ad839b86ba7acb9e2.tar.bz2
podman-f3a7bc1a7b80cbf556f04f8ad839b86ba7acb9e2.zip
Merge pull request #9150 from baude/playkubedns
Honor custom DNS in play|generate kube
-rw-r--r--libpod/kube.go112
-rw-r--r--pkg/specgen/generate/kube/kube.go26
-rw-r--r--test/e2e/generate_kube_test.go63
3 files changed, 187 insertions, 14 deletions
diff --git a/libpod/kube.go b/libpod/kube.go
index 753c58099..b5197293e 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -171,9 +171,10 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
deDupPodVolumes := make(map[string]*v1.Volume)
first := true
podContainers := make([]v1.Container, 0, len(containers))
+ dnsInfo := v1.PodDNSConfig{}
for _, ctr := range containers {
if !ctr.IsInfra() {
- ctr, volumes, err := containerToV1Container(ctr)
+ ctr, volumes, _, err := containerToV1Container(ctr)
if err != nil {
return nil, err
}
@@ -196,6 +197,22 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
vol := vol
deDupPodVolumes[vol.Name] = &vol
}
+ } else {
+ _, _, infraDNS, err := containerToV1Container(ctr)
+ if err != nil {
+ return nil, err
+ }
+ if infraDNS != nil {
+ if servers := infraDNS.Nameservers; len(servers) > 0 {
+ dnsInfo.Nameservers = servers
+ }
+ if searches := infraDNS.Searches; len(searches) > 0 {
+ dnsInfo.Searches = searches
+ }
+ if options := infraDNS.Options; len(options) > 0 {
+ dnsInfo.Options = options
+ }
+ }
}
}
podVolumes := make([]v1.Volume, 0, len(deDupPodVolumes))
@@ -203,10 +220,10 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
podVolumes = append(podVolumes, *vol)
}
- return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name()), nil
+ return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name(), &dnsInfo), nil
}
-func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string) *v1.Pod {
+func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string, dnsOptions *v1.PodDNSConfig) *v1.Pod {
tm := v12.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
@@ -228,6 +245,9 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
Containers: containers,
Volumes: volumes,
}
+ if dnsOptions != nil {
+ ps.DNSConfig = dnsOptions
+ }
p := v1.Pod{
TypeMeta: tm,
ObjectMeta: om,
@@ -241,32 +261,65 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
kubeCtrs := make([]v1.Container, 0, len(ctrs))
kubeVolumes := make([]v1.Volume, 0)
+ podDNS := v1.PodDNSConfig{}
for _, ctr := range ctrs {
- kubeCtr, kubeVols, err := containerToV1Container(ctr)
+ kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctr)
if err != nil {
return nil, err
}
kubeCtrs = append(kubeCtrs, kubeCtr)
kubeVolumes = append(kubeVolumes, kubeVols...)
- }
- return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", "")), nil
+ // Combine DNS information in sum'd structure
+ if ctrDNS != nil {
+ // nameservers
+ if servers := ctrDNS.Nameservers; servers != nil {
+ if podDNS.Nameservers == nil {
+ podDNS.Nameservers = make([]string, 0)
+ }
+ for _, s := range servers {
+ if !util.StringInSlice(s, podDNS.Nameservers) { // only append if it does not exist
+ podDNS.Nameservers = append(podDNS.Nameservers, s)
+ }
+ }
+ }
+ // search domains
+ if domains := ctrDNS.Searches; domains != nil {
+ if podDNS.Searches == nil {
+ podDNS.Searches = make([]string, 0)
+ }
+ for _, d := range domains {
+ if !util.StringInSlice(d, podDNS.Searches) { // only append if it does not exist
+ podDNS.Searches = append(podDNS.Searches, d)
+ }
+ }
+ }
+ // dns options
+ if options := ctrDNS.Options; options != nil {
+ if podDNS.Options == nil {
+ podDNS.Options = make([]v1.PodDNSConfigOption, 0)
+ }
+ podDNS.Options = append(podDNS.Options, options...)
+ }
+ } // end if ctrDNS
+ }
+ return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", ""), &podDNS), nil
}
// containerToV1Container converts information we know about a libpod container
// to a V1.Container specification.
-func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
+func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
kubeContainer := v1.Container{}
kubeVolumes := []v1.Volume{}
kubeSec, err := generateKubeSecurityContext(c)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
if len(c.config.Spec.Linux.Devices) > 0 {
// TODO Enable when we can support devices and their names
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices)
- return kubeContainer, kubeVolumes, errors.Wrapf(define.ErrNotImplemented, "linux devices")
+ return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices")
}
if len(c.config.UserVolumes) > 0 {
@@ -274,7 +327,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
// Volume names need to be coordinated "globally" in the kube files.
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
kubeContainer.VolumeMounts = volumeMounts
kubeVolumes = append(kubeVolumes, volumes...)
@@ -282,16 +335,16 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
portmappings, err := c.PortMappings()
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
ports, err := ocicniPortMappingToContainerPort(portmappings)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
containerCommands := c.Command()
@@ -355,7 +408,38 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
}
}
- return kubeContainer, kubeVolumes, nil
+ // Obtain the DNS entries from the container
+ dns := v1.PodDNSConfig{}
+
+ // DNS servers
+ if servers := c.config.DNSServer; len(servers) > 0 {
+ dnsServers := make([]string, 0)
+ for _, server := range servers {
+ dnsServers = append(dnsServers, server.String())
+ }
+ dns.Nameservers = dnsServers
+ }
+
+ // DNS search domains
+ if searches := c.config.DNSSearch; len(searches) > 0 {
+ dns.Searches = searches
+ }
+
+ // DNS options
+ if options := c.config.DNSOption; len(options) > 0 {
+ dnsOptions := make([]v1.PodDNSConfigOption, 0)
+ for _, option := range options {
+ // the option can be "k:v" or just "k", no delimiter is required
+ opts := strings.SplitN(option, ":", 2)
+ dnsOpt := v1.PodDNSConfigOption{
+ Name: opts[0],
+ Value: &opts[1],
+ }
+ dnsOptions = append(dnsOptions, dnsOpt)
+ }
+ dns.Options = dnsOptions
+ }
+ return kubeContainer, kubeVolumes, &dns, nil
}
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index e39a700eb..0d7ee3ad2 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -3,6 +3,7 @@ package kube
import (
"context"
"fmt"
+ "net"
"strings"
"github.com/containers/common/pkg/parse"
@@ -44,6 +45,31 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
podPorts := getPodPorts(podYAML.Spec.Containers)
p.PortMappings = podPorts
+ if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil {
+ // name servers
+ if dnsServers := dnsConfig.Nameservers; len(dnsServers) > 0 {
+ servers := make([]net.IP, 0)
+ for _, server := range dnsServers {
+ servers = append(servers, net.ParseIP(server))
+ }
+ p.DNSServer = servers
+ }
+ // search domans
+ if domains := dnsConfig.Searches; len(domains) > 0 {
+ p.DNSSearch = domains
+ }
+ // dns options
+ if options := dnsConfig.Options; len(options) > 0 {
+ dnsOptions := make([]string, 0)
+ for _, opts := range options {
+ d := opts.Name
+ if opts.Value != nil {
+ d += ":" + *opts.Value
+ }
+ dnsOptions = append(dnsOptions, d)
+ }
+ }
+ }
return p, nil
}
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 239817e6c..8800f9057 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -540,4 +540,67 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout()
Expect(kube.ExitCode()).ToNot(Equal(0))
})
+
+ It("podman generate kube on a container with dns options", func() {
+ top := podmanTest.Podman([]string{"run", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
+ top.WaitWithDefaultTimeout()
+ Expect(top.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "top"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
+ Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
+ Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
+ })
+
+ It("podman generate kube multiple contianer dns servers and options are cumulative", func() {
+ top1 := podmanTest.Podman([]string{"run", "-dt", "--name", "top1", "--dns", "8.8.8.8", "--dns-search", "foobar.com", ALPINE, "top"})
+ top1.WaitWithDefaultTimeout()
+ Expect(top1.ExitCode()).To(BeZero())
+
+ top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--dns", "8.7.7.7", "--dns-search", "homer.com", ALPINE, "top"})
+ top2.WaitWithDefaultTimeout()
+ Expect(top2.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "top1", "top2"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("8.7.7.7", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(StringInSlice("homer.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ })
+
+ It("podman generate kube on a pod with dns options", func() {
+ top := podmanTest.Podman([]string{"run", "--pod", "new:pod1", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
+ top.WaitWithDefaultTimeout()
+ Expect(top.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "pod1"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
+ Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
+ Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
+ })
})