Merge pull request #913 from runcom/v1.0.0-rc2-patches

V1.0.0 rc2 patches
This commit is contained in:
Mrunal Patel 2017-09-17 21:03:54 -07:00 committed by GitHub
commit 7e7a097395
26 changed files with 661 additions and 116 deletions

View file

@ -32,13 +32,24 @@ jobs:
- make .gitvalidation - make .gitvalidation
- make gofmt - make gofmt
- make lint - make lint
- make testunit
- make docs - make docs
- make - make
go: 1.8.x go: 1.8.x
- stage: Build and Verify
script:
- make .gitvalidation
- make gofmt
- make lint
- make testunit
- make docs
- make
go: 1.9.x
- script: - script:
- make .gitvalidation - make .gitvalidation
- make gofmt - make gofmt
- make lint - make lint
- make testunit
- make docs - make docs
- make - make
go: tip go: tip

View file

@ -35,6 +35,7 @@ RUN apt-get update && apt-get install -y \
libgpgme11-dev \ libgpgme11-dev \
liblzma-dev \ liblzma-dev \
netcat \ netcat \
socat \
--no-install-recommends \ --no-install-recommends \
&& apt-get clean && apt-get clean
@ -113,7 +114,3 @@ COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redh
WORKDIR /go/src/github.com/kubernetes-incubator/cri-o WORKDIR /go/src/github.com/kubernetes-incubator/cri-o
ADD . /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

View file

@ -14,6 +14,7 @@ ETCDIR_CRIO ?= ${ETCDIR}/crio
BUILDTAGS ?= selinux seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) BUILDTAGS ?= selinux seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh)
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z) SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
PACKAGES ?= $(shell go list -tags "${BUILDTAGS}" ./... | grep -v github.com/kubernetes-incubator/cri-o/vendor)
COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true) COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true)
GIT_COMMIT := $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}") GIT_COMMIT := $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}")
@ -113,7 +114,10 @@ dbuild: crioimage
docker run --name=${CRIO_INSTANCE} --privileged ${CRIO_IMAGE} -v ${PWD}:/go/src/${PROJECT} --rm make binaries docker run --name=${CRIO_INSTANCE} --privileged ${CRIO_IMAGE} -v ${PWD}:/go/src/${PROJECT} --rm make binaries
integration: crioimage 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
testunit:
$(GO) test -tags "$(BUILDTAGS)" -cover $(PACKAGES)
localintegration: clean binaries localintegration: clean binaries
./test/test_runner.sh ${TESTFLAGS} ./test/test_runner.sh ${TESTFLAGS}

View file

@ -7,13 +7,16 @@ import (
"flag" "flag"
"github.com/containers/storage"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
func TestGetStore(t *testing.T) { func TestGetStore(t *testing.T) {
t.Skip("FIX THIS!")
//cmd/kpod/common_test.go:27: cannot use c (type *cli.Context) as type *libkpod.Config in argument to getStore
// Make sure the tests are running as root // Make sure the tests are running as root
failTestIfNotRoot(t) skipTestIfNotRoot(t)
set := flag.NewFlagSet("test", 0) set := flag.NewFlagSet("test", 0)
globalSet := flag.NewFlagSet("test", 0) globalSet := flag.NewFlagSet("test", 0)
@ -23,33 +26,21 @@ func TestGetStore(t *testing.T) {
c := cli.NewContext(nil, set, globalCtx) c := cli.NewContext(nil, set, globalCtx)
c.Command = command c.Command = command
_, err := getStore(c) //_, err := getStore(c)
if err != nil { //if err != nil {
t.Error(err) //t.Error(err)
} //}
} }
func failTestIfNotRoot(t *testing.T) { func skipTestIfNotRoot(t *testing.T) {
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
t.Log("Could not determine user. Running without root may cause tests to fail") t.Skip("Could not determine user. Running without root may cause tests to fail")
} else if u.Uid != "0" { } else if u.Uid != "0" {
t.Fatal("tests will fail unless run as root") t.Skip("tests will fail unless run as root")
} }
} }
func getStoreForTests() (storage.Store, error) {
set := flag.NewFlagSet("test", 0)
globalSet := flag.NewFlagSet("test", 0)
globalSet.String("root", "", "path to the root directory in which data, including images, is stored")
globalCtx := cli.NewContext(nil, globalSet, nil)
command := cli.Command{Name: "testCommand"}
c := cli.NewContext(nil, set, globalCtx)
c.Command = command
return getStore(c)
}
func pullTestImage(name string) error { func pullTestImage(name string) error {
cmd := exec.Command("crioctl", "image", "pull", name) cmd := exec.Command("crioctl", "image", "pull", name)
err := cmd.Run() err := cmd.Run()

View file

@ -49,6 +49,7 @@
- oci-systemd-hook - oci-systemd-hook
- oci-register-machine - oci-register-machine
- oci-umount - oci-umount
- socat
async: 600 async: 600
poll: 10 poll: 10
when: (ansible_distribution == 'RedHat' or ansible_distribution == 'CentOS') when: (ansible_distribution == 'RedHat' or ansible_distribution == 'CentOS')
@ -79,6 +80,7 @@
- oci-systemd-hook - oci-systemd-hook
- oci-register-machine - oci-register-machine
- oci-umount - oci-umount
- socat
async: 600 async: 600
poll: 10 poll: 10
when: ansible_distribution == 'Fedora' when: ansible_distribution == 'Fedora'

View file

@ -335,6 +335,7 @@ func (c *ContainerServer) LoadSandbox(id string) error {
if err != nil { if err != nil {
return err return err
} }
sb.AddHostnamePath(m.Annotations[annotations.HostnamePath])
sb.AddIP(ip) sb.AddIP(ip)
// We add a netNS only if we can load a permanent one. // We add a netNS only if we can load a permanent one.

View file

@ -151,6 +151,7 @@ type Sandbox struct {
privileged bool privileged bool
trusted bool trusted bool
resolvPath string resolvPath string
hostnamePath string
hostname string hostname string
portMappings []*hostport.PortMapping portMappings []*hostport.PortMapping
stopped bool stopped bool
@ -301,6 +302,16 @@ func (s *Sandbox) ResolvPath() string {
return s.resolvPath 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 // Hostname returns the hsotname of the sandbox
func (s *Sandbox) Hostname() string { func (s *Sandbox) Hostname() string {
return s.hostname return s.hostname

View file

@ -233,3 +233,10 @@ func (c *Container) SetMountPoint(mp string) {
func (c *Container) MountPoint() string { func (c *Container) MountPoint() string {
return c.mountPoint return c.mountPoint
} }
// SetState sets the conainer state
//
// XXX: DO NOT EVER USE THIS, THIS IS JUST USEFUL FOR MOCKING!!!
func (c *Container) SetState(state *ContainerState) {
c.state = state
}

View file

@ -52,6 +52,9 @@ const (
// ResolvPath is the resolver configuration path annotation // ResolvPath is the resolver configuration path annotation
ResolvPath = "io.kubernetes.cri-o.ResolvPath" 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 is the sandbox ID annotation
SandboxID = "io.kubernetes.cri-o.SandboxID" SandboxID = "io.kubernetes.cri-o.SandboxID"

View file

@ -45,7 +45,7 @@ const (
defaultSystemdParent = "system.slice" 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{} volumes := []oci.ContainerVolume{}
mounts := containerConfig.GetMounts() mounts := containerConfig.GetMounts()
for _, mount := range mounts { for _, mount := range mounts {
@ -73,7 +73,7 @@ func addOCIBindMounts(sb *sandbox.Sandbox, containerConfig *pb.ContainerConfig,
if mount.SelinuxRelabel { if mount.SelinuxRelabel {
// Need a way in kubernetes to determine if the volume is shared or private // 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) return nil, fmt.Errorf("relabel failed %s: %v", src, err)
} }
} }
@ -304,11 +304,11 @@ func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.Linux
if sc != nil { if sc != nil {
containerUser := "" containerUser := ""
// Case 1: run as user is set by kubelet // Case 1: run as user is set by kubelet
if sc.RunAsUser != nil { if sc.GetRunAsUser() != nil {
containerUser = strconv.FormatInt(sc.GetRunAsUser().Value, 10) containerUser = strconv.FormatInt(sc.GetRunAsUser().Value, 10)
} else { } else {
// Case 2: run as username is set by kubelet // Case 2: run as username is set by kubelet
userName := sc.RunAsUsername userName := sc.GetRunAsUsername()
if userName != "" { if userName != "" {
containerUser = userName containerUser = userName
} else { } else {
@ -338,7 +338,7 @@ func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.Linux
} }
// Add groups from CRI // Add groups from CRI
groups := sc.SupplementalGroups groups := sc.GetSupplementalGroups()
for _, group := range groups { for _, group := range groups {
specgen.AddProcessAdditionalGid(uint32(group)) specgen.AddProcessAdditionalGid(uint32(group))
} }
@ -519,7 +519,18 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
specgen.HostSpecific = true specgen.HostSpecific = true
specgen.ClearProcessRlimits() specgen.ClearProcessRlimits()
containerVolumes, err := addOCIBindMounts(sb, containerConfig, &specgen) mountLabel := sb.MountLabel()
processLabel := sb.ProcessLabel()
selinuxConfig := containerConfig.GetLinux().GetSecurityContext().GetSelinuxOptions()
if selinuxConfig != nil {
var err error
processLabel, mountLabel, err = getSELinuxLabels(selinuxConfig)
if err != nil {
return nil, err
}
}
containerVolumes, err := addOCIBindMounts(mountLabel, containerConfig, &specgen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -703,7 +714,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
} }
} }
} }
specgen.SetProcessSelinuxLabel(sb.ProcessLabel()) specgen.SetProcessSelinuxLabel(processLabel)
} }
specgen.SetLinuxMountLabel(sb.MountLabel()) specgen.SetLinuxMountLabel(sb.MountLabel())
@ -818,18 +829,28 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
options = []string{"ro"} options = []string{"ro"}
} }
if sb.ResolvPath() != "" { if sb.ResolvPath() != "" {
if err := label.Relabel(sb.ResolvPath(), mountLabel, true); err != nil && err != unix.ENOTSUP {
return nil, err
}
// bind mount the pod resolver file // bind mount the pod resolver file
specgen.AddBindMount(sb.ResolvPath(), "/etc/resolv.conf", options) specgen.AddBindMount(sb.ResolvPath(), "/etc/resolv.conf", options)
} }
if sb.HostnamePath() != "" {
if err := label.Relabel(sb.HostnamePath(), mountLabel, true); err != nil && err != unix.ENOTSUP {
return nil, err
}
specgen.AddBindMount(sb.HostnamePath(), "/etc/hostname", options)
}
// Bind mount /etc/hosts for host networking containers // Bind mount /etc/hosts for host networking containers
if hostNetwork(containerConfig) { if hostNetwork(containerConfig) {
specgen.AddBindMount("/etc/hosts", "/etc/hosts", options) 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.Name, containerName)
specgen.AddAnnotation(annotations.ContainerID, containerID) specgen.AddAnnotation(annotations.ContainerID, containerID)
@ -877,7 +898,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
containerName, containerID, containerName, containerID,
metaname, metaname,
attempt, attempt,
sb.MountLabel(), mountLabel,
nil) nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -900,7 +921,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
} }
// Add image volumes // 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 return nil, err
} }

View file

@ -2,10 +2,14 @@ package server
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"github.com/go-zoo/bone" "github.com/go-zoo/bone"
"github.com/kubernetes-incubator/cri-o/libkpod/sandbox"
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/sirupsen/logrus"
) )
// ContainerInfo stores information about containers // ContainerInfo stores information about containers
@ -29,16 +33,59 @@ type CrioInfo struct {
CgroupDriver string `json:"cgroup_driver"` CgroupDriver string `json:"cgroup_driver"`
} }
func (s *Server) getInfo() CrioInfo {
return CrioInfo{
StorageDriver: s.config.Config.Storage,
StorageRoot: s.config.Config.Root,
CgroupDriver: s.config.Config.CgroupManager,
}
}
var (
errCtrNotFound = errors.New("container not found")
errCtrStateNil = errors.New("container state is nil")
errSandboxNotFound = errors.New("sandbox for container not found")
)
func (s *Server) getContainerInfo(id string, getContainerFunc func(id string) *oci.Container, getInfraContainerFunc func(id string) *oci.Container, getSandboxFunc func(id string) *sandbox.Sandbox) (ContainerInfo, error) {
ctr := getContainerFunc(id)
if ctr == nil {
ctr = getInfraContainerFunc(id)
if ctr == nil {
return ContainerInfo{}, errCtrNotFound
}
}
// TODO(mrunalp): should we call UpdateStatus()?
ctrState := ctr.State()
if ctrState == nil {
return ContainerInfo{}, errCtrStateNil
}
sb := getSandboxFunc(ctr.Sandbox())
if sb == nil {
logrus.Debugf("can't find sandbox %s for container %s", ctr.Sandbox(), id)
return ContainerInfo{}, errSandboxNotFound
}
return ContainerInfo{
Name: ctr.Name(),
Pid: ctrState.Pid,
Image: ctr.Image(),
CreatedTime: ctrState.Created.UnixNano(),
Labels: ctr.Labels(),
Annotations: ctr.Annotations(),
Root: ctr.MountPoint(),
LogPath: ctr.LogPath(),
Sandbox: ctr.Sandbox(),
IP: sb.IP(),
}, nil
}
// GetInfoMux returns the mux used to serve info requests // GetInfoMux returns the mux used to serve info requests
func (s *Server) GetInfoMux() *bone.Mux { func (s *Server) GetInfoMux() *bone.Mux {
mux := bone.New() mux := bone.New()
mux.Get("/info", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { mux.Get("/info", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ci := CrioInfo{ ci := s.getInfo()
StorageDriver: s.config.Config.Storage,
StorageRoot: s.config.Config.Root,
CgroupDriver: s.config.Config.CgroupManager,
}
js, err := json.Marshal(ci) js, err := json.Marshal(ci)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -50,36 +97,20 @@ func (s *Server) GetInfoMux() *bone.Mux {
mux.Get("/containers/:id", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { mux.Get("/containers/:id", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
containerID := bone.GetValue(req, "id") containerID := bone.GetValue(req, "id")
ctr := s.GetContainer(containerID) ci, err := s.getContainerInfo(containerID, s.GetContainer, s.getInfraContainer, s.getSandbox)
if ctr == nil { if err != nil {
ctr = s.getInfraContainer(containerID) switch err {
if ctr == nil { case errCtrNotFound:
http.Error(w, fmt.Sprintf("container with id: %s not found", containerID), http.StatusNotFound) http.Error(w, fmt.Sprintf("can't find the container with id %s", containerID), http.StatusNotFound)
case errCtrStateNil:
http.Error(w, fmt.Sprintf("can't find container state for container with id %s", containerID), http.StatusInternalServerError)
case errSandboxNotFound:
http.Error(w, fmt.Sprintf("can't find the sandbox for container id %s", containerID), http.StatusNotFound)
default:
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return return
} }
}
ctrState := ctr.State()
if ctrState == nil {
http.Error(w, fmt.Sprintf("container %s state is nil", containerID), http.StatusNotFound)
return
}
sb := s.getSandbox(ctr.Sandbox())
if sb == nil {
http.Error(w, fmt.Sprintf("can't find the sandbox for container id, sandbox id %s: %s", containerID, ctr.Sandbox()), http.StatusNotFound)
return
}
ci := ContainerInfo{
Name: ctr.Name(),
Pid: ctrState.Pid,
Image: ctr.Image(),
CreatedTime: ctrState.Created.UnixNano(),
Labels: ctr.Labels(),
Annotations: ctr.Annotations(),
Root: ctr.MountPoint(),
LogPath: ctr.LogPath(),
Sandbox: ctr.Sandbox(),
IP: sb.IP(),
}
js, err := json.Marshal(ci) js, err := json.Marshal(ci)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

235
server/inspect_test.go Normal file
View file

@ -0,0 +1,235 @@
package server
import (
"testing"
"time"
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/kubernetes-incubator/cri-o/libkpod/sandbox"
"github.com/kubernetes-incubator/cri-o/oci"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
func TestGetInfo(t *testing.T) {
c := libkpod.DefaultConfig()
c.RootConfig.Storage = "afoobarstorage"
c.RootConfig.Root = "afoobarroot"
c.RuntimeConfig.CgroupManager = "systemd"
apiConfig := APIConfig{}
s := &Server{
config: Config{*c, apiConfig},
}
ci := s.getInfo()
if ci.CgroupDriver != "systemd" {
t.Fatalf("expected 'systemd', got %q", ci.CgroupDriver)
}
if ci.StorageDriver != "afoobarstorage" {
t.Fatalf("expected 'afoobarstorage', got %q", ci.StorageDriver)
}
if ci.StorageRoot != "afoobarroot" {
t.Fatalf("expected 'afoobarroot', got %q", ci.StorageRoot)
}
}
type mockNetNS struct {
}
func (ns mockNetNS) Close() error {
return nil
}
func (ns mockNetNS) Fd() uintptr {
ptr := new(uintptr)
return *ptr
}
func (ns mockNetNS) Do(toRun func(ns.NetNS) error) error {
return nil
}
func (ns mockNetNS) Set() error {
return nil
}
func (ns mockNetNS) Path() string {
return ""
}
func TestGetContainerInfo(t *testing.T) {
s := &Server{}
created := time.Now()
labels := map[string]string{
"io.kubernetes.container.name": "POD",
"io.kubernetes.test2": "value2",
"io.kubernetes.test3": "value3",
}
annotations := map[string]string{
"io.kubernetes.test": "value",
"io.kubernetes.test1": "value1",
}
getContainerFunc := func(id string) *oci.Container {
container, err := oci.NewContainer("testid", "testname", "", "/container/logs", mockNetNS{}, labels, annotations, "imageName", "imageName", "imageRef", &runtime.ContainerMetadata{}, "testsandboxid", false, false, false, false, false, "/root/for/container", created, "SIGKILL")
if err != nil {
t.Fatal(err)
}
container.SetMountPoint("/var/foo/container")
cstate := &oci.ContainerState{}
cstate.State = specs.State{
Pid: 42,
}
cstate.Created = created
container.SetState(cstate)
return container
}
getInfraContainerFunc := func(id string) *oci.Container {
return nil
}
getSandboxFunc := func(id string) *sandbox.Sandbox {
s := &sandbox.Sandbox{}
s.AddIP("1.1.1.42")
return s
}
ci, err := s.getContainerInfo("", getContainerFunc, getInfraContainerFunc, getSandboxFunc)
if err != nil {
t.Fatal(err)
}
if ci.CreatedTime != created.UnixNano() {
t.Fatalf("expected same created time %d, got %d", created.UnixNano(), ci.CreatedTime)
}
if ci.Pid != 42 {
t.Fatalf("expected pid 42, got %s", ci.Pid)
}
if ci.Name != "testname" {
t.Fatalf("expected name testname, got %s", ci.Name)
}
if ci.Image != "imageName" {
t.Fatalf("expected image name imageName, got %s", ci.Image)
}
if ci.Root != "/var/foo/container" {
t.Fatalf("expected root to be /var/foo/container, got %s", ci.Root)
}
if ci.LogPath != "/container/logs" {
t.Fatalf("expected log path to be /containers/logs, got %s", ci.LogPath)
}
if ci.Sandbox != "testsandboxid" {
t.Fatalf("expected sandbox to be testsandboxid, got %s", ci.Sandbox)
}
if ci.IP != "1.1.1.42" {
t.Fatal("expected ip 1.1.1.42, got %s", ci.IP)
}
if len(ci.Annotations) == 0 {
t.Fatal("annotations are empty")
}
if len(ci.Labels) == 0 {
t.Fatal("labels are empty")
}
if len(ci.Annotations) != len(annotations) {
t.Fatalf("container info annotations len (%d) isn't the same as original annotations len (%d)", len(ci.Annotations), len(annotations))
}
if len(ci.Labels) != len(labels) {
t.Fatalf("container info labels len (%d) isn't the same as original labels len (%d)", len(ci.Labels), len(labels))
}
var found bool
for k, v := range annotations {
found = false
for key, value := range ci.Annotations {
if k == key && v == value {
found = true
break
}
}
if !found {
t.Fatalf("key %s with value %v wasn't in container info annotations", k, v)
}
}
for k, v := range labels {
found = false
for key, value := range ci.Labels {
if k == key && v == value {
found = true
break
}
}
if !found {
t.Fatalf("key %s with value %v wasn't in container info labels", k, v)
}
}
}
func TestGetContainerInfoCtrNotFound(t *testing.T) {
s := &Server{}
getContainerFunc := func(id string) *oci.Container {
return nil
}
getInfraContainerFunc := func(id string) *oci.Container {
return nil
}
getSandboxFunc := func(id string) *sandbox.Sandbox {
return nil
}
_, err := s.getContainerInfo("", getContainerFunc, getInfraContainerFunc, getSandboxFunc)
if err == nil {
t.Fatal("expected an error but got nothing")
}
if err != errCtrNotFound {
t.Fatalf("expected errCtrNotFound error, got %v", err)
}
}
func TestGetContainerInfoCtrStateNil(t *testing.T) {
s := &Server{}
created := time.Now()
labels := map[string]string{}
annotations := map[string]string{}
getContainerFunc := func(id string) *oci.Container {
container, err := oci.NewContainer("testid", "testname", "", "/container/logs", mockNetNS{}, labels, annotations, "imageName", "imageName", "imageRef", &runtime.ContainerMetadata{}, "testsandboxid", false, false, false, false, false, "/root/for/container", created, "SIGKILL")
if err != nil {
t.Fatal(err)
}
container.SetMountPoint("/var/foo/container")
container.SetState(nil)
return container
}
getInfraContainerFunc := func(id string) *oci.Container {
return nil
}
getSandboxFunc := func(id string) *sandbox.Sandbox {
s := &sandbox.Sandbox{}
s.AddIP("1.1.1.42")
return s
}
_, err := s.getContainerInfo("", getContainerFunc, getInfraContainerFunc, getSandboxFunc)
if err == nil {
t.Fatal("expected an error but got nothing")
}
if err != errCtrStateNil {
t.Fatalf("expected errCtrStateNil error, got %v", err)
}
}
func TestGetContainerInfoSandboxNotFound(t *testing.T) {
s := &Server{}
created := time.Now()
labels := map[string]string{}
annotations := map[string]string{}
getContainerFunc := func(id string) *oci.Container {
container, err := oci.NewContainer("testid", "testname", "", "/container/logs", mockNetNS{}, labels, annotations, "imageName", "imageName", "imageRef", &runtime.ContainerMetadata{}, "testsandboxid", false, false, false, false, false, "/root/for/container", created, "SIGKILL")
if err != nil {
t.Fatal(err)
}
container.SetMountPoint("/var/foo/container")
return container
}
getInfraContainerFunc := func(id string) *oci.Container {
return nil
}
getSandboxFunc := func(id string) *sandbox.Sandbox {
return nil
}
_, err := s.getContainerInfo("", getContainerFunc, getInfraContainerFunc, getSandboxFunc)
if err == nil {
t.Fatal("expected an error but got nothing")
}
if err != errSandboxNotFound {
t.Fatalf("expected errSandboxNotFound error, got %v", err)
}
}

View file

@ -3,6 +3,7 @@ package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -187,12 +188,6 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
g.SetProcessArgs([]string{s.config.PauseCommand}) g.SetProcessArgs([]string{s.config.PauseCommand})
} }
// set hostname
hostname := req.GetConfig().Hostname
if hostname != "" {
g.SetHostname(hostname)
}
// set DNS options // set DNS options
if req.GetConfig().GetDnsConfig() != nil { if req.GetConfig().GetDnsConfig() != nil {
dnsServers := req.GetConfig().GetDnsConfig().Servers dnsServers := req.GetConfig().GetDnsConfig().Servers
@ -208,6 +203,10 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
} }
return nil, err return nil, err
} }
if err := label.Relabel(resolvPath, mountLabel, true); err != nil && err != unix.ENOTSUP {
return nil, err
}
g.AddBindMount(resolvPath, "/etc/resolv.conf", []string{"ro"}) g.AddBindMount(resolvPath, "/etc/resolv.conf", []string{"ro"})
} }
@ -250,7 +249,7 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
// Don't use SELinux separation with Host Pid or IPC Namespace, // Don't use SELinux separation with Host Pid or IPC Namespace,
if !req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostPid && !req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostIpc { if !req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostPid && !req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostIpc {
processLabel, mountLabel, err = getSELinuxLabels(nil) processLabel, mountLabel, err = getSELinuxLabels(req.GetConfig().GetLinux().GetSecurityContext().GetSelinuxOptions())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -301,6 +300,14 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
return nil, err 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) privileged := s.privilegedSandbox(req)
trusted := s.trustedSandbox(req) trusted := s.trustedSandbox(req)
g.AddAnnotation(annotations.Metadata, string(metadataJSON)) g.AddAnnotation(annotations.Metadata, string(metadataJSON))
@ -399,8 +406,6 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
g.SetLinuxResourcesCPUShares(PodInfraCPUshares) g.SetLinuxResourcesCPUShares(PodInfraCPUshares)
hostNetwork := req.GetConfig().GetLinux().GetSecurityContext().GetNamespaceOptions().HostNetwork
// set up namespaces // set up namespaces
if hostNetwork { if hostNetwork {
err = g.RemoveLinuxNamespace("network") err = g.RemoveLinuxNamespace("network")
@ -456,6 +461,17 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
g.AddAnnotation(annotations.MountPoint, mountPoint) g.AddAnnotation(annotations.MountPoint, mountPoint)
g.SetRootPath(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
}
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)
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) 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 { if err != nil {
return nil, err return nil, err
@ -515,6 +531,23 @@ func convertPortMappings(in []*pb.PortMapping) []*hostport.PortMapping {
return out 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 { func (s *Server) setPodSandboxMountLabel(id, mountLabel string) error {
storageMetadata, err := s.StorageRuntimeServer().GetContainerMetadata(id) storageMetadata, err := s.StorageRuntimeServer().GetContainerMetadata(id)
if err != nil { if err != nil {
@ -525,30 +558,22 @@ func (s *Server) setPodSandboxMountLabel(id, mountLabel string) error {
} }
func getSELinuxLabels(selinuxOptions *pb.SELinuxOption) (processLabel string, mountLabel string, err error) { func getSELinuxLabels(selinuxOptions *pb.SELinuxOption) (processLabel string, mountLabel string, err error) {
processLabel = "" labels := []string{}
if selinuxOptions != nil { if selinuxOptions != nil {
user := selinuxOptions.User if selinuxOptions.User != "" {
if user == "" { labels = append(labels, "user:"+selinuxOptions.User)
return "", "", fmt.Errorf("SELinuxOption.User is empty")
} }
if selinuxOptions.Role != "" {
role := selinuxOptions.Role labels = append(labels, "role:"+selinuxOptions.Role)
if role == "" {
return "", "", fmt.Errorf("SELinuxOption.Role is empty")
} }
if selinuxOptions.Type != "" {
t := selinuxOptions.Type labels = append(labels, "type:"+selinuxOptions.Type)
if t == "" {
return "", "", fmt.Errorf("SELinuxOption.Type is empty")
} }
if selinuxOptions.Level != "" {
level := selinuxOptions.Level labels = append(labels, "level:"+selinuxOptions.Level)
if level == "" {
return "", "", fmt.Errorf("SELinuxOption.Level is empty")
} }
processLabel = fmt.Sprintf("%s:%s:%s:%s", user, role, t, level)
} }
return label.InitLabels(label.DupSecOpt(processLabel)) return label.InitLabels(labels)
} }
func setupShm(podSandboxRunDir, mountLabel string) (shmPath string, err error) { func setupShm(podSandboxRunDir, mountLabel string) (shmPath string, err error) {

60
test/inspect.bats Normal file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env bats
load helpers
function teardown() {
cleanup_test
}
@test "info inspect" {
start_crio
out=`echo -e "GET /info HTTP/1.1\r\nHost: crio\r\n" | socat - UNIX-CONNECT:$CRIO_SOCKET`
echo "$out"
[[ "$out" =~ "\"cgroup_driver\":\"$CGROUP_MANAGER\"" ]]
[[ "$out" =~ "\"storage_root\":\"$TESTDIR/crio\"" ]]
stop_crio
}
@test "ctr inspect" {
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_config.json --pod "$pod_id"
echo "$output"
[ "$status" -eq 0 ]
ctr_id="$output"
out=`echo -e "GET /containers/$ctr_id HTTP/1.1\r\nHost: crio\r\n" | socat - UNIX-CONNECT:$CRIO_SOCKET`
echo "$out"
[[ "$out" =~ "\"sandbox\":\"$pod_id\"" ]]
[[ "$out" =~ "\"image\":\"redis:alpine\"" ]]
inet=`crioctl ctr execsync --id $ctr_id ip addr show dev eth0 scope global 2>&1 | grep inet`
IFS=" "
ip=`parse_pod_ip $inet`
[[ "$out" =~ "\"ip_address\":\"$ip\"" ]]
[[ "$out" =~ "\"name\":\"k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1\"" ]]
# TODO: add some other check based on the json below:
#
# {"name":"k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1","pid":27477,"image":"redis:alpine","created_time":1505223601111546169,"labels":{"batch":"no","type":"small"},"annotations":{"daemon":"crio","owner":"dragon"},"log_path":"/var/log/crio/pods/297d014ba2c54236779da0c2f80dfba45dc31b106e4cd126a1c3c6d78edc2201/81567e9573ea798d6494c9aab156103ee91b72180fd3841a7c24d2ca39886ba2.log","root":"/tmp/tmp.0bkjphWudF/crio/overlay/d7cfc1de83cab9f377a4a1542427d2a019e85a70c1c660a9e6cf9e254df68873/merged","sandbox":"297d014ba2c54236779da0c2f80dfba45dc31b106e4cd126a1c3c6d78edc2201","ip_address":"10.88.9.153"}
cleanup_ctrs
cleanup_pods
stop_crio
}
@test "ctr inspect not found" {
start_crio
out=`echo -e "GET /containers/notexists HTTP/1.1\r\nHost: crio\r\n" | socat - UNIX-CONNECT:$CRIO_SOCKET`
echo "$out"
[[ "$out" =~ "can't find the container with id notexists" ]]
stop_crio
}

View file

@ -2,6 +2,72 @@
load helpers 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" { @test "Check for valid pod netns CIDR" {
start_crio start_crio
run crioctl pod run --config "$TESTDATA"/sandbox_config.json run crioctl pod run --config "$TESTDATA"/sandbox_config.json

26
test/selinux.bats Normal file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bats
load helpers
function teardown() {
cleanup_test
}
@test "ctr termination reason Completed" {
start_crio
run crioctl pod run --config "$TESTDATA"/sandbox_config_selinux.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 ]
cleanup_ctrs
cleanup_pods
stop_crio
}

View file

@ -51,6 +51,12 @@
}, },
"security_context": { "security_context": {
"readonly_rootfs": false, "readonly_rootfs": false,
"selinux_options": {
"user": "system_u",
"role": "system_r",
"type": "svirt_lxc_net_t",
"level": "s0:c4,c5"
},
"capabilities": { "capabilities": {
"add_capabilities": [ "add_capabilities": [
"setuid", "setuid",
@ -58,12 +64,6 @@
], ],
"drop_capabilities": [ "drop_capabilities": [
] ]
},
"selinux_options": {
"user": "system_u",
"role": "system_r",
"type": "container_t",
"level": "s0:c4,c5"
} }
} }
} }

View file

@ -62,7 +62,7 @@
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c4,c5" "level": "s0:c4,c5"
} }
} }

View file

@ -64,7 +64,7 @@
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c4,c5" "level": "s0:c4,c5"
} }
} }

View file

@ -64,7 +64,7 @@
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c4,c5" "level": "s0:c4,c5"
} }
} }

View file

@ -64,7 +64,7 @@
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c4,c5" "level": "s0:c4,c5"
} }
} }

View file

@ -64,7 +64,7 @@
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c4,c5" "level": "s0:c4,c5"
} }
} }

View file

@ -65,7 +65,7 @@
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "svirt_lxc_net_t", "type": "svirt_lxc_net_t",
"level": "s0:c4-c5" "level": "s0:c4,c5"
} }
} }
} }

View file

@ -39,6 +39,12 @@
"host_network": false, "host_network": false,
"host_pid": false, "host_pid": false,
"host_ipc": false "host_ipc": false
},
"selinux_options": {
"user": "system_u",
"role": "system_r",
"type": "svirt_lxc_net_t",
"level": "s0:c4,c5"
} }
} }
} }

View file

@ -41,13 +41,13 @@
"host_network": false, "host_network": false,
"host_pid": false, "host_pid": false,
"host_ipc": false "host_ipc": false
}
}, },
"selinux_options": { "selinux_options": {
"user": "system_u", "user": "system_u",
"role": "system_r", "role": "system_r",
"type": "container_t", "type": "svirt_lxc_net_t",
"level": "s0:c1,c2" "level": "s0:c4,c5"
}
} }
} }
} }

View file

@ -0,0 +1,48 @@
{
"metadata": {
"name": "podsandbox1",
"uid": "redhat-test-crio",
"namespace": "redhat.test.crio",
"attempt": 1
},
"hostname": "crioctl_host",
"log_directory": "",
"dns_config": {
"searches": [
"8.8.8.8"
]
},
"port_mappings": [],
"resources": {
"cpu": {
"limits": 3,
"requests": 2
},
"memory": {
"limits": 50000000,
"requests": 2000000
}
},
"labels": {
"group": "test"
},
"annotations": {
"owner": "hmeng",
"security.alpha.kubernetes.io/sysctls": "kernel.shm_rmid_forced=1,net.ipv4.ip_local_port_range=1024 65000",
"security.alpha.kubernetes.io/unsafe-sysctls": "kernel.msgmax=8192" ,
"security.alpha.kubernetes.io/seccomp/pod": "unconfined"
},
"linux": {
"cgroup_parent": "/Burstable/pod_123-456",
"security_context": {
"namespace_options": {
"host_network": false,
"host_pid": false,
"host_ipc": false
},
"selinux_options": {
"level": "s0"
}
}
}
}