diff --git a/Makefile b/Makefile index 4f1d1dcf..9e211a3c 100644 --- a/Makefile +++ b/Makefile @@ -116,13 +116,13 @@ MANPAGES_MD := $(wildcard docs/*.md) MANPAGES := $(MANPAGES_MD:%.md=%) docs/%.1: docs/%.1.md .gopathok - $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ + go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ || $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ docs/%.5: docs/%.5.md .gopathok - $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ + go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ || $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ docs/%.8: docs/%.8.md .gopathok - $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ + go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ || $(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@ docs: $(MANPAGES) diff --git a/oci/container.go b/oci/container.go index 9ac624e4..4717b9ea 100644 --- a/oci/container.go +++ b/oci/container.go @@ -1,7 +1,10 @@ package oci import ( + "encoding/json" "fmt" + "os" + "path/filepath" "sync" "time" @@ -15,7 +18,6 @@ import ( type Container struct { id string name string - bundlePath string logPath string labels fields.Set annotations fields.Set @@ -27,6 +29,10 @@ type Container struct { state *ContainerState metadata *pb.ContainerMetadata opLock sync.Mutex + // this is the /var/run/storage/... directory, erased on reboot + bundlePath string + // this is the /var/lib/storage/... directory + dir string } // ContainerState represents the status of a container. @@ -39,7 +45,9 @@ type ContainerState struct { } // NewContainer creates a container object. -func NewContainer(id string, name string, bundlePath string, logPath string, netns ns.NetNS, labels map[string]string, annotations map[string]string, image *pb.ImageSpec, metadata *pb.ContainerMetadata, sandbox string, terminal bool, privileged bool) (*Container, error) { +func NewContainer(id string, name string, bundlePath string, logPath string, netns ns.NetNS, labels map[string]string, annotations map[string]string, image *pb.ImageSpec, metadata *pb.ContainerMetadata, sandbox string, terminal bool, privileged bool, dir string, created time.Time) (*Container, error) { + state := &ContainerState{} + state.Created = created c := &Container{ id: id, name: name, @@ -53,10 +61,34 @@ func NewContainer(id string, name string, bundlePath string, logPath string, net metadata: metadata, annotations: annotations, image: image, + dir: dir, + state: state, } return c, nil } +// FromDisk restores container's state from disk +func (c *Container) FromDisk() error { + jsonSource, err := os.Open(c.StatePath()) + if err != nil { + return err + } + defer jsonSource.Close() + + dec := json.NewDecoder(jsonSource) + return dec.Decode(c.state) +} + +// StatePath returns the containers state.json path +func (c *Container) StatePath() string { + return filepath.Join(c.dir, "state.json") +} + +// CreatedAt returns the container creation time +func (c *Container) CreatedAt() time.Time { + return c.state.Created +} + // Name returns the name of the container. func (c *Container) Name() string { return c.name diff --git a/oci/oci.go b/oci/oci.go index 1f927102..b407c827 100644 --- a/oci/oci.go +++ b/oci/oci.go @@ -439,6 +439,11 @@ func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp func (r *Runtime) StopContainer(c *Container) error { c.opLock.Lock() defer c.opLock.Unlock() + + if c.state.Status != ContainerStateRunning { + return nil + } + if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "kill", c.name, "TERM"); err != nil { return err } @@ -460,6 +465,8 @@ func (r *Runtime) StopContainer(c *Container) error { i++ } + c.state.Finished = time.Now() + return nil } @@ -467,7 +474,10 @@ func (r *Runtime) StopContainer(c *Container) error { func (r *Runtime) DeleteContainer(c *Container) error { c.opLock.Lock() defer c.opLock.Unlock() - return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "delete", c.name) + if _, err := utils.ExecCmd(r.Path(c), "delete", c.name); err != nil && !strings.Contains(err.Error(), "does not exist") { + return err + } + return nil } // UpdateStatus refreshes the status of the container. @@ -476,6 +486,9 @@ func (r *Runtime) UpdateStatus(c *Container) error { defer c.opLock.Unlock() out, err := exec.Command(r.Path(c), "state", c.name).CombinedOutput() if err != nil { + if strings.Contains(string(out), "does not exist") { + return nil + } return fmt.Errorf("error getting container state for %s: %s: %q", c.name, err, out) } if err := json.NewDecoder(bytes.NewBuffer(out)).Decode(&c.state); err != nil { diff --git a/server/container_create.go b/server/container_create.go index f4af1eb2..dd45c4cc 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" @@ -18,7 +19,9 @@ import ( "github.com/kubernetes-incubator/cri-o/server/apparmor" "github.com/kubernetes-incubator/cri-o/server/seccomp" "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/user" + rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "golang.org/x/net/context" @@ -62,6 +65,33 @@ func addOciBindMounts(sb *sandbox, containerConfig *pb.ContainerConfig, specgen return nil } +func addDevices(sb *sandbox, containerConfig *pb.ContainerConfig, specgen *generate.Generator) error { + sp := specgen.Spec() + for _, device := range containerConfig.GetDevices() { + dev, err := devices.DeviceFromPath(device.HostPath, device.Permissions) + if err != nil { + return fmt.Errorf("failed to add device: %v", err) + } + rd := rspec.LinuxDevice{ + Path: device.ContainerPath, + Type: string(dev.Type), + Major: dev.Major, + Minor: dev.Minor, + UID: &dev.Uid, + GID: &dev.Gid, + } + specgen.AddDevice(rd) + sp.Linux.Resources.Devices = append(sp.Linux.Resources.Devices, rspec.LinuxDeviceCgroup{ + Allow: true, + Type: string(dev.Type), + Major: &dev.Major, + Minor: &dev.Minor, + Access: dev.Permissions, + }) + } + return nil +} + // buildOCIProcessArgs build an OCI compatible process arguments slice. func buildOCIProcessArgs(containerKubeConfig *pb.ContainerConfig, imageOCIConfig *v1.Image) ([]string, error) { processArgs := []string{} @@ -280,6 +310,8 @@ func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerReq return nil, err } + s.containerStateToDisk(container) + resp := &pb.CreateContainerResponse{ ContainerId: containerID, } @@ -303,6 +335,10 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, return nil, err } + if err := addDevices(sb, containerConfig, &specgen); err != nil { + return nil, err + } + labels := containerConfig.GetLabels() metadata := containerConfig.GetMetadata() @@ -486,6 +522,9 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, specgen.AddAnnotation("ocid/tty", fmt.Sprintf("%v", containerConfig.Tty)) specgen.AddAnnotation("ocid/image", image) + created := time.Now() + specgen.AddAnnotation("ocid/created", created.Format(time.RFC3339Nano)) + metadataJSON, err := json.Marshal(metadata) if err != nil { return nil, err @@ -594,7 +633,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, return nil, err } - container, err := oci.NewContainer(containerID, containerName, containerInfo.RunDir, logPath, sb.netNs(), labels, annotations, imageSpec, metadata, sb.id, containerConfig.Tty, sb.privileged) + container, err := oci.NewContainer(containerID, containerName, containerInfo.RunDir, logPath, sb.netNs(), labels, annotations, imageSpec, metadata, sb.id, containerConfig.Tty, sb.privileged, containerInfo.Dir, created) if err != nil { return nil, err } diff --git a/server/container_list.go b/server/container_list.go index 9e372a5f..908145f2 100644 --- a/server/container_list.go +++ b/server/container_list.go @@ -66,9 +66,7 @@ func (s *Server) ListContainers(ctx context.Context, req *pb.ListContainersReque } for _, ctr := range ctrList { - if err := s.runtime.UpdateStatus(ctr); err != nil { - return nil, err - } + s.runtime.UpdateStatus(ctr) podSandboxID := ctr.Sandbox() cState := s.runtime.ContainerStatus(ctr) diff --git a/server/container_remove.go b/server/container_remove.go index 028ffed8..3f36b3d6 100644 --- a/server/container_remove.go +++ b/server/container_remove.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/Sirupsen/logrus" - "github.com/kubernetes-incubator/cri-o/oci" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime" ) @@ -22,11 +21,8 @@ func (s *Server) RemoveContainer(ctx context.Context, req *pb.RemoveContainerReq return nil, fmt.Errorf("failed to update container state: %v", err) } - cState := s.runtime.ContainerStatus(c) - if cState.Status == oci.ContainerStateCreated || cState.Status == oci.ContainerStateRunning { - if err := s.runtime.StopContainer(c); err != nil { - return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err) - } + if err := s.runtime.StopContainer(c); err != nil { + return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err) } if err := s.runtime.DeleteContainer(c); err != nil { diff --git a/server/container_start.go b/server/container_start.go index 128cc5fc..a426def9 100644 --- a/server/container_start.go +++ b/server/container_start.go @@ -20,6 +20,8 @@ func (s *Server) StartContainer(ctx context.Context, req *pb.StartContainerReque return nil, fmt.Errorf("failed to start container %s: %v", c.ID(), err) } + s.containerStateToDisk(c) + resp := &pb.StartContainerResponse{} logrus.Debugf("StartContainerResponse %+v", resp) return resp, nil diff --git a/server/container_status.go b/server/container_status.go index 82a51877..f28d21b2 100644 --- a/server/container_status.go +++ b/server/container_status.go @@ -18,9 +18,9 @@ func (s *Server) ContainerStatus(ctx context.Context, req *pb.ContainerStatusReq return nil, err } - if err = s.runtime.UpdateStatus(c); err != nil { - return nil, err - } + // best effort if container is still in runc store... + s.runtime.UpdateStatus(c) + s.containerStateToDisk(c) containerID := c.ID() image := c.Image() diff --git a/server/container_stop.go b/server/container_stop.go index 58865edf..d77f320e 100644 --- a/server/container_stop.go +++ b/server/container_stop.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/Sirupsen/logrus" - "github.com/kubernetes-incubator/cri-o/oci" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime" ) @@ -20,13 +19,12 @@ func (s *Server) StopContainer(ctx context.Context, req *pb.StopContainerRequest if err := s.runtime.UpdateStatus(c); err != nil { return nil, err } - cStatus := s.runtime.ContainerStatus(c) - if cStatus.Status != oci.ContainerStateStopped { - if err := s.runtime.StopContainer(c); err != nil { - return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err) - } + if err := s.runtime.StopContainer(c); err != nil { + return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err) } + s.containerStateToDisk(c) + resp := &pb.StopContainerResponse{} logrus.Debugf("StopContainerResponse: %+v", resp) return resp, nil diff --git a/server/sandbox_list.go b/server/sandbox_list.go index 9e4b3562..447db7ca 100644 --- a/server/sandbox_list.go +++ b/server/sandbox_list.go @@ -59,9 +59,8 @@ func (s *Server) ListPodSandbox(ctx context.Context, req *pb.ListPodSandboxReque // it's better not to panic continue } - if err := s.runtime.UpdateStatus(podInfraContainer); err != nil { - return nil, err - } + s.runtime.UpdateStatus(podInfraContainer) + cState := s.runtime.ContainerStatus(podInfraContainer) created := cState.Created.UnixNano() rStatus := pb.PodSandboxState_SANDBOX_NOTREADY diff --git a/server/sandbox_remove.go b/server/sandbox_remove.go index 9628c6b5..24ac62b1 100644 --- a/server/sandbox_remove.go +++ b/server/sandbox_remove.go @@ -5,7 +5,6 @@ import ( "syscall" "github.com/Sirupsen/logrus" - "github.com/kubernetes-incubator/cri-o/oci" "github.com/opencontainers/selinux/go-selinux/label" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime" @@ -36,12 +35,8 @@ func (s *Server) RemovePodSandbox(ctx context.Context, req *pb.RemovePodSandboxR return nil, fmt.Errorf("failed to update container state: %v", err) } - cState := s.runtime.ContainerStatus(c) - if cState.Status == oci.ContainerStateCreated || cState.Status == oci.ContainerStateRunning { - if err := s.runtime.StopContainer(c); err != nil { - // Assume container is already stopped - logrus.Warnf("failed to stop container %s: %v", c.Name(), err) - } + if err := s.runtime.StopContainer(c); err != nil { + return nil, fmt.Errorf("failed to stop container %s: %v", c.Name(), err) } if err := s.runtime.DeleteContainer(c); err != nil { diff --git a/server/sandbox_run.go b/server/sandbox_run.go index a43bd55f..d4d25065 100644 --- a/server/sandbox_run.go +++ b/server/sandbox_run.go @@ -7,6 +7,7 @@ import ( "path/filepath" "strconv" "syscall" + "time" "github.com/Sirupsen/logrus" "github.com/containers/storage/storage" @@ -267,6 +268,9 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest g.AddAnnotation("ocid/hostname", hostname) g.AddAnnotation("ocid/kube_name", kubeName) + created := time.Now() + g.AddAnnotation("ocid/created", created.Format(time.RFC3339Nano)) + sb := &sandbox{ id: id, namespace: namespace, @@ -399,7 +403,7 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest return nil, fmt.Errorf("failed to write runtime configuration for pod sandbox %s(%s): %v", sb.name, id, err) } - container, err := oci.NewContainer(id, containerName, podContainer.RunDir, logPath, sb.netNs(), labels, annotations, nil, nil, id, false, sb.privileged) + container, err := oci.NewContainer(id, containerName, podContainer.RunDir, logPath, sb.netNs(), labels, annotations, nil, nil, id, false, sb.privileged, podContainer.Dir, created) if err != nil { return nil, err } @@ -417,6 +421,8 @@ func (s *Server) RunPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest return nil, err } + s.containerStateToDisk(container) + resp = &pb.RunPodSandboxResponse{PodSandboxId: id} logrus.Debugf("RunPodSandboxResponse: %+v", resp) return resp, nil diff --git a/server/sandbox_status.go b/server/sandbox_status.go index 15d35260..65e51a84 100644 --- a/server/sandbox_status.go +++ b/server/sandbox_status.go @@ -16,12 +16,11 @@ func (s *Server) PodSandboxStatus(ctx context.Context, req *pb.PodSandboxStatusR } podInfraContainer := sb.infraContainer - if err = s.runtime.UpdateStatus(podInfraContainer); err != nil { - return nil, err - } + // best effort if container is still in runc store... + s.runtime.UpdateStatus(podInfraContainer) + s.containerStateToDisk(podInfraContainer) cState := s.runtime.ContainerStatus(podInfraContainer) - created := cState.Created.UnixNano() netNsPath, err := podInfraContainer.NetNsPath() if err != nil { @@ -34,6 +33,7 @@ func (s *Server) PodSandboxStatus(ctx context.Context, req *pb.PodSandboxStatusR } rStatus := pb.PodSandboxState_SANDBOX_NOTREADY + if cState.Status == oci.ContainerStateRunning { rStatus = pb.PodSandboxState_SANDBOX_READY } @@ -42,7 +42,7 @@ func (s *Server) PodSandboxStatus(ctx context.Context, req *pb.PodSandboxStatusR resp := &pb.PodSandboxStatusResponse{ Status: &pb.PodSandboxStatus{ Id: sandboxID, - CreatedAt: created, + CreatedAt: podInfraContainer.CreatedAt().UnixNano(), Linux: &pb.LinuxPodSandboxStatus{ Namespaces: &pb.Namespace{ Network: netNsPath, diff --git a/server/sandbox_stop.go b/server/sandbox_stop.go index a6f8d32b..3d7e168d 100644 --- a/server/sandbox_stop.go +++ b/server/sandbox_stop.go @@ -5,7 +5,6 @@ import ( "os" "github.com/Sirupsen/logrus" - "github.com/kubernetes-incubator/cri-o/oci" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime" ) @@ -46,12 +45,10 @@ func (s *Server) StopPodSandbox(ctx context.Context, req *pb.StopPodSandboxReque if err := s.runtime.UpdateStatus(c); err != nil { return nil, err } - cStatus := s.runtime.ContainerStatus(c) - if cStatus.Status != oci.ContainerStateStopped { - if err := s.runtime.StopContainer(c); err != nil { - return nil, fmt.Errorf("failed to stop container %s in pod sandbox %s: %v", c.Name(), sb.id, err) - } + if err := s.runtime.StopContainer(c); err != nil { + return nil, fmt.Errorf("failed to stop container %s in pod sandbox %s: %v", c.Name(), sb.id, err) } + s.containerStateToDisk(c) } resp := &pb.StopPodSandboxResponse{} diff --git a/server/server.go b/server/server.go index 2fe7e3ee..5e290464 100644 --- a/server/server.go +++ b/server/server.go @@ -7,10 +7,12 @@ import ( "os" "path/filepath" "sync" + "time" "github.com/Sirupsen/logrus" "github.com/containers/image/types" sstorage "github.com/containers/storage/storage" + "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/registrar" "github.com/docker/docker/pkg/truncindex" "github.com/kubernetes-incubator/cri-o/oci" @@ -120,6 +122,11 @@ func (s *Server) loadContainer(id string) error { return err } + containerDir, err := s.store.GetContainerDirectory(id) + if err != nil { + return err + } + var img *pb.ImageSpec image, ok := m.Annotations["ocid/image"] if ok { @@ -133,17 +140,47 @@ func (s *Server) loadContainer(id string) error { return err } - ctr, err := oci.NewContainer(id, name, containerPath, m.Annotations["ocid/log_path"], sb.netNs(), labels, annotations, img, &metadata, sb.id, tty, sb.privileged) + created, err := time.Parse(time.RFC3339Nano, m.Annotations["ocid/created"]) if err != nil { return err } - if err = s.runtime.UpdateStatus(ctr); err != nil { - return fmt.Errorf("error updating status for container %s: %v", ctr.ID(), err) + + ctr, err := oci.NewContainer(id, name, containerPath, m.Annotations["ocid/log_path"], sb.netNs(), labels, annotations, img, &metadata, sb.id, tty, sb.privileged, containerDir, created) + if err != nil { + return err } + + s.containerStateFromDisk(ctr) + s.addContainer(ctr) return s.ctrIDIndex.Add(id) } +func (s *Server) containerStateFromDisk(c *oci.Container) error { + if err := c.FromDisk(); err != nil { + return err + } + // ignore errors, this is a best effort to have up-to-date info about + // a given container before its state gets stored + s.runtime.UpdateStatus(c) + + return nil +} + +func (s *Server) containerStateToDisk(c *oci.Container) error { + // ignore errors, this is a best effort to have up-to-date info about + // a given container before its state gets stored + s.runtime.UpdateStatus(c) + + jsonSource, err := ioutils.NewAtomicFileWriter(c.StatePath(), 0644) + if err != nil { + return err + } + defer jsonSource.Close() + enc := json.NewEncoder(jsonSource) + return enc.Encode(s.runtime.ContainerStatus(c)) +} + func configNetNsPath(spec rspec.Spec) (string, error) { for _, ns := range spec.Linux.Namespaces { if ns.Type != rspec.NetworkNamespace { @@ -244,6 +281,11 @@ func (s *Server) loadSandbox(id string) error { return err } + sandboxDir, err := s.store.GetContainerDirectory(id) + if err != nil { + return err + } + cname, err := s.reserveContainerName(m.Annotations["ocid/container_id"], m.Annotations["ocid/container_name"]) if err != nil { return err @@ -254,13 +296,18 @@ func (s *Server) loadSandbox(id string) error { } }() - scontainer, err := oci.NewContainer(m.Annotations["ocid/container_id"], cname, sandboxPath, m.Annotations["ocid/log_path"], sb.netNs(), labels, annotations, nil, nil, id, false, privileged) + created, err := time.Parse(time.RFC3339Nano, m.Annotations["ocid/created"]) if err != nil { return err } - if err = s.runtime.UpdateStatus(scontainer); err != nil { - return fmt.Errorf("error updating status for pod sandbox infra container %s: %v", scontainer.ID(), err) + + scontainer, err := oci.NewContainer(m.Annotations["ocid/container_id"], cname, sandboxPath, m.Annotations["ocid/log_path"], sb.netNs(), labels, annotations, nil, nil, id, false, privileged, sandboxDir, created) + if err != nil { + return err } + + s.containerStateFromDisk(scontainer) + if err = label.ReserveLabel(processLabel); err != nil { return err } diff --git a/test/ctr.bats b/test/ctr.bats index 2c936add..375fc8bf 100644 --- a/test/ctr.bats +++ b/test/ctr.bats @@ -429,6 +429,31 @@ function teardown() { stop_ocid } +@test "ctr device add" { + start_ocid + run ocic pod run --config "$TESTDATA"/sandbox_config.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run ocic ctr create --config "$TESTDATA"/container_redis_device.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run ocic ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + run ocic ctr execsync --id "$ctr_id" ls /dev/mynull + echo "$output" + [ "$status" -eq 0 ] + [[ "$output" =~ "/dev/mynull" ]] + run ocic pod remove --id "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + cleanup_ctrs + cleanup_pods + stop_ocid +} + @test "ctr execsync failure" { start_ocid run ocic pod run --config "$TESTDATA"/sandbox_config.json diff --git a/test/helpers.bash b/test/helpers.bash index 465fa53a..4a244c16 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -68,7 +68,7 @@ PATH=$PATH:$TESTDIR # Make sure we have a copy of the redis:latest image. if ! [ -d "$ARTIFACTS_PATH"/redis-image ]; then mkdir -p "$ARTIFACTS_PATH"/redis-image - if ! "$COPYIMG_BINARY" --import-from=docker://redis --export-to=dir:"$ARTIFACTS_PATH"/redis-image --signature-policy="$INTEGRATION_ROOT"/policy.json ; then + if ! "$COPYIMG_BINARY" --import-from=docker://redis:alpine --export-to=dir:"$ARTIFACTS_PATH"/redis-image --signature-policy="$INTEGRATION_ROOT"/policy.json ; then echo "Error pulling docker://redis" rm -fr "$ARTIFACTS_PATH"/redis-image exit 1 @@ -145,7 +145,7 @@ function start_ocid() { if ! [ "$3" = "--no-pause-image" ] ; then "$BIN2IMG_BINARY" --root "$TESTDIR/ocid" $STORAGE_OPTS --runroot "$TESTDIR/ocid-run" --source-binary "$PAUSE_BINARY" fi - "$COPYIMG_BINARY" --root "$TESTDIR/ocid" $STORAGE_OPTS --runroot "$TESTDIR/ocid-run" --image-name=redis --import-from=dir:"$ARTIFACTS_PATH"/redis-image --add-name=docker://docker.io/library/redis:latest --signature-policy="$INTEGRATION_ROOT"/policy.json + "$COPYIMG_BINARY" --root "$TESTDIR/ocid" $STORAGE_OPTS --runroot "$TESTDIR/ocid-run" --image-name=redis:alpine --import-from=dir:"$ARTIFACTS_PATH"/redis-image --add-name=docker://docker.io/library/redis:alpine --signature-policy="$INTEGRATION_ROOT"/policy.json "$OCID_BINARY" --conmon "$CONMON_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNTIME_BINARY" --root "$TESTDIR/ocid" --runroot "$TESTDIR/ocid-run" $STORAGE_OPTS --seccomp-profile "$seccomp" --apparmor-profile "$apparmor" --cni-config-dir "$OCID_CNI_CONFIG" --signature-policy "$INTEGRATION_ROOT"/policy.json --config /dev/null config >$OCID_CONFIG # Prepare the CNI configuration files, we're running with non host networking by default @@ -159,11 +159,11 @@ function start_ocid() { "$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$! wait_until_reachable - run ocic image status --id=redis + run ocic image status --id=redis:alpine if [ "$status" -ne 0 ] ; then - ocic image pull redis:latest + ocic image pull redis:alpine fi - REDIS_IMAGEID=$(ocic image status --id=redis | head -1 | sed -e "s/ID: //g") + REDIS_IMAGEID=$(ocic image status --id=redis:alpine | head -1 | sed -e "s/ID: //g") run ocic image status --id=busybox if [ "$status" -ne 0 ] ; then ocic image pull busybox:latest diff --git a/test/testdata/container_config.json b/test/testdata/container_config.json index 6f466981..fecc72eb 100644 --- a/test/testdata/container_config.json +++ b/test/testdata/container_config.json @@ -4,7 +4,7 @@ "attempt": 1 }, "image": { - "image": "docker://redis:latest" + "image": "redis:alpine" }, "command": [ "/bin/ls" diff --git a/test/testdata/container_config_by_imageid.json b/test/testdata/container_config_by_imageid.json index 83882d24..7bed4b4f 100644 --- a/test/testdata/container_config_by_imageid.json +++ b/test/testdata/container_config_by_imageid.json @@ -7,11 +7,9 @@ "image": "%VALUE%" }, "command": [ - "/bin/bash" - ], - "args": [ "/bin/ls" ], + "args": [], "working_dir": "/", "envs": [ { diff --git a/test/testdata/container_config_seccomp.json b/test/testdata/container_config_seccomp.json index e63e931c..e62be3c1 100644 --- a/test/testdata/container_config_seccomp.json +++ b/test/testdata/container_config_seccomp.json @@ -4,7 +4,7 @@ "attempt": 1 }, "image": { - "image": "docker://redis:latest" + "image": "redis:alpine" }, "command": [ "/bin/bash" diff --git a/test/testdata/container_redis.json b/test/testdata/container_redis.json index cbc9922c..7c63a3c3 100644 --- a/test/testdata/container_redis.json +++ b/test/testdata/container_redis.json @@ -3,7 +3,7 @@ "name": "podsandbox1-redis" }, "image": { - "image": "docker://redis:latest" + "image": "redis:alpine" }, "args": [ "docker-entrypoint.sh", diff --git a/test/testdata/container_redis_device.json b/test/testdata/container_redis_device.json new file mode 100644 index 00000000..abeaadee --- /dev/null +++ b/test/testdata/container_redis_device.json @@ -0,0 +1,69 @@ +{ + "metadata": { + "name": "podsandbox1-redis" + }, + "image": { + "image": "redis:alpine" + }, + "args": [ + "docker-entrypoint.sh", + "redis-server" + ], + "working_dir": "/data", + "envs": [ + { + "key": "PATH", + "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + }, + { + "key": "TERM", + "value": "xterm" + }, + { + "key": "REDIS_VERSION", + "value": "3.2.3" + }, + { + "key": "REDIS_DOWNLOAD_URL", + "value": "http://download.redis.io/releases/redis-3.2.3.tar.gz" + }, + { + "key": "REDIS_DOWNLOAD_SHA1", + "value": "92d6d93ef2efc91e595c8bf578bf72baff397507" + } + ], + "devices": [ + { + "host_path": "/dev/null", + "container_path": "/dev/mynull", + "permissions": "rwm" + } + ], + "labels": { + "tier": "backend" + }, + "annotations": { + "pod": "podsandbox1" + }, + "readonly_rootfs": false, + "log_path": "", + "stdin": false, + "stdin_once": false, + "tty": false, + "linux": { + "resources": { + "cpu_period": 10000, + "cpu_quota": 20000, + "cpu_shares": 512, + "memory_limit_in_bytes": 88000000, + "oom_score_adj": 30 + }, + "security_context": { + "capabilities": { + "add_capabilities": [ + "sys_admin" + ] + } + } + } +} diff --git a/tutorial.md b/tutorial.md index 584e084f..74011534 100644 --- a/tutorial.md +++ b/tutorial.md @@ -129,15 +129,15 @@ sudo make install Output: ``` -install -D -m 755 kpod /usr/bin/kpod -install -D -m 755 ocid /usr/bin/ocid -install -D -m 755 ocic /usr/bin/ocic +install -D -m 755 kpod /usr/local/bin/kpod +install -D -m 755 ocid /usr/local/bin/ocid +install -D -m 755 ocic /usr/local/bin/ocic install -D -m 755 conmon/conmon /usr/local/libexec/ocid/conmon -install -D -m 755 pause/pause /usr/libexec/ocid/pause -install -d -m 755 /usr/share/man/man{1,5,8} -install -m 644 docs/kpod.1 docs/kpod-launch.1 -t /usr/share/man/man1 -install -m 644 docs/ocid.conf.5 -t /usr/share/man/man5 -install -m 644 docs/ocid.8 -t /usr/share/man/man8 +install -D -m 755 pause/pause /usr/local/libexec/ocid/pause +install -d -m 755 /usr/local/share/man/man{1,5,8} +install -m 644 docs/kpod.1 docs/kpod-launch.1 -t /usr/local/share/man/man1 +install -m 644 docs/ocid.conf.5 -t /usr/local/share/man/man5 +install -m 644 docs/ocid.8 -t /usr/local/share/man/man8 install -D -m 644 ocid.conf /etc/ocid/ocid.conf install -D -m 644 seccomp.json /etc/ocid/seccomp.json ``` @@ -163,7 +163,7 @@ Description=OCI-based implementation of Kubernetes Container Runtime Interface Documentation=https://github.com/kubernetes-incubator/cri-o [Service] -ExecStart=/usr/bin/ocid --debug +ExecStart=/usr/local/bin/ocid --debug Restart=on-failure RestartSec=5 diff --git a/utils/utils.go b/utils/utils.go index 340e1ba9..a46a7c24 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -23,7 +23,7 @@ func ExecCmd(name string, args ...string) (string, error) { err := cmd.Run() if err != nil { - return "", fmt.Errorf("`%v %v` failed: %v (%v)", name, strings.Join(args, " "), stderr.String(), err) + return "", fmt.Errorf("`%v %v` failed: %v (%v)", name, strings.Join(args, " "), stderr.String(), stdout.String(), err) } return stdout.String(), nil