summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/libpod/pods.go1
-rw-r--r--pkg/domain/entities/engine_image.go2
-rw-r--r--pkg/domain/entities/images.go36
-rw-r--r--pkg/domain/entities/pods.go4
-rw-r--r--pkg/domain/infra/abi/images.go179
-rw-r--r--pkg/domain/infra/tunnel/images.go2
-rw-r--r--pkg/rootless/rootless_linux.c2
-rw-r--r--pkg/specgen/generate/container_create.go111
-rw-r--r--pkg/specgen/generate/oci.go37
-rw-r--r--pkg/specgen/podspecgen.go5
10 files changed, 254 insertions, 125 deletions
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 3d18406a5..1b29831b4 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -42,6 +42,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
infraOptions := entities.NewInfraContainerCreateOptions() // options for pulling the image and FillOutSpec
infraOptions.Net = &entities.NetOptions{}
infraOptions.Devices = psg.Devices
+ infraOptions.SecurityOpt = psg.SecurityOpt
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"))
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index d72f64b5e..bec505163 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -27,7 +27,7 @@ type ImageEngine interface {
ShowTrust(ctx context.Context, args []string, options ShowTrustOptions) (*ShowTrustReport, error)
Shutdown(ctx context.Context)
Tag(ctx context.Context, nameOrID string, tags []string, options ImageTagOptions) error
- Transfer(ctx context.Context, scpOpts ImageScpOptions) error
+ Transfer(ctx context.Context, source ImageScpOptions, dest ImageScpOptions, parentFlags []string) error
Tree(ctx context.Context, nameOrID string, options ImageTreeOptions) (*ImageTreeReport, error)
Unmount(ctx context.Context, images []string, options ImageUnmountOptions) ([]*ImageUnmountReport, error)
Untag(ctx context.Context, nameOrID string, tags []string, options ImageUntagOptions) error
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 8b0fd2b85..62e7f67c8 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -311,30 +311,28 @@ type ImageSaveOptions struct {
Quiet bool
}
-// ImageScpOptions provide options for securely copying images to podman remote
+// ImageScpOptions provide options for securely copying images to and from a remote host
type ImageScpOptions struct {
- // SoureImageName is the image the user is providing to load on a remote machine
- SourceImageName string
- // Tag allows for a new image to be created under the given name
- Tag string
- // ToRemote specifies that we are loading to the remote host
- ToRemote bool
- // FromRemote specifies that we are loading from the remote host
- FromRemote bool
+ // Remote determines if this entity is operating on a remote machine
+ Remote bool `json:"remote,omitempty"`
+ // File is the input/output file for the save and load Operation
+ File string `json:"file,omitempty"`
+ // Quiet Determines if the save and load operation will be done quietly
+ Quiet bool `json:"quiet,omitempty"`
+ // Image is the image the user is providing to save and load
+ Image string `json:"image,omitempty"`
+ // User is used in conjunction with Transfer to determine if a valid user was given to save from/load into
+ User string `json:"user,omitempty"`
+}
+
+// ImageScpConnections provides the ssh related information used in remote image transfer
+type ImageScpConnections struct {
// Connections holds the raw string values for connections (ssh or unix)
Connections []string
// URI contains the ssh connection URLs to be used by the client
URI []*url.URL
- // Iden contains ssh identity keys to be used by the client
- Iden []string
- // Save Options used for first half of the scp operation
- Save ImageSaveOptions
- // Load options used for the second half of the scp operation
- Load ImageLoadOptions
- // Rootless determines whether we are loading locally from root storage to rootless storage
- Rootless bool
- // User is used in conjunction with Rootless to determine which user to use to obtain the uid
- User string
+ // Identities contains ssh identity keys to be used by the client
+ Identities []string
}
// ImageTreeOptions provides options for ImageEngine.Tree()
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index f9850e5a8..1b5a1be51 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -138,6 +138,7 @@ type PodCreateOptions struct {
Userns specgen.Namespace `json:"-"`
Volume []string `json:"volume,omitempty"`
VolumesFrom []string `json:"volumes_from,omitempty"`
+ SecurityOpt []string `json:"security_opt,omitempty"`
}
// PodLogsOptions describes the options to extract pod logs.
@@ -230,7 +231,7 @@ type ContainerCreateOptions struct {
Rm bool
RootFS bool
Secrets []string
- SecurityOpt []string
+ SecurityOpt []string `json:"security_opt,omitempty"`
SdNotifyMode string
ShmSize string
SignaturePolicy string
@@ -312,6 +313,7 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
s.Hostname = p.Hostname
s.Labels = p.Labels
s.Devices = p.Devices
+ s.SecurityOpt = p.SecurityOpt
s.NoInfra = !p.Infra
if p.InfraCommand != nil && len(*p.InfraCommand) > 0 {
s.InfraCommand = strings.Split(*p.InfraCommand, " ")
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 4346182d6..84c83ea8e 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -28,6 +28,7 @@ import (
domainUtils "github.com/containers/podman/v3/pkg/domain/utils"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/podman/v3/utils"
"github.com/containers/storage"
dockerRef "github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
@@ -351,65 +352,19 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
return pushError
}
-// Transfer moves images from root to rootless storage so the user specified in the scp call can access and use the image modified by root
-func (ir *ImageEngine) Transfer(ctx context.Context, scpOpts entities.ImageScpOptions) error {
- if scpOpts.User == "" {
+// Transfer moves images between root and rootless storage so the user specified in the scp call can access and use the image modified by root
+func (ir *ImageEngine) Transfer(ctx context.Context, source entities.ImageScpOptions, dest entities.ImageScpOptions, parentFlags []string) error {
+ if source.User == "" {
return errors.Wrapf(define.ErrInvalidArg, "you must define a user when transferring from root to rootless storage")
}
- var u *user.User
- scpOpts.User = strings.Split(scpOpts.User, ":")[0] // split in case provided with uid:gid
- _, err := strconv.Atoi(scpOpts.User)
- if err != nil {
- u, err = user.Lookup(scpOpts.User)
- if err != nil {
- return err
- }
- } else {
- u, err = user.LookupId(scpOpts.User)
- if err != nil {
- return err
- }
- }
- uid, err := strconv.Atoi(u.Uid)
- if err != nil {
- return err
- }
- gid, err := strconv.Atoi(u.Gid)
- if err != nil {
- return err
- }
- err = os.Chown(scpOpts.Save.Output, uid, gid) // chown the output because was created by root so we need to give th euser read access
- if err != nil {
- return err
- }
-
podman, err := os.Executable()
if err != nil {
return err
}
- machinectl, err := exec.LookPath("machinectl")
- if err != nil {
- logrus.Warn("defaulting to su since machinectl is not available, su will fail if no user session is available")
- cmd := exec.Command("su", "-l", u.Username, "--command", podman+" --log-level="+logrus.GetLevel().String()+" --cgroup-manager=cgroupfs load --input="+scpOpts.Save.Output) // load the new image to the rootless storage
- cmd.Stderr = os.Stderr
- cmd.Stdout = os.Stdout
- logrus.Debug("Executing load command su")
- err = cmd.Run()
- if err != nil {
- return err
- }
- } else {
- cmd := exec.Command(machinectl, "shell", "-q", u.Username+"@.host", podman, "--log-level="+logrus.GetLevel().String(), "--cgroup-manager=cgroupfs", "load", "--input", scpOpts.Save.Output) // load the new image to the rootless storage
- cmd.Stderr = os.Stderr
- cmd.Stdout = os.Stdout
- logrus.Debug("Executing load command machinectl")
- err = cmd.Run()
- if err != nil {
- return err
- }
+ if rootless.IsRootless() && (len(dest.User) == 0 || dest.User == "root") { // if we are rootless and do not have a destination user we can just use sudo
+ return transferRootless(source, dest, podman, parentFlags)
}
-
- return nil
+ return transferRootful(source, dest, podman, parentFlags)
}
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
@@ -786,3 +741,123 @@ func putSignature(manifestBlob []byte, mech signature.SigningMechanism, sigStore
}
return nil
}
+
+// TransferRootless creates new podman processes using exec.Command and sudo, transferring images between the given source and destination users
+func transferRootless(source entities.ImageScpOptions, dest entities.ImageScpOptions, podman string, parentFlags []string) error {
+ var cmdSave *exec.Cmd
+ saveCommand := parentFlags
+ saveCommand = append(saveCommand, []string{"save", "--output", source.File, source.Image}...)
+
+ loadCommand := parentFlags
+ loadCommand = append(loadCommand, []string{"load", "--input", dest.File}...)
+
+ if source.User == "root" {
+ cmdSave = exec.Command("sudo", podman)
+ } else {
+ cmdSave = exec.Command(podman)
+ }
+ cmdSave = utils.CreateSCPCommand(cmdSave, saveCommand)
+ logrus.Debug("Executing save command")
+ err := cmdSave.Run()
+ if err != nil {
+ return err
+ }
+
+ var cmdLoad *exec.Cmd
+ if source.User != "root" {
+ cmdLoad = exec.Command("sudo", podman)
+ } else {
+ cmdLoad = exec.Command(podman)
+ }
+ cmdLoad = utils.CreateSCPCommand(cmdLoad, loadCommand)
+ logrus.Debug("Executing load command")
+ err = cmdLoad.Run()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// TransferRootless creates new podman processes using exec.Command and su/machinectl, transferring images between the given source and destination users
+func transferRootful(source entities.ImageScpOptions, dest entities.ImageScpOptions, podman string, parentFlags []string) error {
+ basicCommand := []string{podman}
+ basicCommand = append(basicCommand, parentFlags...)
+ saveCommand := append(basicCommand, []string{"save", "--output", source.File, source.Image}...)
+ loadCommand := append(basicCommand, []string{"load", "--input", dest.File}...)
+ save := []string{strings.Join(saveCommand, " ")}
+ load := []string{strings.Join(loadCommand, " ")}
+
+ // if executing using sudo or transferring between two users, the TransferRootless approach will not work, default to using machinectl or su as necessary.
+ // the approach using sudo is preferable and more straightforward. There is no reason for using sudo in these situations
+ // since the feature is meant to transfer from root to rootless an vice versa without explicit sudo evocaiton.
+ var uSave *user.User
+ var uLoad *user.User
+ var err error
+ source.User = strings.Split(source.User, ":")[0] // split in case provided with uid:gid
+ dest.User = strings.Split(dest.User, ":")[0]
+ uSave, err = lookupUser(source.User)
+ if err != nil {
+ return err
+ }
+ switch {
+ case dest.User != "": // if we are given a destination user, check that first
+ uLoad, err = lookupUser(dest.User)
+ if err != nil {
+ return err
+ }
+ case uSave.Name != "root": // else if we have no destination user, and source is not root that means we should be root
+ uLoad, err = user.LookupId("0")
+ if err != nil {
+ return err
+ }
+ default: // else if we have no dest user, and source user IS root, we want to be the default user.
+ uString := os.Getenv("SUDO_USER")
+ if uString == "" {
+ return errors.New("$SUDO_USER must be defined to find the default rootless user")
+ }
+ uLoad, err = user.Lookup(uString)
+ if err != nil {
+ return err
+ }
+ }
+ machinectl, err := exec.LookPath("machinectl")
+ if err != nil {
+ logrus.Warn("defaulting to su since machinectl is not available, su will fail if no user session is available")
+ err = execSu(uSave, save)
+ if err != nil {
+ return err
+ }
+ return execSu(uLoad, load)
+ }
+ err = execMachine(uSave, saveCommand, machinectl)
+ if err != nil {
+ return err
+ }
+ return execMachine(uLoad, loadCommand, machinectl)
+}
+
+func lookupUser(u string) (*user.User, error) {
+ if u, err := user.LookupId(u); err == nil {
+ return u, nil
+ }
+ return user.Lookup(u)
+}
+
+func execSu(execUser *user.User, command []string) error {
+ cmd := exec.Command("su", "-l", execUser.Username, "--command")
+ cmd = utils.CreateSCPCommand(cmd, command)
+ logrus.Debug("Executing command su")
+ return cmd.Run()
+}
+
+func execMachine(execUser *user.User, command []string, machinectl string) error {
+ var cmd *exec.Cmd
+ if execUser.Uid == "0" {
+ cmd = exec.Command("sudo", machinectl, "shell", "-q", execUser.Username+"@.host")
+ } else {
+ cmd = exec.Command(machinectl, "shell", "-q", execUser.Username+"@.host")
+ }
+ cmd = utils.CreateSCPCommand(cmd, command)
+ logrus.Debug("Executing command machinectl")
+ return cmd.Run()
+}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 2feb9d7ad..f26a489e6 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -123,7 +123,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.
return &entities.ImagePullReport{Images: pulledImages}, nil
}
-func (ir *ImageEngine) Transfer(ctx context.Context, scpOpts entities.ImageScpOptions) error {
+func (ir *ImageEngine) Transfer(ctx context.Context, source entities.ImageScpOptions, dest entities.ImageScpOptions, parentFlags []string) error {
return errors.Wrapf(define.ErrNotImplemented, "cannot use the remote client to transfer images between root and rootless storage")
}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 92f331ce4..94bd40f86 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -244,7 +244,7 @@ can_use_shortcut ()
if (argv[argc+1] != NULL && (strcmp (argv[argc], "container") == 0 ||
strcmp (argv[argc], "image") == 0) &&
- strcmp (argv[argc+1], "mount") == 0)
+ (strcmp (argv[argc+1], "mount") == 0 || strcmp (argv[argc+1], "scp") == 0))
{
ret = false;
break;
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 7ab9d1b29..7d792b3b1 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -2,13 +2,14 @@ package generate
import (
"context"
- "fmt"
+ "encoding/json"
"path/filepath"
"strings"
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg"
"github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
@@ -29,43 +30,30 @@ 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 infraConfig *libpod.ContainerConfig
+ var infra *libpod.Container
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() {
- infra, err := pod.InfraContainer()
+ infra, err = pod.InfraContainer()
if err != nil {
return nil, nil, nil, err
}
- infraConfig = infra.Config()
}
}
- 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)
- }
- if infraConfig != nil && infraConfig.Spec.Linux.Resources != nil && infraConfig.Spec.Linux.Resources.BlockIO != nil && len(infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) > 0 {
- tempDev := make(map[string]spec.LinuxThrottleDevice)
- for _, val := range infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice {
- nodes, err := util.FindDeviceNodes()
- if err != nil {
- return nil, nil, nil, err
- }
- key := fmt.Sprintf("%d:%d", val.Major, val.Minor)
- tempDev[nodes[key]] = spec.LinuxThrottleDevice{Rate: uint64(val.Rate)}
- }
- for i, dev := range s.ThrottleReadBpsDevice {
- tempDev[i] = dev
+ options := []libpod.CtrCreateOption{}
+ compatibleOptions := &libpod.InfraInherit{}
+ var infraSpec *spec.Spec
+ if infra != nil {
+ options, infraSpec, compatibleOptions, err = Inherit(*infra)
+ if err != nil {
+ return nil, nil, nil, err
}
- s.ThrottleReadBpsDevice = tempDev
}
+
if err := FinishThrottleDevices(s); err != nil {
return nil, nil, nil, err
}
@@ -119,8 +107,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
s.CgroupNS = defaultNS
}
- options := []libpod.CtrCreateOption{}
-
if s.ContainerCreateCommand != nil {
options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
}
@@ -165,7 +151,8 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, nil, nil, err
}
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command)
+ infraVolumes := (len(compatibleOptions.InfraVolumes) > 0 || len(compatibleOptions.InfraUserVolumes) > 0 || len(compatibleOptions.InfraImageVolumes) > 0)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command, infraVolumes, *compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
@@ -178,27 +165,29 @@ 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)
+ opts = ExtractCDIDevices(s)
options = append(options, opts...)
}
- runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command)
+ runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command, compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
if len(s.HostDeviceList) > 0 {
options = append(options, libpod.WithHostDevice(s.HostDeviceList))
}
+ if infraSpec != nil && infraSpec.Linux != nil { // if we are inheriting Linux info from a pod...
+ // Pass Security annotations
+ if len(infraSpec.Annotations[define.InspectAnnotationLabel]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationLabel]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationLabel] = infraSpec.Annotations[define.InspectAnnotationLabel]
+ }
+ if len(infraSpec.Annotations[define.InspectAnnotationSeccomp]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationSeccomp]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationSeccomp] = infraSpec.Annotations[define.InspectAnnotationSeccomp]
+ }
+ if len(infraSpec.Annotations[define.InspectAnnotationApparmor]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationApparmor]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationApparmor] = infraSpec.Annotations[define.InspectAnnotationApparmor]
+ }
+ }
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) {
@@ -210,7 +199,7 @@ func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Sp
return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr)
}
-func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
+func ExtractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
devs := make([]spec.LinuxDevice, 0, len(s.Devices))
var cdiDevs []string
var options []libpod.CtrCreateOption
@@ -224,19 +213,16 @@ func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
cdiDevs = append(cdiDevs, device.Path)
continue
}
-
devs = append(devs, device)
}
-
s.Devices = devs
if len(cdiDevs) > 0 {
options = append(options, libpod.WithCDI(cdiDevs))
}
-
return options
}
-func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string) ([]libpod.CtrCreateOption, error) {
+func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string, infraVolumes bool, compatibleOptions libpod.InfraInherit) ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
var err error
@@ -317,7 +303,10 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
for _, imageVolume := range s.ImageVolumes {
destinations = append(destinations, imageVolume.Destination)
}
- options = append(options, libpod.WithUserVolumes(destinations))
+
+ if len(destinations) > 0 || !infraVolumes {
+ options = append(options, libpod.WithUserVolumes(destinations))
+ }
if len(volumes) != 0 {
var vols []*libpod.ContainerNamedVolume
@@ -405,7 +394,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if len(s.SelinuxOpts) > 0 {
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
} else {
- if pod != nil {
+ if pod != nil && len(compatibleOptions.InfraLabels) == 0 {
// duplicate the security options from the pod
processLabel, err := pod.ProcessLabel()
if err != nil {
@@ -498,3 +487,33 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
return options, nil
}
+
+func Inherit(infra libpod.Container) (opts []libpod.CtrCreateOption, infraS *spec.Spec, compat *libpod.InfraInherit, err error) {
+ options := []libpod.CtrCreateOption{}
+ compatibleOptions := &libpod.InfraInherit{}
+ infraConf := infra.Config()
+ infraSpec := infraConf.Spec
+
+ config, err := json.Marshal(infraConf)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ err = json.Unmarshal(config, compatibleOptions)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if infraSpec.Linux != nil && infraSpec.Linux.Resources != nil {
+ resources, err := json.Marshal(infraSpec.Linux.Resources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ err = json.Unmarshal(resources, &compatibleOptions.InfraResources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ }
+ if compatibleOptions != nil {
+ options = append(options, libpod.WithInfraConfig(*compatibleOptions))
+ }
+ return options, infraSpec, compatibleOptions, nil
+}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index efac53104..ee3a990fc 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -2,6 +2,7 @@ package generate
import (
"context"
+ "encoding/json"
"path"
"strings"
@@ -174,7 +175,7 @@ func getCGroupPermissons(unmask []string) string {
}
// SpecGenToOCI returns the base configuration for the container.
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) {
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
cgroupPerm := getCGroupPermissons(s.Unmask)
g, err := generate.New("linux")
@@ -299,9 +300,32 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
g.AddAnnotation(key, val)
}
- g.Config.Linux.Resources = s.ResourceLimits
+ if compatibleOptions.InfraResources == nil && s.ResourceLimits != nil {
+ g.Config.Linux.Resources = s.ResourceLimits
+ } else if s.ResourceLimits != nil { // if we have predefined resource limits we need to make sure we keep the infra and container limits
+ originalResources, err := json.Marshal(s.ResourceLimits)
+ if err != nil {
+ return nil, err
+ }
+ infraResources, err := json.Marshal(compatibleOptions.InfraResources)
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(infraResources, s.ResourceLimits) // put infra's resource limits in the container
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(originalResources, s.ResourceLimits) // make sure we did not override anything
+ if err != nil {
+ return nil, err
+ }
+ g.Config.Linux.Resources = s.ResourceLimits
+ } else {
+ g.Config.Linux.Resources = compatibleOptions.InfraResources
+ }
// Devices
+ var userDevices []spec.LinuxDevice
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
@@ -316,14 +340,19 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
return nil, err
}
}
+ if len(compatibleOptions.InfraDevices) > 0 && len(s.Devices) == 0 {
+ userDevices = compatibleOptions.InfraDevices
+ } else {
+ userDevices = s.Devices
+ }
// add default devices specified by caller
- for _, device := range s.Devices {
+ for _, device := range userDevices {
if err = DevicesFromPath(&g, device.Path); err != nil {
return nil, err
}
}
}
- s.HostDeviceList = s.Devices
+ s.HostDeviceList = userDevices
// set the devices cgroup when not running in a user namespace
if !inUserNS && !s.Privileged {
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index e59d11c0a..33e8422fd 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -196,6 +196,7 @@ type PodSpecGenerator struct {
PodCgroupConfig
PodResourceConfig
PodStorageConfig
+ PodSecurityConfig
InfraContainerSpec *SpecGenerator `json:"-"`
}
@@ -210,6 +211,10 @@ type PodResourceConfig struct {
ThrottleReadBpsDevice map[string]spec.LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
}
+type PodSecurityConfig struct {
+ SecurityOpt []string `json:"security_opt,omitempty"`
+}
+
// NewPodSpecGenerator creates a new pod spec
func NewPodSpecGenerator() *PodSpecGenerator {
return &PodSpecGenerator{}