podman: accept option --rootfs to use exploded images

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>

Closes: #871
Approved by: mheon
This commit is contained in:
Giuseppe Scrivano
2018-04-26 17:21:48 +02:00
committed by Atomic Bot
parent 4b4de5dc21
commit 7bdfb4f9b3
14 changed files with 208 additions and 81 deletions

View File

@ -322,6 +322,10 @@ var createFlags = []cli.Flag{
Name: "rm", Name: "rm",
Usage: "Remove container (and pod if created) after exit", Usage: "Remove container (and pod if created) after exit",
}, },
cli.BoolFlag{
Name: "rootfs",
Usage: "The first argument is not an image but the rootfs to the exploded container",
},
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "security-opt", Name: "security-opt",
Usage: "Security Options (default [])", Usage: "Security Options (default [])",

View File

@ -72,6 +72,11 @@ func createCmd(c *cli.Context) error {
return errors.Errorf("image name or ID is required") return errors.Errorf("image name or ID is required")
} }
rootfs := ""
if c.Bool("rootfs") {
rootfs = c.Args()[0]
}
mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap"))
if err != nil { if err != nil {
return err return err
@ -89,12 +94,17 @@ func createCmd(c *cli.Context) error {
rtc := runtime.GetConfig() rtc := runtime.GetConfig()
ctx := getContext() ctx := getContext()
newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false) imageName := ""
if err != nil { var data *inspect.ImageData = nil
return err if rootfs == "" {
newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false)
if err != nil {
return err
}
data, err = newImage.Inspect(ctx)
imageName = newImage.Names()[0]
} }
data, err := newImage.Inspect(ctx) createConfig, err := parseCreateOpts(ctx, c, runtime, imageName, data)
createConfig, err := parseCreateOpts(ctx, c, runtime, newImage.Names()[0], data)
if err != nil { if err != nil {
return err return err
} }
@ -118,6 +128,9 @@ func createCmd(c *cli.Context) error {
options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize)) options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize))
options = append(options, libpod.WithGroups(createConfig.GroupAdd)) options = append(options, libpod.WithGroups(createConfig.GroupAdd))
options = append(options, libpod.WithIDMappings(*createConfig.IDMappings)) options = append(options, libpod.WithIDMappings(*createConfig.IDMappings))
if createConfig.Rootfs != "" {
options = append(options, libpod.WithRootFS(createConfig.Rootfs))
}
ctr, err := runtime.NewContainer(ctx, runtimeSpec, options...) ctr, err := runtime.NewContainer(ctx, runtimeSpec, options...)
if err != nil { if err != nil {
return err return err
@ -246,10 +259,16 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, err return nil, err
} }
imageID := data.ID imageID := ""
if len(c.Args()) > 1 { inputCommand = c.Args()[1:]
inputCommand = c.Args()[1:] if data != nil {
imageID = data.ID
}
rootfs := ""
if c.Bool("rootfs") {
rootfs = c.Args()[0]
} }
sysctl, err := validateSysctl(c.StringSlice("sysctl")) sysctl, err := validateSysctl(c.StringSlice("sysctl"))
@ -337,12 +356,19 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
// USER // USER
user := c.String("user") user := c.String("user")
if user == "" { if user == "" {
user = data.ContainerConfig.User if data == nil {
user = "0"
} else {
user = data.ContainerConfig.User
}
} }
// STOP SIGNAL // STOP SIGNAL
stopSignal := syscall.SIGTERM stopSignal := syscall.SIGTERM
signalString := data.ContainerConfig.StopSignal signalString := "SIGTERM"
if data != nil {
signalString = data.ContainerConfig.StopSignal
}
if c.IsSet("stop-signal") { if c.IsSet("stop-signal") {
signalString = c.String("stop-signal") signalString = c.String("stop-signal")
} }
@ -355,12 +381,14 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
// ENVIRONMENT VARIABLES // ENVIRONMENT VARIABLES
env := defaultEnvVariables env := defaultEnvVariables
for _, e := range data.ContainerConfig.Env { if data != nil {
split := strings.SplitN(e, "=", 2) for _, e := range data.ContainerConfig.Env {
if len(split) > 1 { split := strings.SplitN(e, "=", 2)
env[split[0]] = split[1] if len(split) > 1 {
} else { env[split[0]] = split[1]
env[split[0]] = "" } else {
env[split[0]] = ""
}
} }
} }
if err := readKVStrings(env, c.StringSlice("env-file"), c.StringSlice("env")); err != nil { if err := readKVStrings(env, c.StringSlice("env-file"), c.StringSlice("env")); err != nil {
@ -372,9 +400,11 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to process labels") return nil, errors.Wrapf(err, "unable to process labels")
} }
for key, val := range data.ContainerConfig.Labels { if data != nil {
if _, ok := labels[key]; !ok { for key, val := range data.ContainerConfig.Labels {
labels[key] = val if _, ok := labels[key]; !ok {
labels[key] = val
}
} }
} }
@ -386,9 +416,11 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if tty { if tty {
annotations[ann.TTY] = "true" annotations[ann.TTY] = "true"
} }
// Next, add annotations from the image if data != nil {
for key, value := range data.Annotations { // Next, add annotations from the image
annotations[key] = value for key, value := range data.Annotations {
annotations[key] = value
}
} }
// Last, add user annotations // Last, add user annotations
for _, annotation := range c.StringSlice("annotation") { for _, annotation := range c.StringSlice("annotation") {
@ -403,14 +435,14 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
workDir := "/" workDir := "/"
if c.IsSet("workdir") || c.IsSet("w") { if c.IsSet("workdir") || c.IsSet("w") {
workDir = c.String("workdir") workDir = c.String("workdir")
} else if data.ContainerConfig.WorkingDir != "" { } else if data != nil && data.ContainerConfig.WorkingDir != "" {
workDir = data.ContainerConfig.WorkingDir workDir = data.ContainerConfig.WorkingDir
} }
// ENTRYPOINT // ENTRYPOINT
// User input entrypoint takes priority over image entrypoint // User input entrypoint takes priority over image entrypoint
entrypoint := c.StringSlice("entrypoint") entrypoint := c.StringSlice("entrypoint")
if len(entrypoint) == 0 { if len(entrypoint) == 0 && data != nil {
entrypoint = data.ContainerConfig.Entrypoint entrypoint = data.ContainerConfig.Entrypoint
} }
// if entrypoint=, we need to clear the entrypoint // if entrypoint=, we need to clear the entrypoint
@ -425,7 +457,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if len(inputCommand) > 0 { if len(inputCommand) > 0 {
// User command overrides data CMD // User command overrides data CMD
command = append(command, inputCommand...) command = append(command, inputCommand...)
} else if len(data.ContainerConfig.Cmd) > 0 && !c.IsSet("entrypoint") { } else if data != nil && len(data.ContainerConfig.Cmd) > 0 && !c.IsSet("entrypoint") {
// If not user command, add CMD // If not user command, add CMD
command = append(command, data.ContainerConfig.Cmd...) command = append(command, data.ContainerConfig.Cmd...)
} }
@ -435,9 +467,12 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
} }
// EXPOSED PORTS // EXPOSED PORTS
portBindings, err := cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.ContainerConfig.ExposedPorts) var portBindings map[nat.Port][]nat.PortBinding
if err != nil { if data != nil {
return nil, err portBindings, err = cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.ContainerConfig.ExposedPorts)
if err != nil {
return nil, err
}
} }
// SHM Size // SHM Size
@ -472,8 +507,11 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, err return nil, err
} }
} }
ImageVolumes := data.ContainerConfig.Volumes
var ImageVolumes map[string]struct{}
if data != nil {
ImageVolumes = data.ContainerConfig.Volumes
}
var imageVolType = map[string]string{ var imageVolType = map[string]string{
"bind": "", "bind": "",
"tmpfs": "", "tmpfs": "",
@ -567,6 +605,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
UsernsMode: usernsMode, UsernsMode: usernsMode,
Volumes: c.StringSlice("volume"), Volumes: c.StringSlice("volume"),
WorkDir: workDir, WorkDir: workDir,
Rootfs: rootfs,
} }
if !config.Privileged { if !config.Privileged {

View File

@ -14,6 +14,7 @@ import (
"github.com/projectatomic/libpod/cmd/podman/libpodruntime" "github.com/projectatomic/libpod/cmd/podman/libpodruntime"
"github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/libpod/image" "github.com/projectatomic/libpod/libpod/image"
"github.com/projectatomic/libpod/pkg/inspect"
cc "github.com/projectatomic/libpod/pkg/spec" cc "github.com/projectatomic/libpod/pkg/spec"
"github.com/projectatomic/libpod/pkg/util" "github.com/projectatomic/libpod/pkg/util"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -66,25 +67,36 @@ func runCmd(c *cli.Context) error {
return errors.Wrapf(err, "error creating libpod runtime") return errors.Wrapf(err, "error creating libpod runtime")
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
if len(c.Args()) < 1 { if len(c.Args()) < 1 {
return errors.Errorf("image name or ID is required") return errors.Errorf("image name or ID is required")
} }
ctx := getContext() rootfs := ""
rtc := runtime.GetConfig() if c.Bool("rootfs") {
newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false) rootfs = c.Args()[0]
if err != nil {
return errors.Wrapf(err, "unable to find image")
} }
data, err := newImage.Inspect(ctx) ctx := getContext()
if err != nil { rtc := runtime.GetConfig()
return err
} var newImage *image.Image = nil
if len(newImage.Names()) < 1 { var data *inspect.ImageData = nil
imageName = newImage.ID() if rootfs == "" {
} else { newImage, err = runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false)
imageName = newImage.Names()[0] if err != nil {
return errors.Wrapf(err, "unable to find image")
}
data, err = newImage.Inspect(ctx)
if err != nil {
return err
}
if len(newImage.Names()) < 1 {
imageName = newImage.ID()
} else {
imageName = newImage.Names()[0]
}
} }
createConfig, err := parseCreateOpts(ctx, c, runtime, imageName, data) createConfig, err := parseCreateOpts(ctx, c, runtime, imageName, data)
if err != nil { if err != nil {
@ -112,6 +124,9 @@ func runCmd(c *cli.Context) error {
options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize)) options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize))
options = append(options, libpod.WithGroups(createConfig.GroupAdd)) options = append(options, libpod.WithGroups(createConfig.GroupAdd))
options = append(options, libpod.WithIDMappings(*createConfig.IDMappings)) options = append(options, libpod.WithIDMappings(*createConfig.IDMappings))
if createConfig.Rootfs != "" {
options = append(options, libpod.WithRootFS(createConfig.Rootfs))
}
// Default used if not overridden on command line // Default used if not overridden on command line

View File

@ -1431,6 +1431,7 @@ _podman_container_run() {
--pids-limit --pids-limit
--publish -p --publish -p
--runtime --runtime
--rootfs
--security-opt --security-opt
--shm-size --shm-size
--stop-signal --stop-signal

View File

@ -470,6 +470,13 @@ its root filesystem mounted as read only prohibiting any writes.
Automatically remove the container when it exits. The default is *false*. Automatically remove the container when it exits. The default is *false*.
**--rootfs**
If specified, the first argument refers to an exploded container on the file system.
This is useful to run a container without requiring any image management, the rootfs
of the container is assumed to be managed externally.
**--security-opt**=[] **--security-opt**=[]
Security Options Security Options

View File

@ -491,6 +491,13 @@ its root filesystem mounted as read only prohibiting any writes.
Automatically remove the container when it exits. The default is *false*. Automatically remove the container when it exits. The default is *false*.
**--rootfs**
If specified, the first argument refers to an exploded container on the file system.
This is useful to run a container without requiring any image management, the rootfs
of the container is assumed to be managed externally.
**--security-opt**=[] **--security-opt**=[]
Security Options Security Options

View File

@ -197,6 +197,8 @@ type ContainerConfig struct {
// Information on the image used for the root filesystem/ // Information on the image used for the root filesystem/
RootfsImageID string `json:"rootfsImageID,omitempty"` RootfsImageID string `json:"rootfsImageID,omitempty"`
RootfsImageName string `json:"rootfsImageName,omitempty"` RootfsImageName string `json:"rootfsImageName,omitempty"`
// Rootfs to use for the container, this conflicts with RootfsImageID
Rootfs string `json:"rootfs,omitempty"`
// Whether to mount volumes specified in the image. // Whether to mount volumes specified in the image.
ImageVolumes bool `json:"imageVolumes"` ImageVolumes bool `json:"imageVolumes"`
// Src path to be mounted on /dev/shm in container. // Src path to be mounted on /dev/shm in container.

View File

@ -34,6 +34,10 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
isEnvCleared, isLabelCleared, isExposeCleared, isVolumeCleared bool isEnvCleared, isLabelCleared, isExposeCleared, isVolumeCleared bool
) )
if c.config.Rootfs != "" {
return nil, errors.Errorf("cannot commit a container that uses an exploded rootfs")
}
if !c.batched { if !c.batched {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()

View File

@ -70,6 +70,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data)
}, },
ImageID: config.RootfsImageID, ImageID: config.RootfsImageID,
ImageName: config.RootfsImageName, ImageName: config.RootfsImageName,
Rootfs: config.Rootfs,
ResolvConfPath: resolvPath, ResolvConfPath: resolvPath,
HostnamePath: hostnamePath, HostnamePath: hostnamePath,
HostsPath: hostsPath, HostsPath: hostsPath,

View File

@ -56,6 +56,10 @@ var (
// mutable layer, and the rest is the RootFS: the set of immutable layers // mutable layer, and the rest is the RootFS: the set of immutable layers
// that make up the image on which the container is based. // that make up the image on which the container is based.
func (c *Container) rootFsSize() (int64, error) { func (c *Container) rootFsSize() (int64, error) {
if c.config.Rootfs != "" {
return 0, nil
}
container, err := c.runtime.store.Container(c.ID()) container, err := c.runtime.store.Container(c.ID())
if err != nil { if err != nil {
return 0, err return 0, err
@ -93,6 +97,18 @@ func (c *Container) rootFsSize() (int64, error) {
// rwSize Gets the size of the mutable top layer of the container. // rwSize Gets the size of the mutable top layer of the container.
func (c *Container) rwSize() (int64, error) { func (c *Container) rwSize() (int64, error) {
if c.config.Rootfs != "" {
var size int64
err := filepath.Walk(c.config.Rootfs, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
size += info.Size()
return nil
})
return size, err
}
container, err := c.runtime.store.Container(c.ID()) container, err := c.runtime.store.Container(c.ID())
if err != nil { if err != nil {
return 0, err return 0, err
@ -205,7 +221,7 @@ func (c *Container) setupStorage(ctx context.Context) error {
} }
// Need both an image ID and image name, plus a bool telling us whether to use the image configuration // Need both an image ID and image name, plus a bool telling us whether to use the image configuration
if c.config.RootfsImageID == "" || c.config.RootfsImageName == "" { if c.config.Rootfs == "" && (c.config.RootfsImageID == "" || c.config.RootfsImageName == "") {
return errors.Wrapf(ErrInvalidArg, "must provide image ID and image name to use an image") return errors.Wrapf(ErrInvalidArg, "must provide image ID and image name to use an image")
} }
@ -691,9 +707,12 @@ func (c *Container) mountStorage() (err error) {
} }
} }
mountPoint, err := c.runtime.storageService.MountContainerImage(c.ID()) mountPoint := c.config.Rootfs
if err != nil { if mountPoint == "" {
return errors.Wrapf(err, "error mounting storage for container %s", c.ID()) mountPoint, err = c.runtime.storageService.MountContainerImage(c.ID())
if err != nil {
return errors.Wrapf(err, "error mounting storage for container %s", c.ID())
}
} }
c.state.Mounted = true c.state.Mounted = true
c.state.Mountpoint = mountPoint c.state.Mountpoint = mountPoint
@ -796,6 +815,9 @@ func (c *Container) cleanupStorage() error {
} }
} }
} }
if c.config.Rootfs != "" {
return nil
}
// Also unmount storage // Also unmount storage
if err := c.runtime.storageService.UnmountContainerImage(c.ID()); err != nil { if err := c.runtime.storageService.UnmountContainerImage(c.ID()); err != nil {
@ -1154,7 +1176,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
return nil, errors.Wrapf(err, "error setting up OCI Hooks") return nil, errors.Wrapf(err, "error setting up OCI Hooks")
} }
// Bind builtin image volumes // Bind builtin image volumes
if c.config.ImageVolumes { if c.config.Rootfs == "" && c.config.ImageVolumes {
if err := c.addImageVolumes(ctx, &g); err != nil { if err := c.addImageVolumes(ctx, &g); err != nil {
return nil, errors.Wrapf(err, "error mounting image volumes") return nil, errors.Wrapf(err, "error mounting image volumes")
} }
@ -1235,8 +1257,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
} }
} }
if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil { if c.config.Rootfs == "" {
return nil, err if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
return nil, err
}
} }
g.SetRootPath(c.state.RealMountpoint) g.SetRootPath(c.state.RealMountpoint)

View File

@ -2,6 +2,7 @@ package libpod
import ( import (
"net" "net"
"os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"syscall" "syscall"
@ -361,6 +362,9 @@ func WithRootFSFromImage(imageID string, imageName string, useImageVolumes bool)
if ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" { if ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" {
return errors.Wrapf(ErrInvalidArg, "container already configured with root filesystem") return errors.Wrapf(ErrInvalidArg, "container already configured with root filesystem")
} }
if ctr.config.Rootfs != "" {
return errors.Wrapf(ErrInvalidArg, "cannot set both an image ID and a rootfs for a container")
}
ctr.config.RootfsImageID = imageID ctr.config.RootfsImageID = imageID
ctr.config.RootfsImageName = imageName ctr.config.RootfsImageName = imageName
@ -909,6 +913,23 @@ func WithCommand(command []string) CtrCreateOption {
} }
} }
// WithRootFS sets the rootfs for the container
func WithRootFS(rootfs string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if _, err := os.Stat(rootfs); err != nil {
return errors.Wrapf(err, "error checking path %q", rootfs)
}
if ctr.config.RootfsImageID != "" {
return errors.Wrapf(ErrInvalidArg, "cannot set both an image ID and a rootfs for a container")
}
ctr.config.Rootfs = rootfs
return nil
}
}
// Pod Creation Options // Pod Creation Options
// WithPodName sets the name of the pod. // WithPodName sets the name of the pod.

View File

@ -60,40 +60,40 @@ func (metadata *RuntimeContainerMetadata) SetMountLabel(mountLabel string) {
// CreateContainerStorage creates the storage end of things. We already have the container spec created // CreateContainerStorage creates the storage end of things. We already have the container spec created
// TO-DO We should be passing in an Image object in the future. // TO-DO We should be passing in an Image object in the future.
func (r *storageService) CreateContainerStorage(ctx context.Context, systemContext *types.SystemContext, imageName, imageID, containerName, containerID, mountLabel string, options *storage.ContainerOptions) (ContainerInfo, error) { func (r *storageService) CreateContainerStorage(ctx context.Context, systemContext *types.SystemContext, imageName, imageID, containerName, containerID, mountLabel string, options *storage.ContainerOptions) (ContainerInfo, error) {
var ref types.ImageReference var imageConfig *v1.Image
if imageName == "" && imageID == "" { if imageName != "" {
return ContainerInfo{}, ErrEmptyID var ref types.ImageReference
} if containerName == "" {
if containerName == "" { return ContainerInfo{}, ErrEmptyID
return ContainerInfo{}, ErrEmptyID }
} // Check if we have the specified image.
// Check if we have the specified image. ref, err := istorage.Transport.ParseStoreReference(r.store, imageID)
ref, err := istorage.Transport.ParseStoreReference(r.store, imageID) if err != nil {
if err != nil { return ContainerInfo{}, err
return ContainerInfo{}, err }
} img, err := istorage.Transport.GetStoreImage(r.store, ref)
img, err := istorage.Transport.GetStoreImage(r.store, ref) if err != nil {
if err != nil { return ContainerInfo{}, err
return ContainerInfo{}, err }
} // Pull out a copy of the image's configuration.
// Pull out a copy of the image's configuration. image, err := ref.NewImage(ctx, systemContext)
image, err := ref.NewImage(ctx, systemContext) if err != nil {
if err != nil { return ContainerInfo{}, err
return ContainerInfo{}, err }
} defer image.Close()
defer image.Close()
// Get OCI configuration of image // Get OCI configuration of image
imageConfig, err := image.OCIConfig(ctx) imageConfig, err = image.OCIConfig(ctx)
if err != nil { if err != nil {
return ContainerInfo{}, err return ContainerInfo{}, err
} }
// Update the image name and ID. // Update the image name and ID.
if imageName == "" && len(img.Names) > 0 { if imageName == "" && len(img.Names) > 0 {
imageName = img.Names[0] imageName = img.Names[0]
}
imageID = img.ID
} }
imageID = img.ID
// Build metadata to store with the container. // Build metadata to store with the container.
metadata := RuntimeContainerMetadata{ metadata := RuntimeContainerMetadata{
@ -119,7 +119,7 @@ func (r *storageService) CreateContainerStorage(ctx context.Context, systemConte
}, },
} }
} }
container, err := r.store.CreateContainer(containerID, names, img.ID, "", string(mdata), options) container, err := r.store.CreateContainer(containerID, names, imageID, "", string(mdata), options)
if err != nil { if err != nil {
logrus.Debugf("failed to create container %s(%s): %v", metadata.ContainerName, containerID, err) logrus.Debugf("failed to create container %s(%s): %v", metadata.ContainerName, containerID, err)

View File

@ -148,6 +148,7 @@ type ContainerInspectData struct {
State *ContainerInspectState `json:"State"` State *ContainerInspectState `json:"State"`
ImageID string `json:"Image"` ImageID string `json:"Image"`
ImageName string `json:"ImageName"` ImageName string `json:"ImageName"`
Rootfs string `json:"Rootfs"`
ResolvConfPath string `json:"ResolvConfPath"` ResolvConfPath string `json:"ResolvConfPath"`
HostnamePath string `json:"HostnamePath"` HostnamePath string `json:"HostnamePath"`
HostsPath string `json:"HostsPath"` HostsPath string `json:"HostsPath"`

View File

@ -130,6 +130,7 @@ type CreateConfig struct {
ApparmorProfile string //SecurityOpts ApparmorProfile string //SecurityOpts
SeccompProfilePath string //SecurityOpts SeccompProfilePath string //SecurityOpts
SecurityOpts []string SecurityOpts []string
Rootfs string
} }
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }