summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2021-01-28 15:20:15 -0600
committerbaude <bbaude@redhat.com>2021-01-29 08:49:45 -0600
commitca0dd76bf3b98d1ebe25813a8b15361d58dc75ed (patch)
treee399fc29cf31d599f3af48e59875319424aa48fd
parent2ee034c1e6ddd9918b97ddea2fd3e6388ec8f60b (diff)
downloadpodman-ca0dd76bf3b98d1ebe25813a8b15361d58dc75ed.tar.gz
podman-ca0dd76bf3b98d1ebe25813a8b15361d58dc75ed.tar.bz2
podman-ca0dd76bf3b98d1ebe25813a8b15361d58dc75ed.zip
Honor custom DNS in play|generate kube
when creating kubernetes yaml from containers and pods, we should honor any custom dns settings the user provided. in the case of generate kube, these would be provided by --dns, --dns-search, and --dns-opt. if multiple containers are involved in the generate, the options will be cumulative and unique with the exception of dns-opt. when replaying a kube file that has kubernetes dns information, we now also add that information to the pod creation. the options for dnspolicy is not enabled as there seemed to be no direct correlation between kubernetes and podman. Fixes: #9132 Signed-off-by: baude <bbaude@redhat.com>
-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"))
+ })
})