Merge branch 'restore-2' into kube-1.6.1
* restore-2: (24 commits) server: ignore runc not exist errors server: *_status: do not fail on updating containers status server: restore containers state from disk on startup server: store containers state on disk server: do not guard runtime.StopContainer oci: ignore non existing containers on delete oci: do not stop containers not running oci: save container's finished time server: store creation in containers oci: add container directory to Container struct server: restore sandbox created time from disk server: return sandbox's own created time server: store sandbox creation time bats: Add a test for adding device to a container Add a test config for device Add devices to OCI config Add helper for adding devices to OCI spec server: store kubeName in annotations sandbox: pass correct pod Namespace/Name to network plugins and fix id/name ordering makefile: Look for go-md2man in system path first ...
This commit is contained in:
commit
0fe816c9fd
24 changed files with 288 additions and 74 deletions
6
Makefile
6
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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
15
oci/oci.go
15
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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,12 +21,9 @@ 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.DeleteContainer(c); err != nil {
|
||||
return nil, fmt.Errorf("failed to delete container %s: %v", c.ID(), err)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,12 +19,11 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
s.containerStateToDisk(c)
|
||||
|
||||
resp := &pb.StopContainerResponse{}
|
||||
logrus.Debugf("StopContainerResponse: %+v", resp)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to stop container %s: %v", c.Name(), err)
|
||||
}
|
||||
|
||||
if err := s.runtime.DeleteContainer(c); err != nil {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
s.containerStateToDisk(c)
|
||||
}
|
||||
|
||||
resp := &pb.StopPodSandboxResponse{}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
2
test/testdata/container_config.json
vendored
2
test/testdata/container_config.json
vendored
|
@ -4,7 +4,7 @@
|
|||
"attempt": 1
|
||||
},
|
||||
"image": {
|
||||
"image": "docker://redis:latest"
|
||||
"image": "redis:alpine"
|
||||
},
|
||||
"command": [
|
||||
"/bin/ls"
|
||||
|
|
|
@ -7,11 +7,9 @@
|
|||
"image": "%VALUE%"
|
||||
},
|
||||
"command": [
|
||||
"/bin/bash"
|
||||
],
|
||||
"args": [
|
||||
"/bin/ls"
|
||||
],
|
||||
"args": [],
|
||||
"working_dir": "/",
|
||||
"envs": [
|
||||
{
|
||||
|
|
2
test/testdata/container_config_seccomp.json
vendored
2
test/testdata/container_config_seccomp.json
vendored
|
@ -4,7 +4,7 @@
|
|||
"attempt": 1
|
||||
},
|
||||
"image": {
|
||||
"image": "docker://redis:latest"
|
||||
"image": "redis:alpine"
|
||||
},
|
||||
"command": [
|
||||
"/bin/bash"
|
||||
|
|
2
test/testdata/container_redis.json
vendored
2
test/testdata/container_redis.json
vendored
|
@ -3,7 +3,7 @@
|
|||
"name": "podsandbox1-redis"
|
||||
},
|
||||
"image": {
|
||||
"image": "docker://redis:latest"
|
||||
"image": "redis:alpine"
|
||||
},
|
||||
"args": [
|
||||
"docker-entrypoint.sh",
|
||||
|
|
69
test/testdata/container_redis_device.json
vendored
Normal file
69
test/testdata/container_redis_device.json
vendored
Normal file
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
tutorial.md
18
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue