2017-07-23 23:01:37 +00:00
|
|
|
package libkpod
|
2017-06-29 19:16:06 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2017-07-27 16:49:44 +00:00
|
|
|
"os"
|
2017-06-29 19:16:06 +00:00
|
|
|
|
|
|
|
"k8s.io/apimachinery/pkg/fields"
|
2017-08-04 11:13:19 +00:00
|
|
|
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
2017-06-29 19:16:06 +00:00
|
|
|
|
2017-08-31 15:17:21 +00:00
|
|
|
"github.com/kubernetes-incubator/cri-o/libpod/driver"
|
|
|
|
"github.com/kubernetes-incubator/cri-o/libpod/images"
|
2017-06-29 19:16:06 +00:00
|
|
|
"github.com/kubernetes-incubator/cri-o/oci"
|
|
|
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
2017-07-23 23:01:37 +00:00
|
|
|
// ContainerData handles the data used when inspecting a container
|
|
|
|
type ContainerData struct {
|
2017-06-29 19:16:06 +00:00
|
|
|
ID string
|
|
|
|
Name string
|
|
|
|
LogPath string
|
|
|
|
Labels fields.Set
|
|
|
|
Annotations fields.Set
|
|
|
|
State *oci.ContainerState
|
|
|
|
Metadata *pb.ContainerMetadata
|
|
|
|
BundlePath string
|
|
|
|
StopSignal string
|
2017-07-27 16:49:44 +00:00
|
|
|
FromImage string `json:"Image,omitempty"`
|
|
|
|
FromImageID string `json:"ImageID"`
|
|
|
|
MountPoint string `json:"Mountpoint,omitempty"`
|
2017-06-29 19:16:06 +00:00
|
|
|
MountLabel string
|
|
|
|
Mounts []specs.Mount
|
|
|
|
AppArmorProfile string
|
2017-07-27 16:49:44 +00:00
|
|
|
ImageAnnotations map[string]string `json:"Annotations,omitempty"`
|
|
|
|
ImageCreatedBy string `json:"CreatedBy,omitempty"`
|
|
|
|
Config v1.ImageConfig `json:"Config,omitempty"`
|
2017-06-29 19:16:06 +00:00
|
|
|
SizeRw uint `json:"SizeRw,omitempty"`
|
|
|
|
SizeRootFs uint `json:"SizeRootFs,omitempty"`
|
|
|
|
Args []string
|
|
|
|
ResolvConfPath string
|
|
|
|
HostnamePath string
|
|
|
|
HostsPath string
|
|
|
|
GraphDriver driverData
|
|
|
|
}
|
|
|
|
|
|
|
|
type driverData struct {
|
|
|
|
Name string
|
|
|
|
Data map[string]string
|
|
|
|
}
|
|
|
|
|
2017-07-23 23:01:37 +00:00
|
|
|
// GetContainerData gets the ContainerData for a container with the given name in the given store.
|
|
|
|
// If size is set to true, it will also determine the size of the container
|
2017-08-01 15:28:50 +00:00
|
|
|
func (c *ContainerServer) GetContainerData(name string, size bool) (*ContainerData, error) {
|
|
|
|
ctr, err := c.inspectContainer(name)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading build container %q", name)
|
|
|
|
}
|
2017-08-01 15:28:50 +00:00
|
|
|
container, err := c.store.Container(name)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
2017-07-27 16:49:44 +00:00
|
|
|
return nil, errors.Wrapf(err, "error reading container data")
|
2017-06-29 19:16:06 +00:00
|
|
|
}
|
2017-07-27 16:49:44 +00:00
|
|
|
|
|
|
|
// The runtime configuration won't exist if the container has never been started by cri-o or kpod,
|
|
|
|
// so treat a not-exist error as non-fatal.
|
|
|
|
m := getBlankSpec()
|
2017-08-01 15:28:50 +00:00
|
|
|
config, err := c.store.FromContainerDirectory(ctr.ID(), "config.json")
|
2017-07-27 16:49:44 +00:00
|
|
|
if err != nil && !os.IsNotExist(errors.Cause(err)) {
|
2017-06-29 19:16:06 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-27 16:49:44 +00:00
|
|
|
if len(config) > 0 {
|
|
|
|
if err = json.Unmarshal(config, &m); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2017-06-29 19:16:06 +00:00
|
|
|
|
2017-07-27 16:49:44 +00:00
|
|
|
if container.ImageID == "" {
|
|
|
|
return nil, errors.Errorf("error reading container image data: container is not based on an image")
|
|
|
|
}
|
2017-08-31 15:17:21 +00:00
|
|
|
imageData, err := images.GetData(c.store, container.ImageID)
|
2017-07-27 16:49:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading container image data")
|
2017-06-29 19:16:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-01 15:28:50 +00:00
|
|
|
driverName, err := driver.GetDriverName(c.store)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-08-01 15:28:50 +00:00
|
|
|
topLayer, err := c.GetContainerTopLayerID(ctr.ID())
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-08-01 15:28:50 +00:00
|
|
|
layer, err := c.store.Layer(topLayer)
|
2017-07-27 16:49:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-08-01 15:28:50 +00:00
|
|
|
driverMetadata, err := driver.GetDriverMetadata(c.store, topLayer)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-27 16:49:44 +00:00
|
|
|
imageName := ""
|
|
|
|
if len(imageData.Tags) > 0 {
|
|
|
|
imageName = imageData.Tags[0]
|
|
|
|
} else if len(imageData.Digests) > 0 {
|
|
|
|
imageName = imageData.Digests[0]
|
|
|
|
}
|
2017-07-23 23:01:37 +00:00
|
|
|
data := &ContainerData{
|
2017-06-29 19:16:06 +00:00
|
|
|
ID: ctr.ID(),
|
|
|
|
Name: ctr.Name(),
|
|
|
|
LogPath: ctr.LogPath(),
|
|
|
|
Labels: ctr.Labels(),
|
|
|
|
Annotations: ctr.Annotations(),
|
|
|
|
State: ctr.State(),
|
|
|
|
Metadata: ctr.Metadata(),
|
|
|
|
BundlePath: ctr.BundlePath(),
|
|
|
|
StopSignal: ctr.GetStopSignal(),
|
|
|
|
Args: m.Process.Args,
|
2017-07-27 16:49:44 +00:00
|
|
|
FromImage: imageName,
|
|
|
|
FromImageID: container.ImageID,
|
|
|
|
MountPoint: layer.MountPoint,
|
|
|
|
ImageAnnotations: imageData.Annotations,
|
|
|
|
ImageCreatedBy: imageData.CreatedBy,
|
|
|
|
Config: imageData.Config,
|
2017-06-29 19:16:06 +00:00
|
|
|
GraphDriver: driverData{
|
|
|
|
Name: driverName,
|
|
|
|
Data: driverMetadata,
|
|
|
|
},
|
|
|
|
MountLabel: m.Linux.MountLabel,
|
|
|
|
Mounts: m.Mounts,
|
|
|
|
AppArmorProfile: m.Process.ApparmorProfile,
|
|
|
|
ResolvConfPath: "",
|
|
|
|
HostnamePath: "",
|
|
|
|
HostsPath: "",
|
|
|
|
}
|
|
|
|
|
|
|
|
if size {
|
2017-08-01 15:28:50 +00:00
|
|
|
sizeRootFs, err := c.GetContainerRootFsSize(data.ID)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, errors.Wrapf(err, "error reading size for container %q", name)
|
|
|
|
}
|
|
|
|
data.SizeRootFs = uint(sizeRootFs)
|
2017-08-01 15:28:50 +00:00
|
|
|
sizeRw, err := c.GetContainerRwSize(data.ID)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading RWSize for container %q", name)
|
|
|
|
}
|
|
|
|
data.SizeRw = uint(sizeRw)
|
|
|
|
}
|
|
|
|
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get an oci.Container and update its status
|
2017-08-01 15:28:50 +00:00
|
|
|
func (c *ContainerServer) inspectContainer(container string) (*oci.Container, error) {
|
|
|
|
ociCtr, err := c.LookupContainer(container)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// call runtime.UpdateStatus()
|
2017-08-01 15:28:50 +00:00
|
|
|
err = c.Runtime().UpdateStatus(ociCtr)
|
2017-06-29 19:16:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ociCtr, nil
|
|
|
|
}
|
|
|
|
|
2017-07-27 16:49:44 +00:00
|
|
|
func getBlankSpec() specs.Spec {
|
|
|
|
return specs.Spec{
|
|
|
|
Process: &specs.Process{},
|
|
|
|
Root: &specs.Root{},
|
|
|
|
Mounts: []specs.Mount{},
|
|
|
|
Hooks: &specs.Hooks{},
|
|
|
|
Annotations: make(map[string]string),
|
|
|
|
Linux: &specs.Linux{},
|
|
|
|
Solaris: &specs.Solaris{},
|
|
|
|
Windows: &specs.Windows{},
|
|
|
|
}
|
|
|
|
}
|