diff options
Diffstat (limited to 'libkpod')
-rw-r--r-- | libkpod/config.go | 5 | ||||
-rw-r--r-- | libkpod/container.go | 157 | ||||
-rw-r--r-- | libkpod/container_server.go | 775 | ||||
-rw-r--r-- | libkpod/kill.go | 45 | ||||
-rw-r--r-- | libkpod/rename.go | 114 | ||||
-rw-r--r-- | libkpod/sandbox/sandbox.go | 484 | ||||
-rw-r--r-- | libkpod/stats.go | 111 | ||||
-rw-r--r-- | libkpod/stop.go | 36 | ||||
-rw-r--r-- | libkpod/wait.go | 42 |
9 files changed, 2 insertions, 1767 deletions
diff --git a/libkpod/config.go b/libkpod/config.go index 84d3ce897..b95ff18ca 100644 --- a/libkpod/config.go +++ b/libkpod/config.go @@ -6,7 +6,6 @@ import ( "github.com/BurntSushi/toml" "github.com/opencontainers/selinux/go-selinux" - "github.com/projectatomic/libpod/oci" ) // Default paths if none are specified @@ -21,9 +20,9 @@ const ( apparmorProfileName = "crio-default" cniConfigDir = "/etc/cni/net.d/" cniBinDir = "/opt/cni/bin/" - cgroupManager = oci.CgroupfsCgroupsManager + cgroupManager = "" //oci.CgroupfsCgroupsManager lockPath = "/run/crio.lock" - containerExitsDir = oci.ContainerExitsDir + containerExitsDir = "" //oci.ContainerExitsDir ) // Config represents the entire set of configuration values that can be set for diff --git a/libkpod/container.go b/libkpod/container.go deleted file mode 100644 index e0ff348d0..000000000 --- a/libkpod/container.go +++ /dev/null @@ -1,157 +0,0 @@ -package libkpod - -import ( - "fmt" - - cstorage "github.com/containers/storage" - "github.com/pkg/errors" - "github.com/projectatomic/libpod/libkpod/sandbox" - "github.com/projectatomic/libpod/oci" - "github.com/projectatomic/libpod/pkg/registrar" -) - -// GetStorageContainer searches for a container with the given name or ID in the given store -func (c *ContainerServer) GetStorageContainer(container string) (*cstorage.Container, error) { - ociCtr, err := c.LookupContainer(container) - if err != nil { - return nil, err - } - return c.store.Container(ociCtr.ID()) -} - -// GetContainerTopLayerID gets the ID of the top layer of the given container -func (c *ContainerServer) GetContainerTopLayerID(containerID string) (string, error) { - ctr, err := c.GetStorageContainer(containerID) - if err != nil { - return "", err - } - return ctr.LayerID, nil -} - -// GetContainerRwSize Gets the size of the mutable top layer of the container -func (c *ContainerServer) GetContainerRwSize(containerID string) (int64, error) { - container, err := c.store.Container(containerID) - if err != nil { - return 0, err - } - - // Get the size of the top layer by calculating the size of the diff - // between the layer and its parent. The top layer of a container is - // the only RW layer, all others are immutable - layer, err := c.store.Layer(container.LayerID) - if err != nil { - return 0, err - } - return c.store.DiffSize(layer.Parent, layer.ID) -} - -// GetContainerRootFsSize gets the size of the container's root filesystem -// A container FS is split into two parts. The first is the top layer, a -// mutable layer, and the rest is the RootFS: the set of immutable layers -// that make up the image on which the container is based -func (c *ContainerServer) GetContainerRootFsSize(containerID string) (int64, error) { - container, err := c.store.Container(containerID) - if err != nil { - return 0, err - } - - // Ignore the size of the top layer. The top layer is a mutable RW layer - // and is not considered a part of the rootfs - rwLayer, err := c.store.Layer(container.LayerID) - if err != nil { - return 0, err - } - layer, err := c.store.Layer(rwLayer.Parent) - if err != nil { - return 0, err - } - - size := int64(0) - for layer.Parent != "" { - layerSize, err := c.store.DiffSize(layer.Parent, layer.ID) - if err != nil { - return size, errors.Wrapf(err, "getting diffsize of layer %q and its parent %q", layer.ID, layer.Parent) - } - size += layerSize - layer, err = c.store.Layer(layer.Parent) - if err != nil { - return 0, err - } - } - // Get the size of the last layer. Has to be outside of the loop - // because the parent of the last layer is "", andlstore.Get("") - // will return an error - layerSize, err := c.store.DiffSize(layer.Parent, layer.ID) - return size + layerSize, err -} - -// GetContainerFromRequest gets an oci container matching the specified full or partial id -func (c *ContainerServer) GetContainerFromRequest(cid string) (*oci.Container, error) { - if cid == "" { - return nil, fmt.Errorf("container ID should not be empty") - } - - containerID, err := c.ctrIDIndex.Get(cid) - if err != nil { - return nil, fmt.Errorf("container with ID starting with %s not found: %v", cid, err) - } - - ctr := c.GetContainer(containerID) - if ctr == nil { - return nil, fmt.Errorf("specified container not found: %s", containerID) - } - return ctr, nil -} - -func (c *ContainerServer) getSandboxFromRequest(pid string) (*sandbox.Sandbox, error) { - if pid == "" { - return nil, fmt.Errorf("pod ID should not be empty") - } - - podID, err := c.podIDIndex.Get(pid) - if err != nil { - return nil, fmt.Errorf("pod with ID starting with %s not found: %v", pid, err) - } - - sb := c.GetSandbox(podID) - if sb == nil { - return nil, fmt.Errorf("specified pod not found: %s", podID) - } - return sb, nil -} - -// LookupContainer returns the container with the given name or full or partial id -func (c *ContainerServer) LookupContainer(idOrName string) (*oci.Container, error) { - if idOrName == "" { - return nil, fmt.Errorf("container ID or name should not be empty") - } - - ctrID, err := c.ctrNameIndex.Get(idOrName) - if err != nil { - if err == registrar.ErrNameNotReserved { - ctrID = idOrName - } else { - return nil, err - } - } - - return c.GetContainerFromRequest(ctrID) -} - -// LookupSandbox returns the pod sandbox with the given name or full or partial id -func (c *ContainerServer) LookupSandbox(idOrName string) (*sandbox.Sandbox, error) { - if idOrName == "" { - return nil, fmt.Errorf("container ID or name should not be empty") - } - - podID, err := c.podNameIndex.Get(idOrName) - if err != nil { - if err == registrar.ErrNameNotReserved { - podID = idOrName - } else { - return nil, err - } - } - - return c.getSandboxFromRequest(podID) -} diff --git a/libkpod/container_server.go b/libkpod/container_server.go deleted file mode 100644 index 8e0e09978..000000000 --- a/libkpod/container_server.go +++ /dev/null @@ -1,775 +0,0 @@ -package libkpod - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "sync" - "time" - - "github.com/containers/image/types" - cstorage "github.com/containers/storage" - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/truncindex" - "github.com/opencontainers/runc/libcontainer" - rspec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/selinux/go-selinux" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" - "github.com/projectatomic/libpod/libkpod/sandbox" - "github.com/projectatomic/libpod/oci" - "github.com/projectatomic/libpod/pkg/annotations" - "github.com/projectatomic/libpod/pkg/registrar" - "github.com/projectatomic/libpod/pkg/storage" - "github.com/sirupsen/logrus" - pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" -) - -// ContainerServer implements the ImageServer -type ContainerServer struct { - runtime *oci.Runtime - store cstorage.Store - storageImageServer storage.ImageServer - storageRuntimeServer storage.RuntimeServer - updateLock sync.RWMutex - ctrNameIndex *registrar.Registrar - ctrIDIndex *truncindex.TruncIndex - podNameIndex *registrar.Registrar - podIDIndex *truncindex.TruncIndex - hooks map[string]HookParams - - imageContext *types.SystemContext - stateLock sync.Locker - state *containerServerState - config *Config -} - -// Runtime returns the oci runtime for the ContainerServer -func (c *ContainerServer) Runtime() *oci.Runtime { - return c.runtime -} - -// Hooks returns the oci hooks for the ContainerServer -func (c *ContainerServer) Hooks() map[string]HookParams { - return c.hooks -} - -// Store returns the Store for the ContainerServer -func (c *ContainerServer) Store() cstorage.Store { - return c.store -} - -// StorageImageServer returns the ImageServer for the ContainerServer -func (c *ContainerServer) StorageImageServer() storage.ImageServer { - return c.storageImageServer -} - -// CtrNameIndex returns the Registrar for the ContainerServer -func (c *ContainerServer) CtrNameIndex() *registrar.Registrar { - return c.ctrNameIndex -} - -// CtrIDIndex returns the TruncIndex for the ContainerServer -func (c *ContainerServer) CtrIDIndex() *truncindex.TruncIndex { - return c.ctrIDIndex -} - -// PodNameIndex returns the index of pod names -func (c *ContainerServer) PodNameIndex() *registrar.Registrar { - return c.podNameIndex -} - -// PodIDIndex returns the index of pod IDs -func (c *ContainerServer) PodIDIndex() *truncindex.TruncIndex { - return c.podIDIndex -} - -// ImageContext returns the SystemContext for the ContainerServer -func (c *ContainerServer) ImageContext() *types.SystemContext { - return c.imageContext -} - -// Config gets the configuration for the ContainerServer -func (c *ContainerServer) Config() *Config { - return c.config -} - -// StorageRuntimeServer gets the runtime server for the ContainerServer -func (c *ContainerServer) StorageRuntimeServer() storage.RuntimeServer { - return c.storageRuntimeServer -} - -// New creates a new ContainerServer with options provided -func New(config *Config) (*ContainerServer, error) { - store, err := cstorage.GetStore(cstorage.StoreOptions{ - RunRoot: config.RunRoot, - GraphRoot: config.Root, - GraphDriverName: config.Storage, - GraphDriverOptions: config.StorageOptions, - }) - if err != nil { - return nil, err - } - - imageService, err := storage.GetImageService(store, config.DefaultTransport, config.InsecureRegistries, config.Registries) - if err != nil { - return nil, err - } - - storageRuntimeService := storage.GetRuntimeService(imageService, config.PauseImage) - if err != nil { - return nil, err - } - - runtime, err := oci.New(config.Runtime, config.RuntimeUntrustedWorkload, config.DefaultWorkloadTrust, config.Conmon, config.ConmonEnv, config.CgroupManager, config.ContainerExitsDir, config.LogSizeMax, config.NoPivot) - if err != nil { - return nil, err - } - - var lock sync.Locker - if config.FileLocking { - fileLock, err := cstorage.GetLockfile(lockPath) - if err != nil { - return nil, fmt.Errorf("error obtaining lockfile: %v", err) - } - lock = fileLock - } else { - lock = new(sync.Mutex) - } - - hooks := make(map[string]HookParams) - // If hooks directory is set in config use it - if config.HooksDirPath != "" { - if err := readHooks(config.HooksDirPath, hooks); err != nil { - return nil, err - } - // If user overrode default hooks, this means it is in a test, so don't - // use OverrideHooksDirPath - if config.HooksDirPath == DefaultHooksDirPath { - if err := readHooks(OverrideHooksDirPath, hooks); err != nil { - return nil, err - } - } - } - - return &ContainerServer{ - runtime: runtime, - store: store, - storageImageServer: imageService, - storageRuntimeServer: storageRuntimeService, - ctrNameIndex: registrar.NewRegistrar(), - ctrIDIndex: truncindex.NewTruncIndex([]string{}), - podNameIndex: registrar.NewRegistrar(), - podIDIndex: truncindex.NewTruncIndex([]string{}), - imageContext: &types.SystemContext{SignaturePolicyPath: config.SignaturePolicyPath}, - hooks: hooks, - stateLock: lock, - state: &containerServerState{ - containers: oci.NewMemoryStore(), - infraContainers: oci.NewMemoryStore(), - sandboxes: make(map[string]*sandbox.Sandbox), - processLevels: make(map[string]int), - }, - config: config, - }, nil -} - -// Update makes changes to the server's state (lists of pods and containers) to -// reflect the list of pods and containers that are stored on disk, possibly -// having been modified by other parties -func (c *ContainerServer) Update() error { - c.updateLock.Lock() - defer c.updateLock.Unlock() - - containers, err := c.store.Containers() - if err != nil && !os.IsNotExist(errors.Cause(err)) { - logrus.Warnf("could not read containers and sandboxes: %v", err) - return err - } - newPods := map[string]*storage.RuntimeContainerMetadata{} - oldPods := map[string]string{} - removedPods := map[string]string{} - newPodContainers := map[string]*storage.RuntimeContainerMetadata{} - oldPodContainers := map[string]string{} - removedPodContainers := map[string]string{} - for _, container := range containers { - if c.HasSandbox(container.ID) { - // FIXME: do we need to reload/update any info about the sandbox? - oldPods[container.ID] = container.ID - oldPodContainers[container.ID] = container.ID - continue - } - if c.GetContainer(container.ID) != nil { - // FIXME: do we need to reload/update any info about the container? - oldPodContainers[container.ID] = container.ID - continue - } - // not previously known, so figure out what it is - metadata, err2 := c.storageRuntimeServer.GetContainerMetadata(container.ID) - if err2 != nil { - logrus.Errorf("error parsing metadata for %s: %v, ignoring", container.ID, err2) - continue - } - if metadata.Pod { - newPods[container.ID] = &metadata - } else { - newPodContainers[container.ID] = &metadata - } - } - c.ctrIDIndex.Iterate(func(id string) { - if _, ok := oldPodContainers[id]; !ok { - // this container's ID wasn't in the updated list -> removed - removedPodContainers[id] = id - } else { - ctr := c.GetContainer(id) - if ctr != nil { - // if the container exists, update its state - c.ContainerStateFromDisk(c.GetContainer(id)) - } - } - }) - for removedPodContainer := range removedPodContainers { - // forget this container - ctr := c.GetContainer(removedPodContainer) - if ctr == nil { - logrus.Warnf("bad state when getting container removed %+v", removedPodContainer) - continue - } - c.ReleaseContainerName(ctr.Name()) - c.RemoveContainer(ctr) - if err = c.ctrIDIndex.Delete(ctr.ID()); err != nil { - return err - } - logrus.Debugf("forgetting removed pod container %s", ctr.ID()) - } - c.PodIDIndex().Iterate(func(id string) { - if _, ok := oldPods[id]; !ok { - // this pod's ID wasn't in the updated list -> removed - removedPods[id] = id - } - }) - for removedPod := range removedPods { - // forget this pod - sb := c.GetSandbox(removedPod) - if sb == nil { - logrus.Warnf("bad state when getting pod to remove %+v", removedPod) - continue - } - podInfraContainer := sb.InfraContainer() - c.ReleaseContainerName(podInfraContainer.Name()) - c.RemoveContainer(podInfraContainer) - if err = c.ctrIDIndex.Delete(podInfraContainer.ID()); err != nil { - return err - } - sb.RemoveInfraContainer() - c.ReleasePodName(sb.Name()) - c.RemoveSandbox(sb.ID()) - if err = c.podIDIndex.Delete(sb.ID()); err != nil { - return err - } - logrus.Debugf("forgetting removed pod %s", sb.ID()) - } - for sandboxID := range newPods { - // load this pod - if err = c.LoadSandbox(sandboxID); err != nil { - logrus.Warnf("could not load new pod sandbox %s: %v, ignoring", sandboxID, err) - } else { - logrus.Debugf("loaded new pod sandbox %s", sandboxID, err) - } - } - for containerID := range newPodContainers { - // load this container - if err = c.LoadContainer(containerID); err != nil { - logrus.Warnf("could not load new sandbox container %s: %v, ignoring", containerID, err) - } else { - logrus.Debugf("loaded new pod container %s", containerID, err) - } - } - return nil -} - -// LoadSandbox loads a sandbox from the disk into the sandbox store -func (c *ContainerServer) LoadSandbox(id string) error { - config, err := c.store.FromContainerDirectory(id, "config.json") - if err != nil { - return err - } - var m rspec.Spec - if err = json.Unmarshal(config, &m); err != nil { - return err - } - labels := make(map[string]string) - if err = json.Unmarshal([]byte(m.Annotations[annotations.Labels]), &labels); err != nil { - return err - } - name := m.Annotations[annotations.Name] - name, err = c.ReservePodName(id, name) - if err != nil { - return err - } - defer func() { - if err != nil { - c.ReleasePodName(name) - } - }() - var metadata pb.PodSandboxMetadata - if err = json.Unmarshal([]byte(m.Annotations[annotations.Metadata]), &metadata); err != nil { - return err - } - - ip := m.Annotations[annotations.IP] - - processLabel, mountLabel, err := label.InitLabels(label.DupSecOpt(m.Process.SelinuxLabel)) - if err != nil { - return err - } - - kubeAnnotations := make(map[string]string) - if err = json.Unmarshal([]byte(m.Annotations[annotations.Annotations]), &kubeAnnotations); err != nil { - return err - } - - privileged := isTrue(m.Annotations[annotations.PrivilegedRuntime]) - trusted := isTrue(m.Annotations[annotations.TrustedSandbox]) - - sb, err := sandbox.New(id, name, m.Annotations[annotations.KubeName], filepath.Dir(m.Annotations[annotations.LogPath]), "", labels, kubeAnnotations, processLabel, mountLabel, &metadata, m.Annotations[annotations.ShmPath], "", privileged, trusted, m.Annotations[annotations.ResolvPath], "", nil) - if err != nil { - return err - } - sb.AddHostnamePath(m.Annotations[annotations.HostnamePath]) - sb.AddIP(ip) - - // We add a netNS only if we can load a permanent one. - // Otherwise, the sandbox will live in the host namespace. - netNsPath, err := configNetNsPath(m) - if err == nil { - nsErr := sb.NetNsJoin(netNsPath, sb.Name()) - // If we can't load the networking namespace - // because it's closed, we just set the sb netns - // pointer to nil. Otherwise we return an error. - if nsErr != nil && nsErr != sandbox.ErrClosedNetNS { - return nsErr - } - } - - c.AddSandbox(sb) - - defer func() { - if err != nil { - c.RemoveSandbox(sb.ID()) - } - }() - - sandboxPath, err := c.store.ContainerRunDirectory(id) - if err != nil { - return err - } - - sandboxDir, err := c.store.ContainerDirectory(id) - if err != nil { - return err - } - - cname, err := c.ReserveContainerName(m.Annotations[annotations.ContainerID], m.Annotations[annotations.ContainerName]) - if err != nil { - return err - } - defer func() { - if err != nil { - c.ReleaseContainerName(cname) - } - }() - - created, err := time.Parse(time.RFC3339Nano, m.Annotations[annotations.Created]) - if err != nil { - return err - } - - scontainer, err := oci.NewContainer(m.Annotations[annotations.ContainerID], cname, sandboxPath, m.Annotations[annotations.LogPath], sb.NetNs(), labels, m.Annotations, kubeAnnotations, "", "", "", nil, id, false, false, false, privileged, trusted, sandboxDir, created, m.Annotations["org.opencontainers.image.stopSignal"]) - if err != nil { - return err - } - scontainer.SetSpec(&m) - scontainer.SetMountPoint(m.Annotations[annotations.MountPoint]) - - if m.Annotations[annotations.Volumes] != "" { - containerVolumes := []oci.ContainerVolume{} - if err = json.Unmarshal([]byte(m.Annotations[annotations.Volumes]), &containerVolumes); err != nil { - return fmt.Errorf("failed to unmarshal container volumes: %v", err) - } - if containerVolumes != nil { - for _, cv := range containerVolumes { - scontainer.AddVolume(cv) - } - } - } - - c.ContainerStateFromDisk(scontainer) - - if err = label.ReserveLabel(processLabel); err != nil { - return err - } - sb.SetInfraContainer(scontainer) - if err = c.ctrIDIndex.Add(scontainer.ID()); err != nil { - return err - } - if err = c.podIDIndex.Add(id); err != nil { - return err - } - return nil -} - -func configNetNsPath(spec rspec.Spec) (string, error) { - for _, ns := range spec.Linux.Namespaces { - if ns.Type != rspec.NetworkNamespace { - continue - } - - if ns.Path == "" { - return "", fmt.Errorf("empty networking namespace") - } - - return ns.Path, nil - } - - return "", fmt.Errorf("missing networking namespace") -} - -// LoadContainer loads a container from the disk into the container store -func (c *ContainerServer) LoadContainer(id string) error { - config, err := c.store.FromContainerDirectory(id, "config.json") - if err != nil { - return err - } - var m rspec.Spec - if err = json.Unmarshal(config, &m); err != nil { - return err - } - labels := make(map[string]string) - if err = json.Unmarshal([]byte(m.Annotations[annotations.Labels]), &labels); err != nil { - return err - } - name := m.Annotations[annotations.Name] - name, err = c.ReserveContainerName(id, name) - if err != nil { - return err - } - - defer func() { - if err != nil { - c.ReleaseContainerName(name) - } - }() - - var metadata pb.ContainerMetadata - if err = json.Unmarshal([]byte(m.Annotations[annotations.Metadata]), &metadata); err != nil { - return err - } - sb := c.GetSandbox(m.Annotations[annotations.SandboxID]) - if sb == nil { - return fmt.Errorf("could not get sandbox with id %s, skipping", m.Annotations[annotations.SandboxID]) - } - - tty := isTrue(m.Annotations[annotations.TTY]) - stdin := isTrue(m.Annotations[annotations.Stdin]) - stdinOnce := isTrue(m.Annotations[annotations.StdinOnce]) - - containerPath, err := c.store.ContainerRunDirectory(id) - if err != nil { - return err - } - - containerDir, err := c.store.ContainerDirectory(id) - if err != nil { - return err - } - - img, ok := m.Annotations[annotations.Image] - if !ok { - img = "" - } - - imgName, ok := m.Annotations[annotations.ImageName] - if !ok { - imgName = "" - } - - imgRef, ok := m.Annotations[annotations.ImageRef] - if !ok { - imgRef = "" - } - - kubeAnnotations := make(map[string]string) - if err = json.Unmarshal([]byte(m.Annotations[annotations.Annotations]), &kubeAnnotations); err != nil { - return err - } - - created, err := time.Parse(time.RFC3339Nano, m.Annotations[annotations.Created]) - if err != nil { - return err - } - - ctr, err := oci.NewContainer(id, name, containerPath, m.Annotations[annotations.LogPath], sb.NetNs(), labels, m.Annotations, kubeAnnotations, img, imgName, imgRef, &metadata, sb.ID(), tty, stdin, stdinOnce, sb.Privileged(), sb.Trusted(), containerDir, created, m.Annotations["org.opencontainers.image.stopSignal"]) - if err != nil { - return err - } - ctr.SetSpec(&m) - ctr.SetMountPoint(m.Annotations[annotations.MountPoint]) - - c.ContainerStateFromDisk(ctr) - - c.AddContainer(ctr) - return c.ctrIDIndex.Add(id) -} - -func isTrue(annotaton string) bool { - return annotaton == "true" -} - -// ContainerStateFromDisk retrieves information on the state of a running container -// from the disk -func (c *ContainerServer) ContainerStateFromDisk(ctr *oci.Container) error { - if err := ctr.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 - c.runtime.UpdateStatus(ctr) - - return nil -} - -// ContainerStateToDisk writes the container's state information to a JSON file -// on disk -func (c *ContainerServer) ContainerStateToDisk(ctr *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 - c.Runtime().UpdateStatus(ctr) - - jsonSource, err := ioutils.NewAtomicFileWriter(ctr.StatePath(), 0644) - if err != nil { - return err - } - defer jsonSource.Close() - enc := json.NewEncoder(jsonSource) - return enc.Encode(c.runtime.ContainerStatus(ctr)) -} - -// ReserveContainerName holds a name for a container that is being created -func (c *ContainerServer) ReserveContainerName(id, name string) (string, error) { - if err := c.ctrNameIndex.Reserve(name, id); err != nil { - if err == registrar.ErrNameReserved { - id, err := c.ctrNameIndex.Get(name) - if err != nil { - logrus.Warnf("conflict, ctr name %q already reserved", name) - return "", err - } - return "", fmt.Errorf("conflict, name %q already reserved for ctr %q", name, id) - } - return "", fmt.Errorf("error reserving ctr name %s", name) - } - return name, nil -} - -// ReleaseContainerName releases a container name from the index so that it can -// be used by other containers -func (c *ContainerServer) ReleaseContainerName(name string) { - c.ctrNameIndex.Release(name) -} - -// ReservePodName holds a name for a pod that is being created -func (c *ContainerServer) ReservePodName(id, name string) (string, error) { - if err := c.podNameIndex.Reserve(name, id); err != nil { - if err == registrar.ErrNameReserved { - id, err := c.podNameIndex.Get(name) - if err != nil { - logrus.Warnf("conflict, pod name %q already reserved", name) - return "", err - } - return "", fmt.Errorf("conflict, name %q already reserved for pod %q", name, id) - } - return "", fmt.Errorf("error reserving pod name %q", name) - } - return name, nil -} - -// ReleasePodName releases a pod name from the index so it can be used by other -// pods -func (c *ContainerServer) ReleasePodName(name string) { - c.podNameIndex.Release(name) -} - -// Shutdown attempts to shut down the server's storage cleanly -func (c *ContainerServer) Shutdown() error { - _, err := c.store.Shutdown(false) - if err != nil && errors.Cause(err) != cstorage.ErrLayerUsedByContainer { - return err - } - return nil -} - -type containerServerState struct { - containers oci.ContainerStorer - infraContainers oci.ContainerStorer - sandboxes map[string]*sandbox.Sandbox - // processLevels The number of sandboxes using the same SELinux MCS level. Need to release MCS Level, when count reaches 0 - processLevels map[string]int -} - -// AddContainer adds a container to the container state store -func (c *ContainerServer) AddContainer(ctr *oci.Container) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - sandbox := c.state.sandboxes[ctr.Sandbox()] - sandbox.AddContainer(ctr) - c.state.containers.Add(ctr.ID(), ctr) -} - -// AddInfraContainer adds a container to the container state store -func (c *ContainerServer) AddInfraContainer(ctr *oci.Container) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - c.state.infraContainers.Add(ctr.ID(), ctr) -} - -// GetContainer returns a container by its ID -func (c *ContainerServer) GetContainer(id string) *oci.Container { - c.stateLock.Lock() - defer c.stateLock.Unlock() - return c.state.containers.Get(id) -} - -// GetInfraContainer returns a container by its ID -func (c *ContainerServer) GetInfraContainer(id string) *oci.Container { - c.stateLock.Lock() - defer c.stateLock.Unlock() - return c.state.infraContainers.Get(id) -} - -// HasContainer checks if a container exists in the state -func (c *ContainerServer) HasContainer(id string) bool { - c.stateLock.Lock() - defer c.stateLock.Unlock() - ctr := c.state.containers.Get(id) - return ctr != nil -} - -// RemoveContainer removes a container from the container state store -func (c *ContainerServer) RemoveContainer(ctr *oci.Container) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - sbID := ctr.Sandbox() - sb := c.state.sandboxes[sbID] - sb.RemoveContainer(ctr) - c.state.containers.Delete(ctr.ID()) -} - -// RemoveInfraContainer removes a container from the container state store -func (c *ContainerServer) RemoveInfraContainer(ctr *oci.Container) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - c.state.infraContainers.Delete(ctr.ID()) -} - -// listContainers returns a list of all containers stored by the server state -func (c *ContainerServer) listContainers() []*oci.Container { - c.stateLock.Lock() - defer c.stateLock.Unlock() - return c.state.containers.List() -} - -// ListContainers returns a list of all containers stored by the server state -// that match the given filter function -func (c *ContainerServer) ListContainers(filters ...func(*oci.Container) bool) ([]*oci.Container, error) { - containers := c.listContainers() - if len(filters) == 0 { - return containers, nil - } - filteredContainers := make([]*oci.Container, 0, len(containers)) - for _, container := range containers { - for _, filter := range filters { - if filter(container) { - filteredContainers = append(filteredContainers, container) - } - } - } - return filteredContainers, nil -} - -// AddSandbox adds a sandbox to the sandbox state store -func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - c.state.sandboxes[sb.ID()] = sb - c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++ -} - -// GetSandbox returns a sandbox by its ID -func (c *ContainerServer) GetSandbox(id string) *sandbox.Sandbox { - c.stateLock.Lock() - defer c.stateLock.Unlock() - return c.state.sandboxes[id] -} - -// GetSandboxContainer returns a sandbox's infra container -func (c *ContainerServer) GetSandboxContainer(id string) *oci.Container { - c.stateLock.Lock() - defer c.stateLock.Unlock() - sb, ok := c.state.sandboxes[id] - if !ok { - return nil - } - return sb.InfraContainer() -} - -// HasSandbox checks if a sandbox exists in the state -func (c *ContainerServer) HasSandbox(id string) bool { - c.stateLock.Lock() - defer c.stateLock.Unlock() - _, ok := c.state.sandboxes[id] - return ok -} - -// RemoveSandbox removes a sandbox from the state store -func (c *ContainerServer) RemoveSandbox(id string) { - c.stateLock.Lock() - defer c.stateLock.Unlock() - processLabel := c.state.sandboxes[id].ProcessLabel() - delete(c.state.sandboxes, id) - level := selinux.NewContext(processLabel)["level"] - c.state.processLevels[level]-- - if c.state.processLevels[level] == 0 { - label.ReleaseLabel(processLabel) - delete(c.state.processLevels, level) - } -} - -// ListSandboxes lists all sandboxes in the state store -func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox { - c.stateLock.Lock() - defer c.stateLock.Unlock() - sbArray := make([]*sandbox.Sandbox, 0, len(c.state.sandboxes)) - for _, sb := range c.state.sandboxes { - sbArray = append(sbArray, sb) - } - - return sbArray -} - -// LibcontainerStats gets the stats for the container with the given id from runc/libcontainer -func (c *ContainerServer) LibcontainerStats(ctr *oci.Container) (*libcontainer.Stats, error) { - // TODO: make this not hardcoded - // was: c.runtime.Path(ociContainer) but that returns /usr/bin/runc - how do we get /run/runc? - // runroot is /var/run/runc - // Hardcoding probably breaks ClearContainers compatibility - factory, err := loadFactory("/run/runc") - if err != nil { - return nil, err - } - container, err := factory.Load(ctr.ID()) - if err != nil { - return nil, err - } - return container.Stats() -} diff --git a/libkpod/kill.go b/libkpod/kill.go deleted file mode 100644 index 74c525818..000000000 --- a/libkpod/kill.go +++ /dev/null @@ -1,45 +0,0 @@ -package libkpod - -import ( - "github.com/docker/docker/pkg/signal" - "github.com/pkg/errors" - "github.com/projectatomic/libpod/oci" - "github.com/projectatomic/libpod/utils" - "os" - "syscall" -) - -// Reverse lookup signal string from its map -func findStringInSignalMap(killSignal syscall.Signal) (string, error) { - for k, v := range signal.SignalMap { - if v == killSignal { - return k, nil - } - } - return "", errors.Errorf("unable to convert signal to string") - -} - -// ContainerKill sends the user provided signal to the containers primary process. -func (c *ContainerServer) ContainerKill(container string, killSignal syscall.Signal) (string, error) { // nolint - ctr, err := c.LookupContainer(container) - if err != nil { - return "", errors.Wrapf(err, "failed to find container %s", container) - } - c.runtime.UpdateStatus(ctr) - cStatus := c.runtime.ContainerStatus(ctr) - - // If the container is not running, error and move on. - if cStatus.Status != oci.ContainerStateRunning { - return "", errors.Errorf("cannot kill container %s: it is not running", container) - } - signalString, err := findStringInSignalMap(killSignal) - if err != nil { - return "", err - } - if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, c.runtime.Path(ctr), "kill", ctr.ID(), signalString); err != nil { - return "", err - } - c.ContainerStateToDisk(ctr) - return ctr.ID(), nil -} diff --git a/libkpod/rename.go b/libkpod/rename.go deleted file mode 100644 index cdb2bfc04..000000000 --- a/libkpod/rename.go +++ /dev/null @@ -1,114 +0,0 @@ -package libkpod - -import ( - "encoding/json" - "path/filepath" - - "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" - - "github.com/docker/docker/pkg/ioutils" - "github.com/opencontainers/runtime-tools/generate" - "github.com/projectatomic/libpod/oci" - "github.com/projectatomic/libpod/pkg/annotations" -) - -const configFile = "config.json" - -// ContainerRename renames the given container -func (c *ContainerServer) ContainerRename(container, name string) error { - ctr, err := c.LookupContainer(container) - if err != nil { - return err - } - - oldName := ctr.Name() - _, err = c.ReserveContainerName(ctr.ID(), name) - if err != nil { - return err - } - defer func() { - if err != nil { - c.ReleaseContainerName(name) - } else { - c.ReleaseContainerName(oldName) - } - }() - - // Update state.json - if err = c.updateStateName(ctr, name); err != nil { - return err - } - - // Update config.json - configRuntimePath := filepath.Join(ctr.BundlePath(), configFile) - if err = updateConfigName(configRuntimePath, name); err != nil { - return err - } - configStoragePath := filepath.Join(ctr.Dir(), configFile) - if err = updateConfigName(configStoragePath, name); err != nil { - return err - } - - // Update containers.json - if err = c.store.SetNames(ctr.ID(), []string{name}); err != nil { - return err - } - return nil -} - -func updateConfigName(configPath, name string) error { - specgen, err := generate.NewFromFile(configPath) - if err != nil { - return err - } - specgen.AddAnnotation(annotations.Name, name) - specgen.AddAnnotation(annotations.Metadata, updateMetadata(specgen.Spec().Annotations, name)) - - return specgen.SaveToFile(configPath, generate.ExportOptions{}) -} - -func (c *ContainerServer) updateStateName(ctr *oci.Container, name string) error { - ctr.State().Annotations[annotations.Name] = name - ctr.State().Annotations[annotations.Metadata] = updateMetadata(ctr.State().Annotations, name) - // This is taken directly from c.ContainerStateToDisk(), which can't be used because of the call to UpdateStatus() in the first line - jsonSource, err := ioutils.NewAtomicFileWriter(ctr.StatePath(), 0644) - if err != nil { - return err - } - defer jsonSource.Close() - enc := json.NewEncoder(jsonSource) - return enc.Encode(c.runtime.ContainerStatus(ctr)) -} - -// Attempts to update a metadata annotation -func updateMetadata(specAnnotations map[string]string, name string) string { - oldMetadata := specAnnotations[annotations.Metadata] - containerType := specAnnotations[annotations.ContainerType] - if containerType == "container" { - metadata := runtime.ContainerMetadata{} - err := json.Unmarshal([]byte(oldMetadata), metadata) - if err != nil { - return oldMetadata - } - metadata.Name = name - m, err := json.Marshal(metadata) - if err != nil { - return oldMetadata - } - return string(m) - } else if containerType == "sandbox" { - metadata := runtime.PodSandboxMetadata{} - err := json.Unmarshal([]byte(oldMetadata), metadata) - if err != nil { - return oldMetadata - } - metadata.Name = name - m, err := json.Marshal(metadata) - if err != nil { - return oldMetadata - } - return string(m) - } else { - return specAnnotations[annotations.Metadata] - } -} diff --git a/libkpod/sandbox/sandbox.go b/libkpod/sandbox/sandbox.go deleted file mode 100644 index a61c5a4f7..000000000 --- a/libkpod/sandbox/sandbox.go +++ /dev/null @@ -1,484 +0,0 @@ -package sandbox - -import ( - "crypto/rand" - "errors" - "fmt" - "os" - "path/filepath" - "sync" - - "github.com/containernetworking/plugins/pkg/ns" - "github.com/docker/docker/pkg/mount" - "github.com/docker/docker/pkg/symlink" - "github.com/projectatomic/libpod/oci" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" - "k8s.io/apimachinery/pkg/fields" - pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" - "k8s.io/kubernetes/pkg/kubelet/network/hostport" -) - -// NetNs handles data pertaining a network namespace -type NetNs struct { - sync.Mutex - ns ns.NetNS - symlink *os.File - closed bool - restored bool -} - -func (ns *NetNs) symlinkCreate(name string) error { - b := make([]byte, 4) - _, randErr := rand.Reader.Read(b) - if randErr != nil { - return randErr - } - - nsName := fmt.Sprintf("%s-%x", name, b) - symlinkPath := filepath.Join(NsRunDir, nsName) - - if err := os.Symlink(ns.ns.Path(), symlinkPath); err != nil { - return err - } - - fd, err := os.Open(symlinkPath) - if err != nil { - if removeErr := os.RemoveAll(symlinkPath); removeErr != nil { - return removeErr - } - - return err - } - - ns.symlink = fd - - return nil -} - -func (ns *NetNs) symlinkRemove() error { - if err := ns.symlink.Close(); err != nil { - return err - } - - return os.RemoveAll(ns.symlink.Name()) -} - -func isSymbolicLink(path string) (bool, error) { - fi, err := os.Lstat(path) - if err != nil { - return false, err - } - - return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil -} - -// NetNsGet returns the NetNs associated with the given nspath and name -func NetNsGet(nspath, name string) (*NetNs, error) { - if err := ns.IsNSorErr(nspath); err != nil { - return nil, ErrClosedNetNS - } - - symlink, symlinkErr := isSymbolicLink(nspath) - if symlinkErr != nil { - return nil, symlinkErr - } - - var resolvedNsPath string - if symlink { - path, err := os.Readlink(nspath) - if err != nil { - return nil, err - } - resolvedNsPath = path - } else { - resolvedNsPath = nspath - } - - netNS, err := ns.GetNS(resolvedNsPath) - if err != nil { - return nil, err - } - - netNs := &NetNs{ns: netNS, closed: false, restored: true} - - if symlink { - fd, err := os.Open(nspath) - if err != nil { - return nil, err - } - - netNs.symlink = fd - } else { - if err := netNs.symlinkCreate(name); err != nil { - return nil, err - } - } - - return netNs, nil -} - -// HostNetNsPath returns the current network namespace for the host -func HostNetNsPath() (string, error) { - netNS, err := ns.GetCurrentNS() - if err != nil { - return "", err - } - - defer netNS.Close() - return netNS.Path(), nil -} - -// Sandbox contains data surrounding kubernetes sandboxes on the server -type Sandbox struct { - id string - namespace string - // OCI pod name (eg "<namespace>-<name>-<attempt>") - name string - // Kubernetes pod name (eg, "<name>") - kubeName string - logDir string - labels fields.Set - annotations map[string]string - infraContainer *oci.Container - containers oci.ContainerStorer - processLabel string - mountLabel string - netns *NetNs - metadata *pb.PodSandboxMetadata - shmPath string - cgroupParent string - privileged bool - trusted bool - resolvPath string - hostnamePath string - hostname string - portMappings []*hostport.PortMapping - stopped bool - // ipv4 or ipv6 cache - ip string -} - -const ( - // DefaultShmSize is the default shm size - DefaultShmSize = 64 * 1024 * 1024 - // NsRunDir is the default directory in which running network namespaces - // are stored - NsRunDir = "/var/run/netns" - // PodInfraCommand is the default command when starting a pod infrastructure - // container - PodInfraCommand = "/pause" -) - -var ( - // ErrIDEmpty is the erro returned when the id of the sandbox is empty - ErrIDEmpty = errors.New("PodSandboxId should not be empty") - // ErrClosedNetNS is the error returned when the network namespace of the - // sandbox is closed - ErrClosedNetNS = errors.New("PodSandbox networking namespace is closed") -) - -// New creates and populates a new pod sandbox -// New sandboxes have no containers, no infra container, and no network namespaces associated with them -// An infra container must be attached before the sandbox is added to the state -func New(id, namespace, name, kubeName, logDir string, labels, annotations map[string]string, processLabel, mountLabel string, metadata *pb.PodSandboxMetadata, shmPath, cgroupParent string, privileged, trusted bool, resolvPath, hostname string, portMappings []*hostport.PortMapping) (*Sandbox, error) { - sb := new(Sandbox) - sb.id = id - sb.namespace = namespace - sb.name = name - sb.kubeName = kubeName - sb.logDir = logDir - sb.labels = labels - sb.annotations = annotations - sb.containers = oci.NewMemoryStore() - sb.processLabel = processLabel - sb.mountLabel = mountLabel - sb.metadata = metadata - sb.shmPath = shmPath - sb.cgroupParent = cgroupParent - sb.privileged = privileged - sb.trusted = trusted - sb.resolvPath = resolvPath - sb.hostname = hostname - sb.portMappings = portMappings - - return sb, nil -} - -// AddIP stores the ip in the sandbox -func (s *Sandbox) AddIP(ip string) { - s.ip = ip -} - -// IP returns the ip of the sandbox -func (s *Sandbox) IP() string { - return s.ip -} - -// ID returns the id of the sandbox -func (s *Sandbox) ID() string { - return s.id -} - -// Namespace returns the namespace for the sandbox -func (s *Sandbox) Namespace() string { - return s.namespace -} - -// Name returns the name of the sandbox -func (s *Sandbox) Name() string { - return s.name -} - -// KubeName returns the kubernetes name for the sandbox -func (s *Sandbox) KubeName() string { - return s.kubeName -} - -// LogDir returns the location of the logging directory for the sandbox -func (s *Sandbox) LogDir() string { - return s.logDir -} - -// Labels returns the labels associated with the sandbox -func (s *Sandbox) Labels() fields.Set { - return s.labels -} - -// Annotations returns a list of annotations for the sandbox -func (s *Sandbox) Annotations() map[string]string { - return s.annotations -} - -// InfraContainer returns the infrastructure container for the sandbox -func (s *Sandbox) InfraContainer() *oci.Container { - return s.infraContainer -} - -// Containers returns the ContainerStorer that contains information on all -// of the containers in the sandbox -func (s *Sandbox) Containers() oci.ContainerStorer { - return s.containers -} - -// ProcessLabel returns the process label for the sandbox -func (s *Sandbox) ProcessLabel() string { - return s.processLabel -} - -// MountLabel returns the mount label for the sandbox -func (s *Sandbox) MountLabel() string { - return s.mountLabel -} - -// Metadata returns a set of metadata about the sandbox -func (s *Sandbox) Metadata() *pb.PodSandboxMetadata { - return s.metadata -} - -// ShmPath returns the shm path of the sandbox -func (s *Sandbox) ShmPath() string { - return s.shmPath -} - -// CgroupParent returns the cgroup parent of the sandbox -func (s *Sandbox) CgroupParent() string { - return s.cgroupParent -} - -// Privileged returns whether or not the containers in the sandbox are -// privileged containers -func (s *Sandbox) Privileged() bool { - return s.privileged -} - -// Trusted returns whether or not the containers in the sandbox are trusted -func (s *Sandbox) Trusted() bool { - return s.trusted -} - -// ResolvPath returns the resolv path for the sandbox -func (s *Sandbox) ResolvPath() string { - return s.resolvPath -} - -// AddHostnamePath adds the hostname path to the sandbox -func (s *Sandbox) AddHostnamePath(hostname string) { - s.hostnamePath = hostname -} - -// HostnamePath retrieves the hostname path from a sandbox -func (s *Sandbox) HostnamePath() string { - return s.hostnamePath -} - -// Hostname returns the hsotname of the sandbox -func (s *Sandbox) Hostname() string { - return s.hostname -} - -// PortMappings returns a list of port mappings between the host and the sandbox -func (s *Sandbox) PortMappings() []*hostport.PortMapping { - return s.portMappings -} - -// AddContainer adds a container to the sandbox -func (s *Sandbox) AddContainer(c *oci.Container) { - s.containers.Add(c.Name(), c) -} - -// GetContainer retrieves a container from the sandbox -func (s *Sandbox) GetContainer(name string) *oci.Container { - return s.containers.Get(name) -} - -// RemoveContainer deletes a container from the sandbox -func (s *Sandbox) RemoveContainer(c *oci.Container) { - s.containers.Delete(c.Name()) -} - -// SetInfraContainer sets the infrastructure container of a sandbox -// Attempts to set the infrastructure container after one is already present will throw an error -func (s *Sandbox) SetInfraContainer(infraCtr *oci.Container) error { - if s.infraContainer != nil { - return fmt.Errorf("sandbox already has an infra container") - } else if infraCtr == nil { - return fmt.Errorf("must provide non-nil infra container") - } - - s.infraContainer = infraCtr - - return nil -} - -// RemoveInfraContainer removes the infrastructure container of a sandbox -func (s *Sandbox) RemoveInfraContainer() { - s.infraContainer = nil -} - -// NetNs retrieves the network namespace of the sandbox -// If the sandbox uses the host namespace, nil is returned -func (s *Sandbox) NetNs() ns.NetNS { - if s.netns == nil { - return nil - } - - return s.netns.ns -} - -// NetNsPath returns the path to the network namespace of the sandbox. -// If the sandbox uses the host namespace, nil is returned -func (s *Sandbox) NetNsPath() string { - if s.netns == nil { - return "" - } - - return s.netns.symlink.Name() -} - -// NetNsCreate creates a new network namespace for the sandbox -func (s *Sandbox) NetNsCreate() error { - if s.netns != nil { - return fmt.Errorf("net NS already created") - } - - netNS, err := ns.NewNS() - if err != nil { - return err - } - - s.netns = &NetNs{ - ns: netNS, - closed: false, - } - - if err := s.netns.symlinkCreate(s.name); err != nil { - logrus.Warnf("Could not create nentns symlink %v", err) - - if err1 := s.netns.ns.Close(); err1 != nil { - return err1 - } - - return err - } - - return nil -} - -// SetStopped sets the sandbox state to stopped. -// This should be set after a stop operation succeeds -// so that subsequent stops can return fast. -func (s *Sandbox) SetStopped() { - s.stopped = true -} - -// Stopped returns whether the sandbox state has been -// set to stopped. -func (s *Sandbox) Stopped() bool { - return s.stopped -} - -// NetNsJoin attempts to join the sandbox to an existing network namespace -// This will fail if the sandbox is already part of a network namespace -func (s *Sandbox) NetNsJoin(nspath, name string) error { - if s.netns != nil { - return fmt.Errorf("sandbox already has a network namespace, cannot join another") - } - - netNS, err := NetNsGet(nspath, name) - if err != nil { - return err - } - - s.netns = netNS - - return nil -} - -// NetNsRemove removes the network namespace associated with the sandbox -func (s *Sandbox) NetNsRemove() error { - if s.netns == nil { - logrus.Warn("no networking namespace") - return nil - } - - s.netns.Lock() - defer s.netns.Unlock() - - if s.netns.closed { - // netNsRemove() can be called multiple - // times without returning an error. - return nil - } - - if err := s.netns.symlinkRemove(); err != nil { - return err - } - - if err := s.netns.ns.Close(); err != nil { - return err - } - - if s.netns.restored { - // we got namespaces in the form of - // /var/run/netns/cni-0d08effa-06eb-a963-f51a-e2b0eceffc5d - // but /var/run on most system is symlinked to /run so we first resolve - // the symlink and then try and see if it's mounted - fp, err := symlink.FollowSymlinkInScope(s.netns.ns.Path(), "/") - if err != nil { - return err - } - if mounted, err := mount.Mounted(fp); err == nil && mounted { - if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil { - return err - } - } - - if err := os.RemoveAll(s.netns.ns.Path()); err != nil { - return err - } - } - - s.netns.closed = true - return nil -} diff --git a/libkpod/stats.go b/libkpod/stats.go deleted file mode 100644 index 8e74577d4..000000000 --- a/libkpod/stats.go +++ /dev/null @@ -1,111 +0,0 @@ -package libkpod - -import ( - "path/filepath" - "syscall" - "time" - - "strings" - - "github.com/opencontainers/runc/libcontainer" - "github.com/projectatomic/libpod/oci" -) - -// ContainerStats contains the statistics information for a running container -type ContainerStats struct { - Container string - CPU float64 - cpuNano uint64 - systemNano uint64 - MemUsage uint64 - MemLimit uint64 - MemPerc float64 - NetInput uint64 - NetOutput uint64 - BlockInput uint64 - BlockOutput uint64 - PIDs uint64 -} - -// GetContainerStats gets the running stats for a given container -func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) { - previousCPU := previousStats.cpuNano - previousSystem := previousStats.systemNano - libcontainerStats, err := c.LibcontainerStats(ctr) - if err != nil { - return nil, err - } - cgroupStats := libcontainerStats.CgroupStats - stats := new(ContainerStats) - stats.Container = ctr.ID() - stats.CPU = calculateCPUPercent(libcontainerStats, previousCPU, previousSystem) - stats.MemUsage = cgroupStats.MemoryStats.Usage.Usage - stats.MemLimit = getMemLimit(cgroupStats.MemoryStats.Usage.Limit) - stats.MemPerc = float64(stats.MemUsage) / float64(stats.MemLimit) - stats.PIDs = cgroupStats.PidsStats.Current - stats.BlockInput, stats.BlockOutput = calculateBlockIO(libcontainerStats) - stats.NetInput, stats.NetOutput = getContainerNetIO(libcontainerStats) - - return stats, nil -} - -func loadFactory(root string) (libcontainer.Factory, error) { - abs, err := filepath.Abs(root) - if err != nil { - return nil, err - } - cgroupManager := libcontainer.Cgroupfs - return libcontainer.New(abs, cgroupManager, libcontainer.CriuPath("")) -} - -// getMemory limit returns the memory limit for a given cgroup -// If the configured memory limit is larger than the total memory on the sys, the -// physical system memory size is returned -func getMemLimit(cgroupLimit uint64) uint64 { - si := &syscall.Sysinfo_t{} - err := syscall.Sysinfo(si) - if err != nil { - return cgroupLimit - } - - physicalLimit := uint64(si.Totalram) - if cgroupLimit > physicalLimit { - return physicalLimit - } - return cgroupLimit -} - -// Returns the total number of bytes transmitted and received for the given container stats -func getContainerNetIO(stats *libcontainer.Stats) (received uint64, transmitted uint64) { - for _, iface := range stats.Interfaces { - received += iface.RxBytes - transmitted += iface.TxBytes - } - return -} - -func calculateCPUPercent(stats *libcontainer.Stats, previousCPU, previousSystem uint64) float64 { - var ( - cpuPercent = 0.0 - cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU) - systemDelta = float64(uint64(time.Now().UnixNano()) - previousSystem) - ) - if systemDelta > 0.0 && cpuDelta > 0.0 { - // gets a ratio of container cpu usage total, multiplies it by the number of cores (4 cores running - // at 100% utilization should be 400% utilization), and multiplies that by 100 to get a percentage - cpuPercent = (cpuDelta / systemDelta) * float64(len(stats.CgroupStats.CpuStats.CpuUsage.PercpuUsage)) * 100 - } - return cpuPercent -} - -func calculateBlockIO(stats *libcontainer.Stats) (read uint64, write uint64) { - for _, blkIOEntry := range stats.CgroupStats.BlkioStats.IoServiceBytesRecursive { - switch strings.ToLower(blkIOEntry.Op) { - case "read": - read += blkIOEntry.Value - case "write": - write += blkIOEntry.Value - } - } - return -} diff --git a/libkpod/stop.go b/libkpod/stop.go deleted file mode 100644 index 4ce7db740..000000000 --- a/libkpod/stop.go +++ /dev/null @@ -1,36 +0,0 @@ -package libkpod - -import ( - "github.com/pkg/errors" - "github.com/projectatomic/libpod/oci" - "golang.org/x/net/context" -) - -// ContainerStop stops a running container with a grace period (i.e., timeout). -func (c *ContainerServer) ContainerStop(ctx context.Context, container string, timeout int64) (string, error) { - ctr, err := c.LookupContainer(container) - if err != nil { - return "", errors.Wrapf(err, "failed to find container %s", container) - } - ctrID := ctr.ID() - - cStatus := c.runtime.ContainerStatus(ctr) - switch cStatus.Status { - - case oci.ContainerStatePaused: - return "", errors.Errorf("cannot stop paused container %s", ctrID) - default: - if cStatus.Status != oci.ContainerStateStopped { - if err := c.runtime.StopContainer(ctx, ctr, timeout); err != nil { - return "", errors.Wrapf(err, "failed to stop container %s", ctrID) - } - if err := c.storageRuntimeServer.StopContainer(ctrID); err != nil { - return "", errors.Wrapf(err, "failed to unmount container %s", ctrID) - } - } - } - - c.ContainerStateToDisk(ctr) - - return ctrID, nil -} diff --git a/libkpod/wait.go b/libkpod/wait.go deleted file mode 100644 index e972a0ba0..000000000 --- a/libkpod/wait.go +++ /dev/null @@ -1,42 +0,0 @@ -package libkpod - -import ( - "github.com/pkg/errors" - "github.com/projectatomic/libpod/oci" - "k8s.io/apimachinery/pkg/util/wait" -) - -func isStopped(c *ContainerServer, ctr *oci.Container) bool { - c.runtime.UpdateStatus(ctr) - cStatus := c.runtime.ContainerStatus(ctr) - if cStatus.Status == oci.ContainerStateStopped { - return true - } - return false -} - -// ContainerWait stops a running container with a grace period (i.e., timeout). -func (c *ContainerServer) ContainerWait(container string) (int32, error) { - ctr, err := c.LookupContainer(container) - if err != nil { - return 0, errors.Wrapf(err, "failed to find container %s", container) - } - - err = wait.PollImmediateInfinite(1, - func() (bool, error) { - if !isStopped(c, ctr) { - return false, nil - } else { // nolint - return true, nil // nolint - } // nolint - - }, - ) - - if err != nil { - return 0, err - } - exitCode := ctr.State().ExitCode - c.ContainerStateToDisk(ctr) - return exitCode, nil -} |