diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/libpod/images.go | 18 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/pods.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/types.go | 3 | ||||
-rw-r--r-- | pkg/api/server/register_images.go | 4 | ||||
-rw-r--r-- | pkg/autoupdate/autoupdate.go | 3 | ||||
-rw-r--r-- | pkg/bindings/images/types.go | 2 | ||||
-rw-r--r-- | pkg/bindings/images/types_export_options.go | 15 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 67 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 55 | ||||
-rw-r--r-- | pkg/domain/infra/abi/generate.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 4 | ||||
-rw-r--r-- | pkg/env/env.go | 5 | ||||
-rw-r--r-- | pkg/specgen/generate/config_linux.go | 1 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 28 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 7 | ||||
-rw-r--r-- | pkg/specgen/podspecgen.go | 2 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 4 |
19 files changed, 140 insertions, 89 deletions
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index b4f08a746..51157d204 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -289,9 +289,10 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { - Compress bool `schema:"compress"` - Format string `schema:"format"` - References []string `schema:"references"` + Compress bool `schema:"compress"` + Format string `schema:"format"` + OciAcceptUncompressedLayers bool `schema:"ociAcceptUncompressedLayers"` + References []string `schema:"references"` }{ Format: define.OCIArchive, } @@ -353,11 +354,12 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { // Use the ABI image engine to share as much code as possible. opts := entities.ImageSaveOptions{ - Compress: query.Compress, - Format: query.Format, - MultiImageArchive: len(query.References) > 1, - Output: output, - RemoveSignatures: true, + Compress: query.Compress, + Format: query.Format, + MultiImageArchive: len(query.References) > 1, + OciAcceptUncompressedLayers: query.OciAcceptUncompressedLayers, + Output: output, + RemoveSignatures: true, } imageEngine := abi.ImageEngine{Libpod: runtime} diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 1f03e121e..9f46ecc52 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -41,8 +41,8 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { return } if !psg.NoInfra { - infraOptions := &entities.ContainerCreateOptions{ImageVolume: "bind", IsInfra: true, Net: &entities.NetOptions{}} // options for pulling the image and FillOutSpec - err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings) + infraOptions := &entities.ContainerCreateOptions{ImageVolume: "bind", IsInfra: true, Net: &entities.NetOptions{}, Devices: psg.Devices} // options for pulling the image and FillOutSpec + err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error filling out specgen")) return diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index b82c586ea..fedab3bb3 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -183,7 +183,8 @@ func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) { } is := entities.ImageSummary{ - ID: l.ID(), + // docker adds sha256: in front of the ID + ID: "sha256:" + l.ID(), ParentId: imageData.Parent, RepoTags: imageData.RepoTags, RepoDigests: imageData.RepoDigests, diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 95981226c..dce609a4e 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1150,6 +1150,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // name: compress // type: boolean // description: use compression on image + // - in: query + // name: ociAcceptUncompressedLayers + // type: boolean + // description: accept uncompressed layers when copying OCI images // produces: // - application/json // responses: diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index 894178bb9..29c234ce9 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -404,7 +404,8 @@ func newerRemoteImageAvailable(ctx context.Context, runtime *libpod.Runtime, img if err != nil { return false, err } - return img.HasDifferentDigest(ctx, remoteRef) + options := &libimage.HasDifferentDigestOptions{AuthFilePath: authfile} + return img.HasDifferentDigest(ctx, remoteRef, options) } // newerLocalImageAvailable returns true if the container and local image have different digests diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 801f5ed96..6ff9f18ec 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -65,6 +65,8 @@ type ExportOptions struct { Compress *bool // Format of the output Format *string + // Accept uncompressed layers when copying OCI images. + OciAcceptUncompressedLayers *bool } //go:generate go run ../generator/generator.go PruneOptions diff --git a/pkg/bindings/images/types_export_options.go b/pkg/bindings/images/types_export_options.go index 6229e435c..649b6814e 100644 --- a/pkg/bindings/images/types_export_options.go +++ b/pkg/bindings/images/types_export_options.go @@ -46,3 +46,18 @@ func (o *ExportOptions) GetFormat() string { } return *o.Format } + +// WithOciAcceptUncompressedLayers set field OciAcceptUncompressedLayers to given value +func (o *ExportOptions) WithOciAcceptUncompressedLayers(value bool) *ExportOptions { + o.OciAcceptUncompressedLayers = &value + return o +} + +// GetOciAcceptUncompressedLayers returns value of field OciAcceptUncompressedLayers +func (o *ExportOptions) GetOciAcceptUncompressedLayers() bool { + if o.OciAcceptUncompressedLayers == nil { + var z bool + return z + } + return *o.OciAcceptUncompressedLayers +} diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index c575212b1..edd23e662 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -301,6 +301,8 @@ type ImageSaveOptions struct { // than one image. Additional tags will be interpreted as references // to images which are added to the archive. MultiImageArchive bool + // Accept uncompressed layers when copying OCI images. + OciAcceptUncompressedLayers bool // Output - write image to the specified path. Output string // Do not save the signature from the source image diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index a74725c63..f0c88d77e 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -112,26 +112,28 @@ type PodSpec struct { PodSpecGen specgen.PodSpecGenerator } -// PodCreateOptions provides all possible options for creating a pod and its infra container +// PodCreateOptions provides all possible options for creating a pod and its infra container. +// The JSON tags below are made to match the respective field in ContainerCreateOptions for the purpose of mapping. // swagger:model PodCreateOptions type PodCreateOptions struct { - CGroupParent string - CreateCommand []string - Hostname string - Infra bool - InfraImage string - InfraName string - InfraCommand string - InfraConmonPidFile string - Labels map[string]string - Name string - Net *NetOptions - Share []string - Pid string - Cpus float64 - CpusetCpus string - Userns specgen.Namespace - Volume []string + CGroupParent string `json:"cgroup_parent,omitempty"` + CreateCommand []string `json:"create_command,omitempty"` + Devices []string `json:"devices,omitempty"` + Hostname string `json:"hostname,omitempty"` + Infra bool `json:"infra,omitempty"` + InfraImage string `json:"infra_image,omitempty"` + InfraName string `json:"container_name,omitempty"` + InfraCommand *string `json:"container_command,omitempty"` + InfraConmonPidFile string `json:"container_conmon_pidfile,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Name string `json:"name,omitempty"` + Net *NetOptions `json:"net,omitempty"` + Share []string `json:"share,omitempty"` + Pid string `json:"pid,omitempty"` + Cpus float64 `json:"cpus,omitempty"` + CpusetCpus string `json:"cpuset_cpus,omitempty"` + Userns specgen.Namespace `json:"-"` + Volume []string `json:"volume,omitempty"` } // PodLogsOptions describes the options to extract pod logs. @@ -152,24 +154,24 @@ type ContainerCreateOptions struct { CapDrop []string CgroupNS string CGroupsMode string - CGroupParent string + CGroupParent string `json:"cgroup_parent,omitempty"` CIDFile string - ConmonPIDFile string + ConmonPIDFile string `json:"container_conmon_pidfile,omitempty"` CPUPeriod uint64 CPUQuota int64 CPURTPeriod uint64 CPURTRuntime int64 CPUShares uint64 - CPUS float64 - CPUSetCPUs string + CPUS float64 `json:"cpus,omitempty"` + CPUSetCPUs string `json:"cpuset_cpus,omitempty"` CPUSetMems string - Devices []string + Devices []string `json:"devices,omitempty"` DeviceCGroupRule []string DeviceReadBPs []string DeviceReadIOPs []string DeviceWriteBPs []string DeviceWriteIOPs []string - Entrypoint *string + Entrypoint *string `json:"container_command,omitempty"` Env []string EnvHost bool EnvFile []string @@ -181,7 +183,7 @@ type ContainerCreateOptions struct { HealthRetries uint HealthStartPeriod string HealthTimeout string - Hostname string + Hostname string `json:"hostname,omitempty"` HTTPProxy bool ImageVolume string Init bool @@ -198,14 +200,14 @@ type ContainerCreateOptions struct { MemoryReservation string MemorySwap string MemorySwappiness int64 - Name string + Name string `json:"container_name,omitempty"` NoHealthCheck bool OOMKillDisable bool OOMScoreAdj int Arch string OS string Variant string - PID string + PID string `json:"pid,omitempty"` PIDsLimit *int64 Platform string Pod string @@ -244,17 +246,17 @@ type ContainerCreateOptions struct { UIDMap []string Ulimit []string User string - UserNS string + UserNS string `json:"-"` UTS string Mount []string - Volume []string + Volume []string `json:"volume,omitempty"` VolumesFrom []string Workdir string SeccompPolicy string PidFile string IsInfra bool - Net *NetOptions + Net *NetOptions `json:"net,omitempty"` CgroupConf []string } @@ -294,9 +296,10 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod s.Pid = out s.Hostname = p.Hostname s.Labels = p.Labels + s.Devices = p.Devices s.NoInfra = !p.Infra - if len(p.InfraCommand) > 0 { - s.InfraCommand = strings.Split(p.InfraCommand, " ") + if p.InfraCommand != nil && len(*p.InfraCommand) > 0 { + s.InfraCommand = strings.Split(*p.InfraCommand, " ") } if len(p.InfraConmonPidFile) > 0 { s.InfraConmonPidFile = p.InfraConmonPidFile diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index dc5f7a0df..affed64d1 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -830,21 +830,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri } return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID()) } - - if ecode, err := ctr.Wait(ctx); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - exitCode = define.ExecErrorCodeNotFound - } else { - exitCode = event.ContainerExitCode - } - } - } else { - exitCode = int(ecode) - } + exitCode = ic.GetContainerExitCode(ctx, ctr) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), RawInput: rawInput, @@ -985,21 +971,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta report.ExitCode = define.ExitCode(err) return &report, err } - - if ecode, err := ctr.Wait(ctx); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - report.ExitCode = define.ExecErrorCodeNotFound - } else { - report.ExitCode = event.ContainerExitCode - } - } - } else { - report.ExitCode = int(ecode) - } + report.ExitCode = ic.GetContainerExitCode(ctx, ctr) if opts.Rm && !ctr.ShouldRestart(ctx) { if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr || @@ -1013,6 +985,29 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta return &report, nil } +func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int { + exitCode, err := ctr.Wait(ctx) + if err == nil { + return int(exitCode) + } + if errors.Cause(err) != define.ErrNoSuchCtr { + logrus.Errorf("Could not retrieve exit code: %v", err) + return define.ExecErrorCodeNotFound + } + // Make 4 attempt with 0.25s backoff between each for 1 second total + var event *events.Event + for i := 0; i < 4; i++ { + event, err = ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) + if err != nil { + time.Sleep(250 * time.Millisecond) + continue + } + return int(event.ContainerExitCode) + } + logrus.Errorf("Could not retrieve exit code from event: %v", err) + return define.ExecErrorCodeNotFound +} + func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { if options.StdoutWriter == nil && options.StderrWriter == nil { return errors.New("no io.Writer set for container logs") diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 2d7bc15f5..1e614ce58 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -210,9 +210,7 @@ func generateKubeYAML(kubeKind interface{}) ([]byte, error) { func generateKubeOutput(content [][]byte) ([]byte, error) { output := make([]byte, 0) - header := `# Generation of Kubernetes YAML is still under development! -# -# Save the output of this file and use kubectl create -f to import + header := `# Save the output of this file and use kubectl create -f to import # it into Kubernetes. # # Created with podman-%s diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index a88d38a10..f8ee0304d 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -367,6 +367,7 @@ func (ir *ImageEngine) Load(ctx context.Context, options entities.ImageLoadOptio func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error { saveOptions := &libimage.SaveOptions{} saveOptions.DirForceCompress = options.Compress + saveOptions.OciAcceptUncompressedLayers = options.OciAcceptUncompressedLayers saveOptions.RemoveSignatures = options.RemoveSignatures if !options.Quiet { diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index db4e14aba..282770613 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -165,6 +165,9 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string if t, ok := ref.(reference.Tagged); ok { tag = t.Tag() } + if t, ok := ref.(reference.Digested); ok { + tag += "@" + t.Digest().String() + } if r, ok := ref.(reference.Named); ok { repo = r.Name() } @@ -253,6 +256,7 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, err error ) options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress) + options = options.WithOciAcceptUncompressedLayers(opts.OciAcceptUncompressedLayers) switch opts.Format { case "oci-dir", "docker-dir": diff --git a/pkg/env/env.go b/pkg/env/env.go index 0d55e5560..ecd2d62a5 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -17,8 +17,9 @@ const whiteSpaces = " \t" // DefaultEnvVariables returns a default environment, with $PATH and $TERM set. func DefaultEnvVariables() map[string]string { return map[string]string{ - "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM": "xterm", + "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM": "xterm", + "container": "podman", } } diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go index 6b9e9c4bf..2d1e2b288 100644 --- a/pkg/specgen/generate/config_linux.go +++ b/pkg/specgen/generate/config_linux.go @@ -132,7 +132,6 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error { } return nil } - return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":")) } diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 91230338e..fefa9b4a9 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -30,24 +30,27 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener // If joining a pod, retrieve the pod for use, and its infra container var pod *libpod.Pod - var cont *libpod.Container - var config *libpod.ContainerConfig + var infraConfig *libpod.ContainerConfig if s.Pod != "" { pod, err = rt.LookupPod(s.Pod) if err != nil { return nil, nil, nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod) } if pod.HasInfraContainer() { - cont, err = pod.InfraContainer() + infra, err := pod.InfraContainer() if err != nil { return nil, nil, nil, err } - config = cont.Config() + infraConfig = infra.Config() } } - if config != nil && (len(config.NamedVolumes) > 0 || len(config.UserVolumes) > 0 || len(config.ImageVolumes) > 0 || len(config.OverlayVolumes) > 0) { - s.VolumesFrom = append(s.VolumesFrom, config.ID) + if infraConfig != nil && (len(infraConfig.NamedVolumes) > 0 || len(infraConfig.UserVolumes) > 0 || len(infraConfig.ImageVolumes) > 0 || len(infraConfig.OverlayVolumes) > 0) { + s.VolumesFrom = append(s.VolumesFrom, infraConfig.ID) + } + + if infraConfig != nil && len(infraConfig.Spec.Linux.Devices) > 0 { + s.DevicesFrom = append(s.DevicesFrom, infraConfig.ID) } // Set defaults for unset namespaces if s.PidNS.IsDefault() { @@ -166,6 +169,16 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener logrus.Debugf("setting container name %s", s.Name) options = append(options, libpod.WithName(s.Name)) } + if len(s.DevicesFrom) > 0 { + for _, dev := range s.DevicesFrom { + ctr, err := rt.GetContainer(dev) + if err != nil { + return nil, nil, nil, err + } + devices := ctr.DeviceHostSrc() + s.Devices = append(s.Devices, devices...) + } + } if len(s.Devices) > 0 { opts = extractCDIDevices(s) options = append(options, opts...) @@ -174,6 +187,9 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener if err != nil { return nil, nil, nil, err } + if len(s.HostDeviceList) > 0 { + options = append(options, libpod.WithHostDevice(s.HostDeviceList)) + } return runtimeSpec, s, options, err } func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) { diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 80c7f112f..55010f716 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -301,8 +301,8 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt g.AddProcessEnv("container", "podman") g.Config.Linux.Resources = s.ResourceLimits - // Devices + if s.Privileged { // If privileged, we need to add all the host devices to the // spec. We do not add the user provided ones because we are @@ -313,17 +313,18 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } else { // add default devices from containers.conf for _, device := range rtc.Containers.Devices { - if err := DevicesFromPath(&g, device); err != nil { + if err = DevicesFromPath(&g, device); err != nil { return nil, err } } // add default devices specified by caller for _, device := range s.Devices { - if err := DevicesFromPath(&g, device.Path); err != nil { + if err = DevicesFromPath(&g, device.Path); err != nil { return nil, err } } } + s.HostDeviceList = s.Devices for _, dev := range s.DeviceCGroupRule { g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access) diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 5f72fc47d..83fa9426c 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -88,6 +88,8 @@ type PodBasicConfig struct { // Image volumes bind-mount a container-image mount into the pod's infra container. // Optional. ImageVolumes []*ImageVolume `json:"image_volumes,omitempty"` + // Devices contains user specified Devices to be added to the Pod + Devices []string `json:"pod_devices,omitempty"` } // PodNetworkConfig contains networking configuration for a pod. diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index e0609c5bc..7aa27487a 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -254,6 +254,10 @@ type ContainerStorageConfig struct { // DeviceCGroupRule are device cgroup rules that allow containers // to use additional types of devices. DeviceCGroupRule []spec.LinuxDeviceCgroup `json:"device_cgroup_rule,omitempty"` + // DevicesFrom is a way to ensure your container inherits device specific information from another container + DevicesFrom []string `json:"devices_from,omitempty"` + // HostDeviceList is used to recreate the mounted device on inherited containers + HostDeviceList []spec.LinuxDevice `json:"host_device_list,omitempty"` // IpcNS is the container's IPC namespace. // Default is private. // Conflicts with ShmSize if not set to private. |