From 731ccdea35fc5ca2b5c994de30ac8cac1a2890a8 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Wed, 13 Sep 2017 10:28:41 +0200 Subject: [PATCH 1/5] server: correctly set hostname Signed-off-by: Antonio Murdaca --- libkpod/container_server.go | 1 + libkpod/sandbox/sandbox.go | 11 ++++++ pkg/annotations/annotations.go | 3 ++ server/container_create.go | 13 +++++-- server/sandbox_run.go | 46 +++++++++++++++++++----- test/network.bats | 66 ++++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 11 deletions(-) diff --git a/libkpod/container_server.go b/libkpod/container_server.go index 20680ffc..f20705df 100644 --- a/libkpod/container_server.go +++ b/libkpod/container_server.go @@ -335,6 +335,7 @@ func (c *ContainerServer) LoadSandbox(id string) error { if err != nil { return err } + sb.AddHostnamePath(m.Annotations[annotations.HostnamePath]) sb.AddIP(ip) // We add a netNS only if we can load a permanent one. diff --git a/libkpod/sandbox/sandbox.go b/libkpod/sandbox/sandbox.go index 8e84dfb2..d7d6569d 100644 --- a/libkpod/sandbox/sandbox.go +++ b/libkpod/sandbox/sandbox.go @@ -151,6 +151,7 @@ type Sandbox struct { privileged bool trusted bool resolvPath string + hostnamePath string hostname string portMappings []*hostport.PortMapping stopped bool @@ -301,6 +302,16 @@ func (s *Sandbox) ResolvPath() string { return s.resolvPath } +// AddHostnamePath adds the hostname path to the sandbox +func (s *Sandbox) AddHostnamePath(hostname string) { + s.hostnamePath = hostname +} + +// HostnamePath retrieves the hostname path from a sandbox +func (s *Sandbox) HostnamePath() string { + return s.hostnamePath +} + // Hostname returns the hsotname of the sandbox func (s *Sandbox) Hostname() string { return s.hostname diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go index 80f943c2..151d9390 100644 --- a/pkg/annotations/annotations.go +++ b/pkg/annotations/annotations.go @@ -52,6 +52,9 @@ const ( // ResolvPath is the resolver configuration path annotation ResolvPath = "io.kubernetes.cri-o.ResolvPath" + // HostnamePath is the path to /etc/hostname to bind mount annotation + HostnamePath = "io.kubernetes.cri-o.HostnamePath" + // SandboxID is the sandbox ID annotation SandboxID = "io.kubernetes.cri-o.SandboxID" diff --git a/server/container_create.go b/server/container_create.go index c90f2baa..126303f8 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -818,18 +818,25 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, options = []string{"ro"} } if sb.ResolvPath() != "" { + // TODO: selinux + // label.Relabel(sb.ResolvPath(), container.MountLabel, shared) + // bind mount the pod resolver file specgen.AddBindMount(sb.ResolvPath(), "/etc/resolv.conf", options) } + if sb.HostnamePath() != "" { + // TODO: selinux + + specgen.AddBindMount(sb.HostnamePath(), "/etc/hostname", options) + } + // Bind mount /etc/hosts for host networking containers if hostNetwork(containerConfig) { specgen.AddBindMount("/etc/hosts", "/etc/hosts", options) } - if sb.Hostname() != "" { - specgen.SetHostname(sb.Hostname()) - } + specgen.SetHostname(sb.Hostname()) specgen.AddAnnotation(annotations.Name, containerName) specgen.AddAnnotation(annotations.ContainerID, containerID) diff --git a/server/sandbox_run.go b/server/sandbox_run.go index 0cd2d644..d5e6ecc4 100644 --- a/server/sandbox_run.go +++ b/server/sandbox_run.go @@ -3,6 +3,7 @@ package server import ( "encoding/json" "fmt" + "io/ioutil" "os" "path" "path/filepath" @@ -187,12 +188,6 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest g.SetProcessArgs([]string{s.config.PauseCommand}) } - // set hostname - hostname := req.GetConfig().Hostname - if hostname != "" { - g.SetHostname(hostname) - } - // set DNS options if req.GetConfig().GetDnsConfig() != nil { dnsServers := req.GetConfig().GetDnsConfig().Servers @@ -208,6 +203,9 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest } return nil, err } + // TODO: selinux + // label.Relabel(sb.ResolvPath(), container.MountLabel, shared) + g.AddBindMount(resolvPath, "/etc/resolv.conf", []string{"ro"}) } @@ -301,6 +299,14 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest return nil, err } + hostNetwork := req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostNetwork + + hostname, err := getHostname(id, req.GetConfig().Hostname, hostNetwork) + if err != nil { + return nil, err + } + g.SetHostname(hostname) + privileged := s.privilegedSandbox(req) trusted := s.trustedSandbox(req) g.AddAnnotation(annotations.Metadata, string(metadataJSON)) @@ -399,8 +405,6 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest g.SetLinuxResourcesCPUShares(PodInfraCPUshares) - hostNetwork := req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostNetwork - // set up namespaces if hostNetwork { err = g.RemoveLinuxNamespace("network") @@ -456,6 +460,15 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest g.AddAnnotation(annotations.MountPoint, mountPoint) g.SetRootPath(mountPoint) + hostnamePath := fmt.Sprintf("%s/hostname", podContainer.RunDir) + if err := ioutil.WriteFile(hostnamePath, []byte(hostname+"\n"), 0644); err != nil { + return nil, err + } + // TODO: selinux relabel + g.AddBindMount(hostnamePath, "/etc/hostname", []string{"ro"}) + g.AddAnnotation(annotations.HostnamePath, hostnamePath) + sb.AddHostnamePath(hostnamePath) + container, err := oci.NewContainer(id, containerName, podContainer.RunDir, logPath, sb.NetNs(), labels, kubeAnnotations, "", "", "", nil, id, false, false, false, sb.Privileged(), sb.Trusted(), podContainer.Dir, created, podContainer.Config.Config.StopSignal) if err != nil { return nil, err @@ -515,6 +528,23 @@ func convertPortMappings(in []*pb.PortMapping) []*hostport.PortMapping { return out } +func getHostname(id, hostname string, hostNetwork bool) (string, error) { + if hostNetwork { + if hostname == "" { + h, err := os.Hostname() + if err != nil { + return "", err + } + hostname = h + } + } else { + if hostname == "" { + hostname = id[:12] + } + } + return hostname, nil +} + func (s *Server) setPodSandboxMountLabel(id, mountLabel string) error { storageMetadata, err := s.StorageRuntimeServer().GetContainerMetadata(id) if err != nil { diff --git a/test/network.bats b/test/network.bats index 8121ca48..67fbdfc8 100644 --- a/test/network.bats +++ b/test/network.bats @@ -2,6 +2,72 @@ load helpers +@test "ensure correct hostname" { + start_crio + run crioctl pod run --config "$TESTDATA"/sandbox_config.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run crioctl ctr create --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run crioctl ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + + run crioctl ctr execsync --id "$ctr_id" sh -c "hostname" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "crioctl_host" ]] + run crioctl ctr execsync --id "$ctr_id" sh -c "echo \$HOSTNAME" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "crioctl_host" ]] + run crioctl ctr execsync --id "$ctr_id" sh -c "cat /etc/hostname" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "crioctl_host" ]] + + cleanup_ctrs + cleanup_pods + stop_crio +} + +@test "ensure correct hostname for hostnetwork:true" { + start_crio + hostnetworkconfig=$(cat "$TESTDATA"/sandbox_config.json | python -c 'import json,sys;obj=json.load(sys.stdin);obj["linux"]["security_context"]["namespace_options"]["host_network"] = True; obj["annotations"] = {}; obj["hostname"] = ""; json.dump(obj, sys.stdout)') + echo "$hostnetworkconfig" > "$TESTDIR"/sandbox_hostnetwork_config.json + run crioctl pod run --config "$TESTDIR"/sandbox_hostnetwork_config.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run crioctl ctr create --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run crioctl ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + + run crioctl ctr execsync --id "$ctr_id" sh -c "hostname" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "$HOSTNAME" ]] + run crioctl ctr execsync --id "$ctr_id" sh -c "echo \$HOSTNAME" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "$HOSTNAME" ]] + run crioctl ctr execsync --id "$ctr_id" sh -c "cat /etc/hostname" + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "$HOSTNAME" ]] + + cleanup_ctrs + cleanup_pods + stop_crio +} + @test "Check for valid pod netns CIDR" { start_crio run crioctl pod run --config "$TESTDATA"/sandbox_config.json From 2cac86f804e41ab7d7c22e5bbf112674e28105db Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Wed, 13 Sep 2017 13:04:51 +0200 Subject: [PATCH 2/5] Dockerfile: remove not needed image copy Signed-off-by: Antonio Murdaca --- Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 31b353c2..6cbd4584 100644 --- a/Dockerfile +++ b/Dockerfile @@ -112,7 +112,3 @@ COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redh WORKDIR /go/src/github.com/kubernetes-incubator/cri-o ADD . /go/src/github.com/kubernetes-incubator/cri-o - -RUN make test/copyimg/copyimg \ - && mkdir -p .artifacts/redis-image \ - && ./test/copyimg/copyimg --import-from=docker://redis --export-to=dir:.artifacts/redis-image --signature-policy ./test/policy.json From 590027edcd5b358ee70f29743f5ffcef07d3617c Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Wed, 13 Sep 2017 13:05:30 +0200 Subject: [PATCH 3/5] Makefile: always use vfs to test in container Signed-off-by: Antonio Murdaca --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b6d926ab..34f172ed 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,7 @@ dbuild: crioimage docker run --name=${CRIO_INSTANCE} --privileged ${CRIO_IMAGE} -v ${PWD}:/go/src/${PROJECT} --rm make binaries integration: crioimage - docker run -e TESTFLAGS -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${CRIO_IMAGE} make localintegration + docker run -e STORAGE_OPTS="--storage-driver=vfs" -e TESTFLAGS -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${CRIO_IMAGE} make localintegration localintegration: clean binaries ./test/test_runner.sh ${TESTFLAGS} From daf34b9a31f73ca0ee4d328105d7625f86c8381b Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Wed, 13 Sep 2017 13:06:05 +0200 Subject: [PATCH 4/5] server: use grpc getters Signed-off-by: Antonio Murdaca --- server/container_create.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/container_create.go b/server/container_create.go index 126303f8..9e3f5670 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -304,11 +304,11 @@ func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.Linux if sc != nil { containerUser := "" // Case 1: run as user is set by kubelet - if sc.RunAsUser != nil { + if sc.GetRunAsUser() != nil { containerUser = strconv.FormatInt(sc.GetRunAsUser().Value, 10) } else { // Case 2: run as username is set by kubelet - userName := sc.RunAsUsername + userName := sc.GetRunAsUsername() if userName != "" { containerUser = userName } else { @@ -338,7 +338,7 @@ func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.Linux } // Add groups from CRI - groups := sc.SupplementalGroups + groups := sc.GetSupplementalGroups() for _, group := range groups { specgen.AddProcessAdditionalGid(uint32(group)) } From e3682373d06b8c68c083d91ee06c7c1f3b485245 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Wed, 13 Sep 2017 21:06:54 +0200 Subject: [PATCH 5/5] server: fix selinux labels for pod and containers Signed-off-by: Antonio Murdaca --- server/container_create.go | 26 +++++++++++++++++--------- server/sandbox_run.go | 9 ++++++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/server/container_create.go b/server/container_create.go index 9e3f5670..042581f3 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -45,7 +45,7 @@ const ( defaultSystemdParent = "system.slice" ) -func addOCIBindMounts(sb *sandbox.Sandbox, containerConfig *pb.ContainerConfig, specgen *generate.Generator) ([]oci.ContainerVolume, error) { +func addOCIBindMounts(mountLabel string, containerConfig *pb.ContainerConfig, specgen *generate.Generator) ([]oci.ContainerVolume, error) { volumes := []oci.ContainerVolume{} mounts := containerConfig.GetMounts() for _, mount := range mounts { @@ -73,7 +73,7 @@ func addOCIBindMounts(sb *sandbox.Sandbox, containerConfig *pb.ContainerConfig, if mount.SelinuxRelabel { // Need a way in kubernetes to determine if the volume is shared or private - if err := label.Relabel(src, sb.MountLabel(), true); err != nil && err != unix.ENOTSUP { + if err := label.Relabel(src, mountLabel, true); err != nil && err != unix.ENOTSUP { return nil, fmt.Errorf("relabel failed %s: %v", src, err) } } @@ -519,7 +519,12 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, specgen.HostSpecific = true specgen.ClearProcessRlimits() - containerVolumes, err := addOCIBindMounts(sb, containerConfig, &specgen) + processLabel, mountLabel, err := getSELinuxLabels(containerConfig.GetLinux().GetSecurityContext().GetSelinuxOptions()) + if err != nil { + return nil, err + } + + containerVolumes, err := addOCIBindMounts(mountLabel, containerConfig, &specgen) if err != nil { return nil, err } @@ -703,7 +708,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, } } } - specgen.SetProcessSelinuxLabel(sb.ProcessLabel()) + specgen.SetProcessSelinuxLabel(processLabel) } specgen.SetLinuxMountLabel(sb.MountLabel()) @@ -818,15 +823,18 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, options = []string{"ro"} } if sb.ResolvPath() != "" { - // TODO: selinux - // label.Relabel(sb.ResolvPath(), container.MountLabel, shared) + if err := label.Relabel(sb.ResolvPath(), mountLabel, true); err != nil && err != unix.ENOTSUP { + return nil, err + } // bind mount the pod resolver file specgen.AddBindMount(sb.ResolvPath(), "/etc/resolv.conf", options) } if sb.HostnamePath() != "" { - // TODO: selinux + if err := label.Relabel(sb.HostnamePath(), mountLabel, true); err != nil && err != unix.ENOTSUP { + return nil, err + } specgen.AddBindMount(sb.HostnamePath(), "/etc/hostname", options) } @@ -884,7 +892,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, containerName, containerID, metaname, attempt, - sb.MountLabel(), + mountLabel, nil) if err != nil { return nil, err @@ -907,7 +915,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, } // Add image volumes - if err := addImageVolumes(mountPoint, s, &containerInfo, &specgen, sb.MountLabel()); err != nil { + if err := addImageVolumes(mountPoint, s, &containerInfo, &specgen, mountLabel); err != nil { return nil, err } diff --git a/server/sandbox_run.go b/server/sandbox_run.go index d5e6ecc4..887a846e 100644 --- a/server/sandbox_run.go +++ b/server/sandbox_run.go @@ -203,8 +203,9 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest } return nil, err } - // TODO: selinux - // label.Relabel(sb.ResolvPath(), container.MountLabel, shared) + if err := label.Relabel(resolvPath, mountLabel, true); err != nil && err != unix.ENOTSUP { + return nil, err + } g.AddBindMount(resolvPath, "/etc/resolv.conf", []string{"ro"}) } @@ -464,7 +465,9 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest if err := ioutil.WriteFile(hostnamePath, []byte(hostname+"\n"), 0644); err != nil { return nil, err } - // TODO: selinux relabel + if err := label.Relabel(hostnamePath, mountLabel, true); err != nil && err != unix.ENOTSUP { + return nil, err + } g.AddBindMount(hostnamePath, "/etc/hostname", []string{"ro"}) g.AddAnnotation(annotations.HostnamePath, hostnamePath) sb.AddHostnamePath(hostnamePath)