podman/pkg/varlinkapi/containers_create.go
baude e10baba326 podman play kube: add containers to pod
when defining containers, we missed the conditional logic to allow
the container to be defined with "WithPod" and so forth.  I had to
slightly modify the createcontainer process to pass a libpod.Pod
that could override things; use nil as no pod.

Signed-off-by: baude <bbaude@redhat.com>
2019-01-11 14:01:57 -06:00

225 lines
7.2 KiB
Go

package varlinkapi
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"syscall"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/inspect"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
"github.com/docker/docker/pkg/signal"
"github.com/sirupsen/logrus"
)
// CreateContainer ...
func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error {
rtc := i.Runtime.GetConfig()
ctx := getContext()
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
data, err := newImage.Inspect(ctx)
createConfig, err := varlinkCreateToCreateConfig(ctx, config, i.Runtime, config.Image, data)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
// TODO fix when doing remote client and dealing with the ability to create a container
// within a non-existing pod (i.e. --pod new:foobar)
options, err := createConfig.GetContainerCreateOptions(i.Runtime, nil)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
ctr, err := i.Runtime.NewContainer(ctx, runtimeSpec, options...)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
createConfigJSON, err := json.Marshal(createConfig)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
logrus.Debug("new container created ", ctr.ID())
return call.ReplyCreateContainer(ctr.ID())
}
// varlinkCreateToCreateConfig takes the varlink input struct and maps it to a pointer
// of a CreateConfig, which eventually can be used to create the OCI spec.
func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
var (
inputCommand, command []string
memoryLimit, memoryReservation, memorySwap, memoryKernel int64
blkioWeight uint16
)
idmappings, err := util.ParseIDMapping(create.Uidmap, create.Gidmap, create.Subuidname, create.Subgidname)
if err != nil {
return nil, err
}
inputCommand = create.Command
entrypoint := create.Entrypoint
// ENTRYPOINT
// User input entrypoint takes priority over image entrypoint
if len(entrypoint) == 0 {
entrypoint = data.Config.Entrypoint
}
// if entrypoint=, we need to clear the entrypoint
if len(entrypoint) == 1 && strings.Join(create.Entrypoint, "") == "" {
entrypoint = []string{}
}
// Build the command
// If we have an entry point, it goes first
if len(entrypoint) > 0 {
command = entrypoint
}
if len(inputCommand) > 0 {
// User command overrides data CMD
command = append(command, inputCommand...)
} else if len(data.Config.Cmd) > 0 && len(command) == 0 {
// If not user command, add CMD
command = append(command, data.Config.Cmd...)
}
if create.Resources.Blkio_weight != 0 {
blkioWeight = uint16(create.Resources.Blkio_weight)
}
stopSignal := syscall.SIGTERM
if create.Stop_signal > 0 {
stopSignal, err = signal.ParseSignal(fmt.Sprintf("%d", create.Stop_signal))
if err != nil {
return nil, err
}
}
user := create.User
if user == "" {
user = data.Config.User
}
// EXPOSED PORTS
portBindings, err := cc.ExposedPorts(create.Exposed_ports, create.Publish, create.Publish_all, data.Config.ExposedPorts)
if err != nil {
return nil, err
}
// NETWORK MODE
networkMode := create.Net_mode
if networkMode == "" {
if rootless.IsRootless() {
networkMode = "slirp4netns"
} else {
networkMode = "bridge"
}
}
// WORKING DIR
workDir := create.Work_dir
if workDir == "" {
workDir = "/"
}
imageID := data.ID
config := &cc.CreateConfig{
Runtime: runtime,
BuiltinImgVolumes: data.Config.Volumes,
ConmonPidFile: create.Conmon_pidfile,
ImageVolumeType: create.Image_volume_type,
CapAdd: create.Cap_add,
CapDrop: create.Cap_drop,
CgroupParent: create.Cgroup_parent,
Command: command,
Detach: create.Detach,
Devices: create.Devices,
DNSOpt: create.Dns_opt,
DNSSearch: create.Dns_search,
DNSServers: create.Dns_servers,
Entrypoint: create.Entrypoint,
Env: create.Env,
GroupAdd: create.Group_add,
Hostname: create.Hostname,
HostAdd: create.Host_add,
IDMappings: idmappings,
Image: imageName,
ImageID: imageID,
Interactive: create.Interactive,
Labels: create.Labels,
LogDriver: create.Log_driver,
LogDriverOpt: create.Log_driver_opt,
Name: create.Name,
Network: networkMode,
IpcMode: namespaces.IpcMode(create.Ipc_mode),
NetMode: namespaces.NetworkMode(networkMode),
UtsMode: namespaces.UTSMode(create.Uts_mode),
PidMode: namespaces.PidMode(create.Pid_mode),
Pod: create.Pod,
Privileged: create.Privileged,
Publish: create.Publish,
PublishAll: create.Publish_all,
PortBindings: portBindings,
Quiet: create.Quiet,
ReadOnlyRootfs: create.Readonly_rootfs,
Resources: cc.CreateResourceConfig{
BlkioWeight: blkioWeight,
BlkioWeightDevice: create.Resources.Blkio_weight_device,
CPUShares: uint64(create.Resources.Cpu_shares),
CPUPeriod: uint64(create.Resources.Cpu_period),
CPUsetCPUs: create.Resources.Cpuset_cpus,
CPUsetMems: create.Resources.Cpuset_mems,
CPUQuota: create.Resources.Cpu_quota,
CPURtPeriod: uint64(create.Resources.Cpu_rt_period),
CPURtRuntime: create.Resources.Cpu_rt_runtime,
CPUs: create.Resources.Cpus,
DeviceReadBps: create.Resources.Device_read_bps,
DeviceReadIOps: create.Resources.Device_write_bps,
DeviceWriteBps: create.Resources.Device_read_iops,
DeviceWriteIOps: create.Resources.Device_write_iops,
DisableOomKiller: create.Resources.Disable_oomkiller,
ShmSize: create.Resources.Shm_size,
Memory: memoryLimit,
MemoryReservation: memoryReservation,
MemorySwap: memorySwap,
MemorySwappiness: int(create.Resources.Memory_swappiness),
KernelMemory: memoryKernel,
OomScoreAdj: int(create.Resources.Oom_score_adj),
PidsLimit: create.Resources.Pids_limit,
Ulimit: create.Resources.Ulimit,
},
Rm: create.Rm,
StopSignal: stopSignal,
StopTimeout: uint(create.Stop_timeout),
Sysctl: create.Sys_ctl,
Tmpfs: create.Tmpfs,
Tty: create.Tty,
User: user,
UsernsMode: namespaces.UsernsMode(create.Userns_mode),
Volumes: create.Volumes,
WorkDir: workDir,
}
return config, nil
}