podman-remote create|run

add the ability to create and run containers via the podman-remote
client.

we now create an intermediate layer from the the create/run cli flags.
the intermediate layer can be converted into a createconfig or into a
varlink struct.  Once transported, the varlink struct can be converted
back to an intermediate layer and then to a createconfig.

remote terminals are not supported yet.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2019-03-20 13:00:34 -05:00
parent d86729e743
commit ba65301c95
33 changed files with 1630 additions and 859 deletions

239
API.md
View File

@ -27,6 +27,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func CreateContainer(create: Create) string](#CreateContainer)
[func CreateFromCC(in: []string) string](#CreateFromCC)
[func CreatePod(create: PodCreate) string](#CreatePod)
[func DeleteStoppedContainers() []string](#DeleteStoppedContainers)
@ -177,16 +179,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type Create](#Create)
[type CreateResourceConfig](#CreateResourceConfig)
[type DiffInfo](#DiffInfo)
[type Event](#Event)
[type IDMap](#IDMap)
[type IDMappingOptions](#IDMappingOptions)
[type Image](#Image)
[type ImageHistory](#ImageHistory)
@ -338,16 +334,12 @@ development of Podman only and generally should not be used.
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method CreateContainer(create: [Create](#Create)) [string](https://godoc.org/builtin#string)</div>
CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. The minimum
input required for CreateContainer is an image name. If the image name is not found, an [ImageNotFound](#ImageNotFound)
error will be returned. Otherwise, the ID of the newly created container will be returned.
#### Example
~~~
$ varlink call unix:/run/podman/io.podman/io.podman.CreateContainer '{"create": {"image": "alpine"}}'
{
"container": "8759dafbc0a4dc3bcfb57eeb72e4331eb73c5cc09ab968e65ce45b9ad5c4b6bb"
}
~~~
CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input.
### <a name="CreateFromCC"></a>func CreateFromCC
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method CreateFromCC(in: [[]string](#[]string)) [string](https://godoc.org/builtin#string)</div>
This call is for the development of Podman only and should not be used.
### <a name="CreatePod"></a>func CreatePod
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@ -1272,188 +1264,199 @@ block_input [int](https://godoc.org/builtin#int)
pids [int](https://godoc.org/builtin#int)
### <a name="Create"></a>type Create
Create is an input structure for creating containers. It closely resembles the
CreateConfig structure in libpod/pkg/spec.
Create is an input structure for creating containers.
args [[]string](#[]string)
cap_add [[]string](#[]string)
addHost [](#)
cap_drop [[]string](#[]string)
annotation [](#)
conmon_pidfile [string](https://godoc.org/builtin#string)
attach [](#)
cgroup_parent [string](https://godoc.org/builtin#string)
blkioWeight [](#)
command [[]string](#[]string)
blkioWeightDevice [](#)
detach [bool](https://godoc.org/builtin#bool)
capAdd [](#)
devices [[]string](#[]string)
capDrop [](#)
dns_opt [[]string](#[]string)
cgroupParent [](#)
dns_search [[]string](#[]string)
cidFile [](#)
dns_servers [[]string](#[]string)
conmonPidfile [](#)
entrypoint [[]string](#[]string)
command [](#)
env [map[string]](#map[string])
cpuPeriod [](#)
exposed_ports [[]string](#[]string)
cpuQuota [](#)
gidmap [[]string](#[]string)
cpuRtPeriod [](#)
group_add [[]string](#[]string)
cpuRtRuntime [](#)
host_add [[]string](#[]string)
cpuShares [](#)
hostname [string](https://godoc.org/builtin#string)
cpus [](#)
image [string](https://godoc.org/builtin#string)
cpuSetCpus [](#)
image_id [string](https://godoc.org/builtin#string)
cpuSetMems [](#)
init [bool](https://godoc.org/builtin#bool)
detach [](#)
init_path [string](https://godoc.org/builtin#string)
detachKeys [](#)
builtin_imgvolumes [[]string](#[]string)
device [](#)
id_mappings [IDMappingOptions](#IDMappingOptions)
deviceReadBps [](#)
image_volume_type [string](https://godoc.org/builtin#string)
deviceReadIops [](#)
interactive [bool](https://godoc.org/builtin#bool)
deviceWriteBps [](#)
ipc_mode [string](https://godoc.org/builtin#string)
deviceWriteIops [](#)
labels [map[string]](#map[string])
dns [](#)
log_driver [string](https://godoc.org/builtin#string)
dnsOpt [](#)
log_driver_opt [[]string](#[]string)
dnsSearch [](#)
name [string](https://godoc.org/builtin#string)
dnsServers [](#)
net_mode [string](https://godoc.org/builtin#string)
entrypoint [](#)
network [string](https://godoc.org/builtin#string)
env [](#)
pid_mode [string](https://godoc.org/builtin#string)
envFile [](#)
pod [string](https://godoc.org/builtin#string)
expose [](#)
privileged [bool](https://godoc.org/builtin#bool)
gidmap [](#)
publish [[]string](#[]string)
groupadd [](#)
publish_all [bool](https://godoc.org/builtin#bool)
healthcheckCommand [](#)
quiet [bool](https://godoc.org/builtin#bool)
healthcheckInterval [](#)
readonly_rootfs [bool](https://godoc.org/builtin#bool)
healthcheckRetries [](#)
resources [CreateResourceConfig](#CreateResourceConfig)
healthcheckStartPeriod [](#)
rm [bool](https://godoc.org/builtin#bool)
healthcheckTimeout [](#)
shm_dir [string](https://godoc.org/builtin#string)
hostname [](#)
stop_signal [int](https://godoc.org/builtin#int)
imageVolume [](#)
stop_timeout [int](https://godoc.org/builtin#int)
init [](#)
subuidmap [string](https://godoc.org/builtin#string)
initPath [](#)
subgidmap [string](https://godoc.org/builtin#string)
interactive [](#)
subuidname [string](https://godoc.org/builtin#string)
ip [](#)
subgidname [string](https://godoc.org/builtin#string)
ipc [](#)
sys_ctl [map[string]](#map[string])
kernelMemory [](#)
tmpfs [[]string](#[]string)
label [](#)
tty [bool](https://godoc.org/builtin#bool)
labelFile [](#)
uidmap [[]string](#[]string)
logDriver [](#)
userns_mode [string](https://godoc.org/builtin#string)
logOpt [](#)
user [string](https://godoc.org/builtin#string)
macAddress [](#)
uts_mode [string](https://godoc.org/builtin#string)
memory [](#)
volumes [[]string](#[]string)
memoryReservation [](#)
work_dir [string](https://godoc.org/builtin#string)
memorySwap [](#)
mount_label [string](https://godoc.org/builtin#string)
memorySwappiness [](#)
process_label [string](https://godoc.org/builtin#string)
name [](#)
no_new_privs [bool](https://godoc.org/builtin#bool)
net [](#)
apparmor_profile [string](https://godoc.org/builtin#string)
network [](#)
seccomp_profile_path [string](https://godoc.org/builtin#string)
noHosts [](#)
security_opts [[]string](#[]string)
### <a name="CreateResourceConfig"></a>type CreateResourceConfig
oomKillDisable [](#)
CreateResourceConfig is an input structure used to describe host attributes during
container creation. It is only valid inside a [Create](#Create) type.
oomScoreAdj [](#)
blkio_weight [int](https://godoc.org/builtin#int)
pid [](#)
blkio_weight_device [[]string](#[]string)
pidsLimit [](#)
cpu_period [int](https://godoc.org/builtin#int)
pod [](#)
cpu_quota [int](https://godoc.org/builtin#int)
privileged [](#)
cpu_rt_period [int](https://godoc.org/builtin#int)
publish [](#)
cpu_rt_runtime [int](https://godoc.org/builtin#int)
publishAll [](#)
cpu_shares [int](https://godoc.org/builtin#int)
quiet [](#)
cpus [float](https://golang.org/src/builtin/builtin.go#L58)
readonly [](#)
cpuset_cpus [string](https://godoc.org/builtin#string)
restart [](#)
cpuset_mems [string](https://godoc.org/builtin#string)
rm [](#)
device_read_bps [[]string](#[]string)
rootfs [](#)
device_read_iops [[]string](#[]string)
securityOpt [](#)
device_write_bps [[]string](#[]string)
shmSize [](#)
device_write_iops [[]string](#[]string)
stopSignal [](#)
disable_oomkiller [bool](https://godoc.org/builtin#bool)
stopTimeout [](#)
kernel_memory [int](https://godoc.org/builtin#int)
storageOpt [](#)
memory [int](https://godoc.org/builtin#int)
subuidname [](#)
memory_reservation [int](https://godoc.org/builtin#int)
subgidname [](#)
memory_swap [int](https://godoc.org/builtin#int)
sysctl [](#)
memory_swappiness [int](https://godoc.org/builtin#int)
systemd [](#)
oom_score_adj [int](https://godoc.org/builtin#int)
tmpfs [](#)
pids_limit [int](https://godoc.org/builtin#int)
tty [](#)
shm_size [int](https://godoc.org/builtin#int)
uidmap [](#)
ulimit [[]string](#[]string)
ulimit [](#)
user [](#)
userns [](#)
uts [](#)
mount [](#)
volume [](#)
volumesFrom [](#)
workDir [](#)
### <a name="DiffInfo"></a>type DiffInfo
@ -1476,26 +1479,6 @@ status [string](https://godoc.org/builtin#string)
time [string](https://godoc.org/builtin#string)
type [string](https://godoc.org/builtin#string)
### <a name="IDMap"></a>type IDMap
IDMap is used to describe user name spaces during container creation
container_id [int](https://godoc.org/builtin#int)
host_id [int](https://godoc.org/builtin#int)
size [int](https://godoc.org/builtin#int)
### <a name="IDMappingOptions"></a>type IDMappingOptions
IDMappingOptions is an input structure used to described ids during container creation.
host_uid_mapping [bool](https://godoc.org/builtin#bool)
host_gid_mapping [bool](https://godoc.org/builtin#bool)
uid_map [IDMap](#IDMap)
gid_map [IDMap](#IDMap)
### <a name="Image"></a>type Image

View File

@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -78,7 +79,7 @@ func attachCmd(c *cliconfig.AttachValues) error {
}
// If the container is in a pod, also set to recursively start dependencies
if err := startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != libpod.ErrDetach {
if err := adapter.StartAttachCtr(getContext(), ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != libpod.ErrDetach {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}

View File

@ -0,0 +1,21 @@
package cliconfig
const (
// DefaultSystemD value
DefaultSystemD bool = true
)
var (
// DefaultHealthCheckInterval default value
DefaultHealthCheckInterval = "30s"
// DefaultHealthCheckRetries default value
DefaultHealthCheckRetries uint = 3
// DefaultHealthCheckStartPeriod default value
DefaultHealthCheckStartPeriod = "0s"
// DefaultHealthCheckTimeout default value
DefaultHealthCheckTimeout = "30s"
// DefaultImageVolume default value
DefaultImageVolume = "bind"
// DefaultShmSize default value
DefaultShmSize = "65536k"
)

View File

@ -13,7 +13,6 @@ func getMainCommands() []*cobra.Command {
rootCommands := []*cobra.Command{
_attachCommand,
_commitCommand,
_createCommand,
_execCommand,
_generateCommand,
_playCommand,
@ -26,7 +25,6 @@ func getMainCommands() []*cobra.Command {
_refreshCommand,
_restartCommand,
_rmCommand,
_runCommand,
_searchCommand,
_startCommand,
_statsCommand,
@ -56,7 +54,6 @@ func getContainerSubCommands() []*cobra.Command {
_checkpointCommand,
_cleanupCommand,
_commitCommand,
_createCommand,
_execCommand,
_exportCommand,
_killCommand,
@ -68,7 +65,6 @@ func getContainerSubCommands() []*cobra.Command {
_restartCommand,
_restoreCommand,
_rmCommand,
_runCommand,
_runlabelCommand,
_startCommand,
_statsCommand,

View File

@ -294,19 +294,19 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"set a healthcheck command for the container ('none' disables the existing healthcheck)",
)
createFlags.String(
"healthcheck-interval", "30s",
"healthcheck-interval", cliconfig.DefaultHealthCheckInterval,
"set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
)
createFlags.Uint(
"healthcheck-retries", 3,
"healthcheck-retries", cliconfig.DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
createFlags.String(
"healthcheck-start-period", "0s",
"healthcheck-start-period", cliconfig.DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
createFlags.String(
"healthcheck-timeout", "30s",
"healthcheck-timeout", cliconfig.DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
createFlags.StringP(
@ -314,7 +314,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Set container hostname",
)
createFlags.String(
"image-volume", "bind",
"image-volume", cliconfig.DefaultImageVolume,
"Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore'",
)
createFlags.Bool(
@ -451,7 +451,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Security Options (default [])",
)
createFlags.String(
"shm-size", "65536k",
"shm-size", cliconfig.DefaultShmSize,
"Size of `/dev/shm`. The format is `<number><unit>`",
)
createFlags.String(
@ -480,7 +480,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Sysctl options (default [])",
)
createFlags.Bool(
"systemd", true,
"systemd", cliconfig.DefaultSystemD,
"Run container in systemd mode if the command executable is systemd or init",
)
createFlags.StringSlice(

View File

@ -53,8 +53,10 @@ var (
_containerExistsCommand,
_contInspectSubCommand,
_diffCommand,
_createCommand,
_listSubCommand,
_logsCommand,
_runCommand,
}
)

View File

@ -4,8 +4,7 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/pkg/adapter"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -52,18 +51,17 @@ func createCmd(c *cliconfig.CreateValues) error {
return err
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
ctr, _, err := shared.CreateContainer(getContext(), &c.PodmanCommand, runtime)
cid, err := runtime.CreateContainer(getContext(), c)
if err != nil {
return err
}
fmt.Printf("%s\n", ctr.ID())
fmt.Printf("%s\n", cid)
return nil
}

View File

@ -40,6 +40,7 @@ var (
var mainCommands = []*cobra.Command{
_buildCommand,
_diffCommand,
_createCommand,
_eventsCommand,
_exportCommand,
_historyCommand,
@ -54,6 +55,7 @@ var mainCommands = []*cobra.Command{
_pullCommand,
_pushCommand,
&_rmiCommand,
_runCommand,
_saveCommand,
_stopCommand,
_tagCommand,

View File

@ -1,20 +1,10 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
opentracing "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -57,143 +47,12 @@ func runCmd(c *cliconfig.RunValues) error {
return err
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
ctr, createConfig, err := shared.CreateContainer(getContext(), &c.PodmanCommand, runtime)
if err != nil {
exitCode, err = runtime.Run(getContext(), c, exitCode)
return err
}
if logrus.GetLevel() == logrus.DebugLevel {
cgroupPath, err := ctr.CGroupPath()
if err == nil {
logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
}
}
ctx := getContext()
// Handle detached start
if createConfig.Detach {
// if the container was created as part of a pod, also start its dependencies, if any.
if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
exitCode = 126
}
return err
}
fmt.Printf("%s\n", ctr.ID())
exitCode = 0
return nil
}
outputStream := os.Stdout
errorStream := os.Stderr
inputStream := os.Stdin
// If -i is not set, clear stdin
if !c.Bool("interactive") {
inputStream = nil
}
// If attach is set, clear stdin/stdout/stderr and only attach requested
if c.IsSet("attach") || c.IsSet("a") {
outputStream = nil
errorStream = nil
if !c.Bool("interactive") {
inputStream = nil
}
attachTo := c.StringSlice("attach")
for _, stream := range attachTo {
switch strings.ToLower(stream) {
case "stdout":
outputStream = os.Stdout
case "stderr":
errorStream = os.Stderr
case "stdin":
inputStream = os.Stdin
default:
return errors.Wrapf(libpod.ErrInvalidArg, "invalid stream %q for --attach - must be one of stdin, stdout, or stderr", stream)
}
}
}
// if the container was created as part of a pod, also start its dependencies, if any.
if err := startAttachCtr(ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true, c.IsSet("pod")); err != nil {
// We've manually detached from the container
// Do not perform cleanup, or wait for container exit code
// Just exit immediately
if errors.Cause(err) == libpod.ErrDetach {
exitCode = 0
return nil
}
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
exitCode = 126
}
if c.IsSet("rm") {
if deleteError := runtime.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID())
}
}
return err
}
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == libpod.ErrNoSuchCtr {
// The container may have been removed
// Go looking for an exit file
rtc, err := runtime.GetConfig()
if err != nil {
return err
}
ctrExitCode, err := readExitFile(rtc.TmpDir, ctr.ID())
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = 127
} else {
exitCode = ctrExitCode
}
}
} else {
exitCode = int(ecode)
}
if c.IsSet("rm") {
runtime.RemoveContainer(ctx, ctr, false, true)
}
return nil
}
// Read a container's exit file
func readExitFile(runtimeTmp, ctrID string) (int, error) {
exitFile := filepath.Join(runtimeTmp, "exits", fmt.Sprintf("%s-old", ctrID))
logrus.Debugf("Attempting to read container %s exit code from file %s", ctrID, exitFile)
// Check if it exists
if _, err := os.Stat(exitFile); err != nil {
return 0, errors.Wrapf(err, "error getting exit file for container %s", ctrID)
}
// File exists, read it in and convert to int
statusStr, err := ioutil.ReadFile(exitFile)
if err != nil {
return 0, errors.Wrapf(err, "error reading exit file for container %s", ctrID)
}
exitCode, err := strconv.Atoi(string(statusStr))
if err != nil {
return 0, errors.Wrapf(err, "error parsing exit code for container %s", ctrID)
}
return exitCode, nil
}

View File

@ -83,7 +83,8 @@ func getRuntimeSpec(c *cliconfig.PodmanCommand) (*spec.Spec, error) {
createConfig, err := parseCreateOpts(c, runtime, "alpine", generateAlpineImageData())
*/
ctx := getContext()
createConfig, err := shared.ParseCreateOpts(ctx, c, nil, "alpine", generateAlpineImageData())
genericResults := shared.NewIntermediateLayer(c)
createConfig, err := shared.ParseCreateOpts(ctx, &genericResults, nil, "alpine", generateAlpineImageData())
if err != nil {
return nil, err
}

View File

@ -13,7 +13,6 @@ import (
"time"
"github.com/containers/image/manifest"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
@ -34,12 +33,7 @@ import (
"github.com/sirupsen/logrus"
)
// getContext returns a non-nil, empty context
func getContext() context.Context {
return context.TODO()
}
func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
var (
healthCheck *manifest.Schema2HealthConfig
err error
@ -221,7 +215,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
return nil
}
func configureEntrypoint(c *cliconfig.PodmanCommand, data *inspect.ImageData) []string {
func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string {
entrypoint := []string{}
if c.IsSet("entrypoint") {
// Force entrypoint to ""
@ -241,7 +235,7 @@ func configureEntrypoint(c *cliconfig.PodmanCommand, data *inspect.ImageData) []
return entrypoint
}
func configurePod(c *cliconfig.PodmanCommand, runtime *libpod.Runtime, namespaces map[string]string, podName string) (map[string]string, error) {
func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[string]string, podName string) (map[string]string, error) {
pod, err := runtime.LookupPod(podName)
if err != nil {
return namespaces, err
@ -270,7 +264,7 @@ func configurePod(c *cliconfig.PodmanCommand, runtime *libpod.Runtime, namespace
// Parses CLI options related to container creation into a config which can be
// parsed into an OCI runtime spec
func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
var (
inputCommand, command []string
memoryLimit, memoryReservation, memorySwap, memoryKernel int64
@ -353,14 +347,14 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
tty := c.Bool("tty")
if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
if c.Changed("cpu-period") && c.Changed("cpus") {
return nil, errors.Errorf("--cpu-period and --cpus cannot be set together")
}
if c.Flag("cpu-quota").Changed && c.Flag("cpus").Changed {
if c.Changed("cpu-quota") && c.Changed("cpus") {
return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
if c.Bool("no-hosts") && c.Flag("add-host").Changed {
if c.Bool("no-hosts") && c.Changed("add-host") {
return nil, errors.Errorf("--no-hosts and --add-host cannot be set together")
}
@ -379,7 +373,7 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
// However, that also involves setting up security opts
// when the pod's namespace is integrated
namespaceNet := c.String("network")
if c.Flag("net").Changed {
if c.Changed("net") {
namespaceNet = c.String("net")
}
namespaces = map[string]string{
@ -548,7 +542,7 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
// WORKING DIRECTORY
workDir := "/"
if c.IsSet("workdir") || c.IsSet("w") {
if c.IsSet("workdir") {
workDir = c.String("workdir")
} else if data != nil && data.Config.WorkingDir != "" {
workDir = data.Config.WorkingDir
@ -624,14 +618,12 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
// This is done because cobra cannot have two aliased flags. So we have to check
// both
network := c.String("network")
if c.Flag("net").Changed {
if c.Changed("net") {
network = c.String("net")
}
var memorySwappiness int64
if c.Flags().Lookup("memory-swappiness") != nil {
memorySwappiness, _ = c.Flags().GetInt64("memory-swappiness")
}
memorySwappiness := c.Int64("memory-swappiness")
config := &cc.CreateConfig{
Runtime: runtime,
Annotations: annotations,
@ -719,7 +711,7 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
WorkDir: workDir,
Rootfs: rootfs,
VolumesFrom: c.StringSlice("volumes-from"),
Syslog: c.GlobalFlags.Syslog,
Syslog: c.Bool("syslog"),
}
if c.Bool("init") {
initPath := c.String("init-path")
@ -789,7 +781,7 @@ var defaultEnvVariables = map[string]string{
"TERM": "xterm",
}
func makeHealthCheckFromCli(c *cliconfig.PodmanCommand) (*manifest.Schema2HealthConfig, error) {
func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig, error) {
inCommand := c.String("healthcheck-command")
inInterval := c.String("healthcheck-interval")
inRetries := c.Uint("healthcheck-retries")

View File

@ -0,0 +1,465 @@
package shared
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/sirupsen/logrus"
)
/*
attention
in this file you will see alot of struct duplication. this was done because people wanted a strongly typed
varlink mechanism. this resulted in us creating this intermediate layer that allows us to take the input
from the cli and make an intermediate layer which can be transferred as strongly typed structures over a varlink
interface.
we intentionally avoided heavy use of reflection here because we were concerned about performance impacts to the
non-varlink intermediate layer generation.
*/
// GenericCLIResult describes the overall interface for dealing with
// the create command cli in both local and remote uses
type GenericCLIResult interface {
IsSet() bool
Name() string
Value() interface{}
}
// CRStringSlice describes a string slice cli struct
type CRStringSlice struct {
Val []string
createResult
}
// CRString describes a string cli struct
type CRString struct {
Val string
createResult
}
// CRUint64 describes a uint64 cli struct
type CRUint64 struct {
Val uint64
createResult
}
// CRFloat64 describes a float64 cli struct
type CRFloat64 struct {
Val float64
createResult
}
//CRBool describes a bool cli struct
type CRBool struct {
Val bool
createResult
}
// CRInt64 describes an int64 cli struct
type CRInt64 struct {
Val int64
createResult
}
// CRUint describes a uint cli struct
type CRUint struct {
Val uint
createResult
}
// CRInt describes an int cli struct
type CRInt struct {
Val int
createResult
}
// CRStringArray describes a stringarray cli struct
type CRStringArray struct {
Val []string
createResult
}
type createResult struct {
Flag string
Changed bool
}
// GenericCLIResults in the intermediate object between the cobra cli
// and createconfig
type GenericCLIResults struct {
results map[string]GenericCLIResult
InputArgs []string
}
// IsSet returns a bool if the flag was changed
func (f GenericCLIResults) IsSet(flag string) bool {
r := f.findResult(flag)
if r == nil {
return false
}
return r.IsSet()
}
// Value returns the value of the cli flag
func (f GenericCLIResults) Value(flag string) interface{} {
r := f.findResult(flag)
if r == nil {
return ""
}
return r.Value()
}
func (f GenericCLIResults) findResult(flag string) GenericCLIResult {
val, ok := f.results[flag]
if ok {
return val
}
logrus.Errorf("unable to find flag %s", flag)
return nil
}
// Bool is a wrapper to get a bool value from GenericCLIResults
func (f GenericCLIResults) Bool(flag string) bool {
r := f.findResult(flag)
if r == nil {
return false
}
return r.Value().(bool)
}
// String is a wrapper to get a string value from GenericCLIResults
func (f GenericCLIResults) String(flag string) string {
r := f.findResult(flag)
if r == nil {
return ""
}
return r.Value().(string)
}
// Uint is a wrapper to get an uint value from GenericCLIResults
func (f GenericCLIResults) Uint(flag string) uint {
r := f.findResult(flag)
if r == nil {
return 0
}
return r.Value().(uint)
}
// StringSlice is a wrapper to get a stringslice value from GenericCLIResults
func (f GenericCLIResults) StringSlice(flag string) []string {
r := f.findResult(flag)
if r == nil {
return []string{}
}
return r.Value().([]string)
}
// StringArray is a wrapper to get a stringslice value from GenericCLIResults
func (f GenericCLIResults) StringArray(flag string) []string {
r := f.findResult(flag)
if r == nil {
return []string{}
}
return r.Value().([]string)
}
// Uint64 is a wrapper to get an uint64 value from GenericCLIResults
func (f GenericCLIResults) Uint64(flag string) uint64 {
r := f.findResult(flag)
if r == nil {
return 0
}
return r.Value().(uint64)
}
// Int64 is a wrapper to get an int64 value from GenericCLIResults
func (f GenericCLIResults) Int64(flag string) int64 {
r := f.findResult(flag)
if r == nil {
return 0
}
return r.Value().(int64)
}
// Int is a wrapper to get an int value from GenericCLIResults
func (f GenericCLIResults) Int(flag string) int {
r := f.findResult(flag)
if r == nil {
return 0
}
return r.Value().(int)
}
// Float64 is a wrapper to get an float64 value from GenericCLIResults
func (f GenericCLIResults) Float64(flag string) float64 {
r := f.findResult(flag)
if r == nil {
return 0
}
return r.Value().(float64)
}
// Float64 is a wrapper to get an float64 value from GenericCLIResults
func (f GenericCLIResults) Changed(flag string) bool {
r := f.findResult(flag)
if r == nil {
return false
}
return r.IsSet()
}
// IsSet ...
func (c CRStringSlice) IsSet() bool { return c.Changed }
// Name ...
func (c CRStringSlice) Name() string { return c.Flag }
// Value ...
func (c CRStringSlice) Value() interface{} { return c.Val }
// IsSet ...
func (c CRString) IsSet() bool { return c.Changed }
// Name ...
func (c CRString) Name() string { return c.Flag }
// Value ...
func (c CRString) Value() interface{} { return c.Val }
// IsSet ...
func (c CRUint64) IsSet() bool { return c.Changed }
// Name ...
func (c CRUint64) Name() string { return c.Flag }
// Value ...
func (c CRUint64) Value() interface{} { return c.Val }
// IsSet ...
func (c CRFloat64) IsSet() bool { return c.Changed }
// Name ...
func (c CRFloat64) Name() string { return c.Flag }
// Value ...
func (c CRFloat64) Value() interface{} { return c.Val }
// IsSet ...
func (c CRBool) IsSet() bool { return c.Changed }
// Name ...
func (c CRBool) Name() string { return c.Flag }
// Value ...
func (c CRBool) Value() interface{} { return c.Val }
// IsSet ...
func (c CRInt64) IsSet() bool { return c.Changed }
// Name ...
func (c CRInt64) Name() string { return c.Flag }
// Value ...
func (c CRInt64) Value() interface{} { return c.Val }
// IsSet ...
func (c CRUint) IsSet() bool { return c.Changed }
// Name ...
func (c CRUint) Name() string { return c.Flag }
// Value ...
func (c CRUint) Value() interface{} { return c.Val }
// IsSet ...
func (c CRInt) IsSet() bool { return c.Changed }
// Name ...
func (c CRInt) Name() string { return c.Flag }
// Value ...
func (c CRInt) Value() interface{} { return c.Val }
// IsSet ...
func (c CRStringArray) IsSet() bool { return c.Changed }
// Name ...
func (c CRStringArray) Name() string { return c.Flag }
// Value ...
func (c CRStringArray) Value() interface{} { return c.Val }
func newCreateResult(c *cliconfig.PodmanCommand, flag string) createResult {
return createResult{
Flag: flag,
Changed: c.IsSet(flag),
}
}
func newCRStringSlice(c *cliconfig.PodmanCommand, flag string) CRStringSlice {
return CRStringSlice{
Val: c.StringSlice(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRString(c *cliconfig.PodmanCommand, flag string) CRString {
return CRString{
Val: c.String(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRUint64(c *cliconfig.PodmanCommand, flag string) CRUint64 {
return CRUint64{
Val: c.Uint64(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRFloat64(c *cliconfig.PodmanCommand, flag string) CRFloat64 {
return CRFloat64{
Val: c.Float64(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRBool(c *cliconfig.PodmanCommand, flag string) CRBool {
return CRBool{
Val: c.Bool(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRInt64(c *cliconfig.PodmanCommand, flag string) CRInt64 {
return CRInt64{
Val: c.Int64(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRUint(c *cliconfig.PodmanCommand, flag string) CRUint {
return CRUint{
Val: c.Uint(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRInt(c *cliconfig.PodmanCommand, flag string) CRInt {
return CRInt{
Val: c.Int(flag),
createResult: newCreateResult(c, flag),
}
}
func newCRStringArray(c *cliconfig.PodmanCommand, flag string) CRStringArray {
return CRStringArray{
Val: c.StringArray(flag),
createResult: newCreateResult(c, flag),
}
}
// NewIntermediateLayer creates a GenericCLIResults from a create or run cli-command
func NewIntermediateLayer(c *cliconfig.PodmanCommand) GenericCLIResults {
m := make(map[string]GenericCLIResult)
m["add-host"] = newCRStringSlice(c, "add-host")
m["annotation"] = newCRStringSlice(c, "annotation")
m["attach"] = newCRStringSlice(c, "attach")
m["blkio-weight"] = newCRString(c, "blkio-weight")
m["blkio-weight-device"] = newCRStringSlice(c, "blkio-weight-device")
m["cap-add"] = newCRStringSlice(c, "cap-add")
m["cap-drop"] = newCRStringSlice(c, "cap-drop")
m["cgroup-parent"] = newCRString(c, "cgroup-parent")
m["cidfile"] = newCRString(c, "cidfile")
m["conmon-pidfile"] = newCRString(c, "conmon-pidfile")
m["cpu-period"] = newCRUint64(c, "cpu-period")
m["cpu-quota"] = newCRInt64(c, "cpu-quota")
m["cpu-rt-period"] = newCRUint64(c, "cpu-rt-period")
m["cpu-rt-runtime"] = newCRInt64(c, "cpu-rt-runtime")
m["cpu-shares"] = newCRUint64(c, "cpu-shares")
m["cpus"] = newCRFloat64(c, "cpus")
m["cpuset-cpus"] = newCRString(c, "cpuset-cpus")
m["cpuset-mems"] = newCRString(c, "cpuset-mems")
m["detach"] = newCRBool(c, "detach")
m["detach-keys"] = newCRString(c, "detach-keys")
m["device"] = newCRStringSlice(c, "device")
m["device-read-bps"] = newCRStringSlice(c, "device-read-bps")
m["device-read-iops"] = newCRStringSlice(c, "device-read-iops")
m["device-write-bps"] = newCRStringSlice(c, "device-write-bps")
m["device-write-iops"] = newCRStringSlice(c, "device-write-iops")
m["dns"] = newCRStringSlice(c, "dns")
m["dns-opt"] = newCRStringSlice(c, "dns-opt")
m["dns-search"] = newCRStringSlice(c, "dns-search")
m["entrypoint"] = newCRString(c, "entrypoint")
m["env"] = newCRStringArray(c, "env")
m["env-file"] = newCRStringSlice(c, "env-file")
m["expose"] = newCRStringSlice(c, "expose")
m["gidmap"] = newCRStringSlice(c, "gidmap")
m["group-add"] = newCRStringSlice(c, "group-add")
m["help"] = newCRBool(c, "help")
m["healthcheck-command"] = newCRString(c, "healthcheck-command")
m["healthcheck-interval"] = newCRString(c, "healthcheck-interval")
m["healthcheck-retries"] = newCRUint(c, "healthcheck-retries")
m["healthcheck-start-period"] = newCRString(c, "healthcheck-start-period")
m["healthcheck-timeout"] = newCRString(c, "healthcheck-timeout")
m["hostname"] = newCRString(c, "hostname")
m["image-volume"] = newCRString(c, "image-volume")
m["init"] = newCRBool(c, "init")
m["init-path"] = newCRString(c, "init-path")
m["interactive"] = newCRBool(c, "interactive")
m["ip"] = newCRString(c, "ip")
m["ipc"] = newCRString(c, "ipc")
m["kernel-memory"] = newCRString(c, "kernel-memory")
m["label"] = newCRStringArray(c, "label")
m["label-file"] = newCRStringSlice(c, "label-file")
m["log-driver"] = newCRString(c, "log-driver")
m["log-opt"] = newCRStringSlice(c, "log-opt")
m["mac-address"] = newCRString(c, "mac-address")
m["memory"] = newCRString(c, "memory")
m["memory-reservation"] = newCRString(c, "memory-reservation")
m["memory-swap"] = newCRString(c, "memory-swap")
m["memory-swappiness"] = newCRInt64(c, "memory-swappiness")
m["name"] = newCRString(c, "name")
m["net"] = newCRString(c, "net")
m["network"] = newCRString(c, "network")
m["no-hosts"] = newCRBool(c, "no-hosts")
m["oom-kill-disable"] = newCRBool(c, "oom-kill-disable")
m["oom-score-adj"] = newCRInt(c, "oom-score-adj")
m["pid"] = newCRString(c, "pid")
m["pids-limit"] = newCRInt64(c, "pids-limit")
m["pod"] = newCRString(c, "pod")
m["privileged"] = newCRBool(c, "privileged")
m["publish"] = newCRStringSlice(c, "publish")
m["publish-all"] = newCRBool(c, "publish-all")
m["quiet"] = newCRBool(c, "quiet")
m["read-only"] = newCRBool(c, "read-only")
m["restart"] = newCRString(c, "restart")
m["rm"] = newCRBool(c, "rm")
m["rootfs"] = newCRBool(c, "rootfs")
m["security-opt"] = newCRStringArray(c, "security-opt")
m["shm-size"] = newCRString(c, "shm-size")
m["stop-signal"] = newCRString(c, "stop-signal")
m["stop-timeout"] = newCRUint(c, "stop-timeout")
m["storage-opt"] = newCRStringSlice(c, "storage-opt")
m["subgidname"] = newCRString(c, "subgidname")
m["subuidname"] = newCRString(c, "subuidname")
m["sysctl"] = newCRStringSlice(c, "sysctl")
m["systemd"] = newCRBool(c, "systemd")
m["tmpfs"] = newCRStringSlice(c, "tmpfs")
m["tty"] = newCRBool(c, "tty")
m["uidmap"] = newCRStringSlice(c, "uidmap")
m["ulimit"] = newCRStringSlice(c, "ulimit")
m["user"] = newCRString(c, "user")
m["userns"] = newCRString(c, "userns")
m["uts"] = newCRString(c, "uts")
m["mount"] = newCRStringArray(c, "mount")
m["volume"] = newCRStringArray(c, "volume")
m["volumes-from"] = newCRStringSlice(c, "volumes-from")
m["workdir"] = newCRString(c, "workdir")
// global flag
m["trace"] = newCRBool(c, "trace")
m["syslog"] = newCRBool(c, "syslog")
return GenericCLIResults{m, c.InputArgs}
}

View File

@ -0,0 +1,70 @@
// +build !varlink
// +build !remoteclient
package shared
/*
attention
in this file you will see alot of struct duplication. this was done because people wanted a strongly typed
varlink mechanism. this resulted in us creating this intermediate layer that allows us to take the input
from the cli and make an intermediate layer which can be transferred as strongly typed structures over a varlink
interface.
we intentionally avoided heavy use of reflection here because we were concerned about performance impacts to the
non-varlink intermediate layer generation.
*/
// ToString wrapper for build without varlink
func (c CRStringSlice) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRString) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRBool) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRUint64) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRInt64) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRFloat64) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRUint) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRStringArray) ToVarlink() interface{} {
var v interface{}
return v
}
// ToString wrapper for build without varlink
func (c CRInt) ToVarlink() interface{} {
var v interface{}
return v
}

View File

@ -0,0 +1,427 @@
// +build varlink remoteclient
package shared
import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/pkg/errors"
)
// StringSliceToPtr converts a genericcliresult value into a *[]string
func StringSliceToPtr(g GenericCLIResult) *[]string {
if !g.IsSet() {
return nil
}
newT := g.Value().([]string)
return &newT
}
// StringToPtr converts a genericcliresult value into a *string
func StringToPtr(g GenericCLIResult) *string {
if !g.IsSet() {
return nil
}
newT := g.Value().(string)
return &newT
}
// BoolToPtr converts a genericcliresult value into a *bool
func BoolToPtr(g GenericCLIResult) *bool {
if !g.IsSet() {
return nil
}
newT := g.Value().(bool)
return &newT
}
// AnyIntToInt64Ptr converts a genericcliresult value into an *int64
func AnyIntToInt64Ptr(g GenericCLIResult) *int64 {
if !g.IsSet() {
return nil
}
var newT int64
switch g.Value().(type) {
case int:
newT = int64(g.Value().(int))
case int64:
newT = g.Value().(int64)
case uint64:
newT = int64(g.Value().(uint64))
case uint:
newT = int64(g.Value().(uint))
default:
panic(errors.Errorf("invalid int type"))
}
return &newT
}
// Float64ToPtr converts a genericcliresult into a *float64
func Float64ToPtr(g GenericCLIResult) *float64 {
if !g.IsSet() {
return nil
}
newT := g.Value().(float64)
return &newT
}
// MakeVarlink creates a varlink transportable struct from GenericCLIResults
func (g GenericCLIResults) MakeVarlink() iopodman.Create {
v := iopodman.Create{
Args: g.InputArgs,
AddHost: StringSliceToPtr(g.Find("add-host")),
Annotation: StringSliceToPtr(g.Find("annotation")),
Attach: StringSliceToPtr(g.Find("attach")),
BlkioWeight: StringToPtr(g.Find("blkio-weight")),
BlkioWeightDevice: StringSliceToPtr(g.Find("blkio-weight-device")),
CapAdd: StringSliceToPtr(g.Find("cap-add")),
CapDrop: StringSliceToPtr(g.Find("cap-drop")),
CgroupParent: StringToPtr(g.Find("cgroup-parent")),
CidFile: StringToPtr(g.Find("cidfile")),
ConmonPidfile: StringToPtr(g.Find("conmon-pidfile")),
CpuPeriod: AnyIntToInt64Ptr(g.Find("cpu-period")),
CpuQuota: AnyIntToInt64Ptr(g.Find("cpu-quota")),
CpuRtPeriod: AnyIntToInt64Ptr(g.Find("cpu-rt-period")),
CpuRtRuntime: AnyIntToInt64Ptr(g.Find("cpu-rt-runtime")),
CpuShares: AnyIntToInt64Ptr(g.Find("cpu-shares")),
Cpus: Float64ToPtr(g.Find("cpus")),
CpuSetCpus: StringToPtr(g.Find("cpuset-cpus")),
CpuSetMems: StringToPtr(g.Find("cpuset-mems")),
Detach: BoolToPtr(g.Find("detach")),
DetachKeys: StringToPtr(g.Find("detach-keys")),
Device: StringSliceToPtr(g.Find("device")),
DeviceReadBps: StringSliceToPtr(g.Find("device-read-bps")),
DeviceReadIops: StringSliceToPtr(g.Find("device-read-iops")),
DeviceWriteBps: StringSliceToPtr(g.Find("device-write-bps")),
DeviceWriteIops: StringSliceToPtr(g.Find("device-write-iops")),
Dns: StringSliceToPtr(g.Find("dns")),
DnsOpt: StringSliceToPtr(g.Find("dns-opt")),
DnsSearch: StringSliceToPtr(g.Find("dns-search")),
Entrypoint: StringToPtr(g.Find("entrypoint")),
Env: StringSliceToPtr(g.Find("env")),
EnvFile: StringSliceToPtr(g.Find("env-file")),
Expose: StringSliceToPtr(g.Find("expose")),
Gidmap: StringSliceToPtr(g.Find("gidmap")),
Groupadd: StringSliceToPtr(g.Find("group-add")),
HealthcheckCommand: StringToPtr(g.Find("healthcheck-command")),
HealthcheckInterval: StringToPtr(g.Find("healthcheck-interval")),
HealthcheckRetries: AnyIntToInt64Ptr(g.Find("healthcheck-retries")),
HealthcheckStartPeriod: StringToPtr(g.Find("healthcheck-start-period")),
HealthcheckTimeout: StringToPtr(g.Find("healthcheck-timeout")),
Hostname: StringToPtr(g.Find("hostname")),
ImageVolume: StringToPtr(g.Find("image-volume")),
Init: BoolToPtr(g.Find("init")),
InitPath: StringToPtr(g.Find("init-path")),
Interactive: BoolToPtr(g.Find("interactive")),
Ip: StringToPtr(g.Find("ip")),
Ipc: StringToPtr(g.Find("ipc")),
KernelMemory: StringToPtr(g.Find("kernel-memory")),
Label: StringSliceToPtr(g.Find("label")),
LabelFile: StringSliceToPtr(g.Find("label-file")),
LogDriver: StringToPtr(g.Find("log-driver")),
LogOpt: StringSliceToPtr(g.Find("log-opt")),
MacAddress: StringToPtr(g.Find("mac-address")),
Memory: StringToPtr(g.Find("memory")),
MemoryReservation: StringToPtr(g.Find("memory-reservation")),
MemorySwap: StringToPtr(g.Find("memory-swap")),
MemorySwappiness: AnyIntToInt64Ptr(g.Find("memory-swappiness")),
Name: StringToPtr(g.Find("name")),
Net: StringToPtr(g.Find("net")),
Network: StringToPtr(g.Find("network")),
OomKillDisable: BoolToPtr(g.Find("oom-kill-disable")),
OomScoreAdj: AnyIntToInt64Ptr(g.Find("oom-score-adj")),
Pid: StringToPtr(g.Find("pid")),
PidsLimit: AnyIntToInt64Ptr(g.Find("pids-limit")),
Pod: StringToPtr(g.Find("pod")),
Privileged: BoolToPtr(g.Find("privileged")),
Publish: StringSliceToPtr(g.Find("publish")),
PublishAll: BoolToPtr(g.Find("publish-all")),
Quiet: BoolToPtr(g.Find("quiet")),
Readonly: BoolToPtr(g.Find("read-only")),
Restart: StringToPtr(g.Find("restart")),
Rm: BoolToPtr(g.Find("rm")),
Rootfs: BoolToPtr(g.Find("rootfs")),
SecurityOpt: StringSliceToPtr(g.Find("security-opt")),
ShmSize: StringToPtr(g.Find("shm-size")),
StopSignal: StringToPtr(g.Find("stop-signal")),
StopTimeout: AnyIntToInt64Ptr(g.Find("stop-timeout")),
StorageOpt: StringSliceToPtr(g.Find("storage-opt")),
Subuidname: StringToPtr(g.Find("subuidname")),
Subgidname: StringToPtr(g.Find("subgidname")),
Sysctl: StringSliceToPtr(g.Find("sysctl")),
Systemd: BoolToPtr(g.Find("systemd")),
Tmpfs: StringSliceToPtr(g.Find("tmpfs")),
Tty: BoolToPtr(g.Find("tty")),
Uidmap: StringSliceToPtr(g.Find("uidmap")),
Ulimit: StringSliceToPtr(g.Find("ulimit")),
User: StringToPtr(g.Find("user")),
Userns: StringToPtr(g.Find("userns")),
Uts: StringToPtr(g.Find("uts")),
Mount: StringSliceToPtr(g.Find("mount")),
Volume: StringSliceToPtr(g.Find("volume")),
VolumesFrom: StringSliceToPtr(g.Find("volumes-from")),
WorkDir: StringToPtr(g.Find("workdir")),
}
return v
}
func stringSliceFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringSlice {
cr := CRStringSlice{}
if v == nil {
cr.Val = []string{}
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func stringFromVarlink(v *string, flagName string, defaultValue *string) CRString {
cr := CRString{}
if v == nil {
cr.Val = ""
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool {
cr := CRBool{}
if v == nil {
// In case a cli bool default value is true
cr.Val = defaultValue
cr.Changed = false
} else {
fmt.Println(flagName, cr.Val)
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func uint64FromVarlink(v *int64, flagName string, defaultValue *uint64) CRUint64 {
cr := CRUint64{}
if v == nil {
cr.Val = 0
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = uint64(*v)
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func int64FromVarlink(v *int64, flagName string, defaultValue *int64) CRInt64 {
cr := CRInt64{}
if v == nil {
cr.Val = 0
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func float64FromVarlink(v *float64, flagName string, defaultValue *float64) CRFloat64 {
cr := CRFloat64{}
if v == nil {
cr.Val = 0
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func uintFromVarlink(v *int64, flagName string, defaultValue *uint) CRUint {
cr := CRUint{}
if v == nil {
cr.Val = 0
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = uint(*v)
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func stringArrayFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringArray {
cr := CRStringArray{}
if v == nil {
cr.Val = []string{}
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Changed = false
} else {
cr.Val = *v
cr.Changed = true
}
cr.Flag = flagName
return cr
}
func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt {
cr := CRInt{}
if v == nil {
if defaultValue != nil {
cr.Val = *defaultValue
}
cr.Val = 0
cr.Changed = false
} else {
cr.Val = int(*v)
cr.Changed = true
}
cr.Flag = flagName
return cr
}
// VarlinkCreateToGeneric creates a GenericCLIResults from the varlink create
// structure.
func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
// TODO | WARN
// We do not get a default network over varlink. Unlike the other default values for some cli
// elements, it seems it gets set to the default anyway.
m := make(map[string]GenericCLIResult)
m["add-host"] = stringSliceFromVarlink(opts.AddHost, "add-host", nil)
m["annotation"] = stringSliceFromVarlink(opts.Annotation, "annotation", nil)
m["attach"] = stringSliceFromVarlink(opts.Attach, "attach", nil)
m["blkio-weight"] = stringFromVarlink(opts.BlkioWeight, "blkio-weight", nil)
m["blkio-weight-device"] = stringSliceFromVarlink(opts.BlkioWeightDevice, "blkio-weight-device", nil)
m["cap-add"] = stringSliceFromVarlink(opts.CapAdd, "cap-add", nil)
m["cap-drop"] = stringSliceFromVarlink(opts.CapDrop, "cap-drop", nil)
m["cgroup-parent"] = stringFromVarlink(opts.CgroupParent, "cgroup-parent", nil)
m["cidfile"] = stringFromVarlink(opts.CidFile, "cidfile", nil)
m["conmon-pidfile"] = stringFromVarlink(opts.ConmonPidfile, "conmon-file", nil)
m["cpu-period"] = uint64FromVarlink(opts.CpuPeriod, "cpu-period", nil)
m["cpu-quota"] = int64FromVarlink(opts.CpuQuota, "quota", nil)
m["cpu-rt-period"] = uint64FromVarlink(opts.CpuRtPeriod, "cpu-rt-period", nil)
m["cpu-rt-runtime"] = int64FromVarlink(opts.CpuRtRuntime, "cpu-rt-quota", nil)
m["cpu-shares"] = uint64FromVarlink(opts.CpuShares, "cpu-shares", nil)
m["cpus"] = float64FromVarlink(opts.Cpus, "cpus", nil)
m["cpuset-cpus"] = stringFromVarlink(opts.CpuSetCpus, "cpuset-cpus", nil)
m["cpuset-mems"] = stringFromVarlink(opts.CpuSetMems, "cpuset-mems", nil)
m["detach"] = boolFromVarlink(opts.Detach, "detach", false)
m["detach-keys"] = stringFromVarlink(opts.DetachKeys, "detach-keys", nil)
m["device"] = stringSliceFromVarlink(opts.Device, "device", nil)
m["device-read-bps"] = stringSliceFromVarlink(opts.DeviceReadBps, "device-read-bps", nil)
m["device-read-iops"] = stringSliceFromVarlink(opts.DeviceReadIops, "device-read-iops", nil)
m["device-write-bps"] = stringSliceFromVarlink(opts.DeviceWriteBps, "write-device-bps", nil)
m["device-write-iops"] = stringSliceFromVarlink(opts.DeviceWriteIops, "write-device-iops", nil)
m["dns"] = stringSliceFromVarlink(opts.Dns, "dns", nil)
m["dns-opt"] = stringSliceFromVarlink(opts.DnsOpt, "dns-opt", nil)
m["dns-search"] = stringSliceFromVarlink(opts.DnsSearch, "dns-search", nil)
m["entrypoint"] = stringFromVarlink(opts.Entrypoint, "entrypoint", nil)
m["env"] = stringArrayFromVarlink(opts.Env, "env", nil)
m["env-file"] = stringSliceFromVarlink(opts.EnvFile, "env-file", nil)
m["expose"] = stringSliceFromVarlink(opts.Expose, "expose", nil)
m["gidmap"] = stringSliceFromVarlink(opts.Gidmap, "gidmap", nil)
m["group-add"] = stringSliceFromVarlink(opts.Groupadd, "group-add", nil)
m["healthcheck-command"] = stringFromVarlink(opts.HealthcheckCommand, "healthcheck-command", nil)
m["healthcheck-interval"] = stringFromVarlink(opts.HealthcheckInterval, "healthcheck-interval", &cliconfig.DefaultHealthCheckInterval)
m["healthcheck-retries"] = uintFromVarlink(opts.HealthcheckRetries, "healthcheck-retries", &cliconfig.DefaultHealthCheckRetries)
m["healthcheck-start-period"] = stringFromVarlink(opts.HealthcheckStartPeriod, "healthcheck-start-period", &cliconfig.DefaultHealthCheckStartPeriod)
m["healthcheck-timeout"] = stringFromVarlink(opts.HealthcheckTimeout, "healthcheck-timeout", &cliconfig.DefaultHealthCheckTimeout)
m["hostname"] = stringFromVarlink(opts.Hostname, "hostname", nil)
m["image-volume"] = stringFromVarlink(opts.ImageVolume, "image-volume", &cliconfig.DefaultImageVolume)
m["init"] = boolFromVarlink(opts.Init, "init", false)
m["init-path"] = stringFromVarlink(opts.InitPath, "init-path", nil)
m["interactive"] = boolFromVarlink(opts.Interactive, "interactive", false)
m["ip"] = stringFromVarlink(opts.Ip, "ip", nil)
m["ipc"] = stringFromVarlink(opts.Ipc, "ipc", nil)
m["kernel-memory"] = stringFromVarlink(opts.KernelMemory, "kernel-memory", nil)
m["label"] = stringArrayFromVarlink(opts.Label, "label", nil)
m["label-file"] = stringSliceFromVarlink(opts.LabelFile, "label-file", nil)
m["log-driver"] = stringFromVarlink(opts.LogDriver, "log-driver", nil)
m["log-opt"] = stringSliceFromVarlink(opts.LogOpt, "log-opt", nil)
m["mac-address"] = stringFromVarlink(opts.MacAddress, "mac-address", nil)
m["memory"] = stringFromVarlink(opts.Memory, "memory", nil)
m["memory-reservation"] = stringFromVarlink(opts.MemoryReservation, "memory-reservation", nil)
m["memory-swap"] = stringFromVarlink(opts.MemorySwap, "memory-swap", nil)
m["memory-swappiness"] = int64FromVarlink(opts.MemorySwappiness, "memory-swappiness", nil)
m["name"] = stringFromVarlink(opts.Name, "name", nil)
m["net"] = stringFromVarlink(opts.Net, "net", nil)
m["network"] = stringFromVarlink(opts.Network, "network", nil)
m["no-hosts"] = boolFromVarlink(opts.NoHosts, "no-hosts", false)
m["oom-kill-disable"] = boolFromVarlink(opts.OomKillDisable, "oon-kill-disable", false)
m["oom-score-adj"] = intFromVarlink(opts.OomScoreAdj, "oom-score-adj", nil)
m["pid"] = stringFromVarlink(opts.Pid, "pid", nil)
m["pids-limit"] = int64FromVarlink(opts.PidsLimit, "pids-limit", nil)
m["pod"] = stringFromVarlink(opts.Pod, "pod", nil)
m["privileged"] = boolFromVarlink(opts.Privileged, "privileged", false)
m["publish"] = stringSliceFromVarlink(opts.Publish, "publish", nil)
m["publish-all"] = boolFromVarlink(opts.PublishAll, "publish-all", false)
m["quiet"] = boolFromVarlink(opts.Quiet, "quiet", false)
m["read-only"] = boolFromVarlink(opts.Readonly, "read-only", false)
m["restart"] = stringFromVarlink(opts.Restart, "restart", nil)
m["rm"] = boolFromVarlink(opts.Rm, "rm", false)
m["rootfs"] = boolFromVarlink(opts.Rootfs, "rootfs", false)
m["security-opt"] = stringArrayFromVarlink(opts.SecurityOpt, "security-opt", nil)
m["shm-size"] = stringFromVarlink(opts.ShmSize, "shm-size", &cliconfig.DefaultShmSize)
m["stop-signal"] = stringFromVarlink(opts.StopSignal, "stop-signal", nil)
m["stop-timeout"] = uintFromVarlink(opts.StopTimeout, "stop-timeout", nil)
m["storage-opt"] = stringSliceFromVarlink(opts.StorageOpt, "storage-opt", nil)
m["subgidname"] = stringFromVarlink(opts.Subgidname, "subgidname", nil)
m["subuidname"] = stringFromVarlink(opts.Subuidname, "subuidname", nil)
m["sysctl"] = stringSliceFromVarlink(opts.Sysctl, "sysctl", nil)
m["systemd"] = boolFromVarlink(opts.Systemd, "systemd", cliconfig.DefaultSystemD)
m["tmpfs"] = stringSliceFromVarlink(opts.Tmpfs, "tmpfs", nil)
m["tty"] = boolFromVarlink(opts.Tty, "tty", false)
m["uidmap"] = stringSliceFromVarlink(opts.Uidmap, "uidmap", nil)
m["ulimit"] = stringSliceFromVarlink(opts.Ulimit, "ulimit", nil)
m["user"] = stringFromVarlink(opts.User, "user", nil)
m["userns"] = stringFromVarlink(opts.Userns, "userns", nil)
m["uts"] = stringFromVarlink(opts.Uts, "uts", nil)
m["mount"] = stringArrayFromVarlink(opts.Mount, "mount", nil)
m["volume"] = stringArrayFromVarlink(opts.Volume, "volume", nil)
m["volumes-from"] = stringSliceFromVarlink(opts.VolumesFrom, "volumes-from", nil)
m["workdir"] = stringFromVarlink(opts.WorkDir, "workdir", nil)
gcli := GenericCLIResults{m, opts.Args}
return gcli
}
// Find returns a flag from a GenericCLIResults by name
func (g GenericCLIResults) Find(name string) GenericCLIResult {
result, ok := g.results[name]
if ok {
return result
}
panic(errors.Errorf("unable to find generic flag for varlink %s", name))
}

View File

@ -7,6 +7,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
opentracing "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -109,7 +110,7 @@ func startCmd(c *cliconfig.StartValues) error {
// attach to the container and also start it not already running
// If the container is in a pod, also set to recursively start dependencies
err = startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning, ctr.PodID() != "")
err = adapter.StartAttachCtr(ctx, ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning, ctr.PodID() != "")
if errors.Cause(err) == libpod.ErrDetach {
// User manually detached
// Exit cleanly immediately
@ -133,7 +134,7 @@ func startCmd(c *cliconfig.StartValues) error {
if err != nil {
return err
}
ctrExitCode, err := readExitFile(rtc.TmpDir, ctr.ID())
ctrExitCode, err := adapter.ReadExitFile(rtc.TmpDir, ctr.ID())
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = 127

View File

@ -1,205 +1,11 @@
package main
import (
"context"
"fmt"
"github.com/spf13/pflag"
"os"
gosignal "os/signal"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
"k8s.io/client-go/tools/remotecommand"
)
type RawTtyFormatter struct {
}
// Start (if required) and attach to a container
func startAttachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error {
ctx := context.Background()
resize := make(chan remotecommand.TerminalSize)
haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
// Check if we are attached to a terminal. If we are, generate resize
// events, and set the terminal to raw mode
if haveTerminal && ctr.Spec().Process.Terminal {
logrus.Debugf("Handling terminal attach")
subCtx, cancel := context.WithCancel(ctx)
defer cancel()
resizeTty(subCtx, resize)
oldTermState, err := term.SaveState(os.Stdin.Fd())
if err != nil {
return errors.Wrapf(err, "unable to save terminal state")
}
logrus.SetFormatter(&RawTtyFormatter{})
term.SetRawTerminal(os.Stdin.Fd())
defer restoreTerminal(oldTermState)
}
streams := new(libpod.AttachStreams)
streams.OutputStream = stdout
streams.ErrorStream = stderr
streams.InputStream = stdin
streams.AttachOutput = true
streams.AttachError = true
streams.AttachInput = true
if stdout == nil {
logrus.Debugf("Not attaching to stdout")
streams.AttachOutput = false
}
if stderr == nil {
logrus.Debugf("Not attaching to stderr")
streams.AttachError = false
}
if stdin == nil {
logrus.Debugf("Not attaching to stdin")
streams.AttachInput = false
}
if !startContainer {
if sigProxy {
ProxySignals(ctr)
}
return ctr.Attach(streams, detachKeys, resize)
}
attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, recursive)
if err != nil {
return err
}
if sigProxy {
ProxySignals(ctr)
}
if stdout == nil && stderr == nil {
fmt.Printf("%s\n", ctr.ID())
}
err = <-attachChan
if err != nil {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}
return nil
}
// getResize returns a TerminalSize command matching stdin's current
// size on success, and nil on errors.
func getResize() *remotecommand.TerminalSize {
winsize, err := term.GetWinsize(os.Stdin.Fd())
if err != nil {
logrus.Warnf("Could not get terminal size %v", err)
return nil
}
return &remotecommand.TerminalSize{
Width: winsize.Width,
Height: winsize.Height,
}
}
// Helper for prepareAttach - set up a goroutine to generate terminal resize events
func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) {
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
defer close(resize)
// Update the terminal size immediately without waiting
// for a SIGWINCH to get the correct initial size.
resizeEvent := getResize()
for {
if resizeEvent == nil {
select {
case <-ctx.Done():
return
case <-sigchan:
resizeEvent = getResize()
}
} else {
select {
case <-ctx.Done():
return
case <-sigchan:
resizeEvent = getResize()
case resize <- *resizeEvent:
resizeEvent = nil
}
}
}
}()
}
func restoreTerminal(state *term.State) error {
logrus.SetFormatter(&logrus.TextFormatter{})
return term.RestoreTerminal(os.Stdin.Fd(), state)
}
func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
textFormatter := logrus.TextFormatter{}
bytes, err := textFormatter.Format(entry)
if err == nil {
bytes = append(bytes, '\r')
}
return bytes, err
}
// For pod commands that have a latest and all flag, getPodsFromContext gets
// pods the user specifies. If there's an error before getting pods, the pods slice
// will be empty and error will be not nil. If an error occured after, the pod slice
// will hold all of the successful pods, and error will hold the last error.
// The remaining errors will be logged. On success, pods will hold all pods and
// error will be nil.
func getPodsFromContext(c *cliconfig.PodmanCommand, r *libpod.Runtime) ([]*libpod.Pod, error) {
args := c.InputArgs
var pods []*libpod.Pod
var lastError error
var err error
if c.Bool("all") {
pods, err = r.GetAllPods()
if err != nil {
return nil, errors.Wrapf(err, "unable to get running pods")
}
}
if c.Bool("latest") {
pod, err := r.GetLatestPod()
if err != nil {
return nil, errors.Wrapf(err, "unable to get latest pod")
}
pods = append(pods, pod)
}
for _, i := range args {
pod, err := r.LookupPod(i)
if err != nil {
if lastError != nil {
logrus.Errorf("%q", lastError)
}
lastError = errors.Wrapf(err, "unable to find pod %s", i)
continue
}
pods = append(pods, pod)
}
return pods, lastError
}
//printParallelOutput takes the map of parallel worker results and outputs them
// to stdout
func printParallelOutput(m map[string]error, errCount int) error {

View File

@ -225,117 +225,104 @@ type Sockets(
control_socket: string
)
# Create is an input structure for creating containers. It closely resembles the
# CreateConfig structure in libpod/pkg/spec.
# Create is an input structure for creating containers.
type Create (
args: []string,
cap_add: []string,
cap_drop: []string,
conmon_pidfile: string,
cgroup_parent: string,
command: []string,
detach: bool,
devices: []string,
dns_opt: []string,
dns_search: []string,
dns_servers: []string,
entrypoint: []string,
env: [string]string,
exposed_ports: []string,
gidmap: []string,
group_add: []string,
host_add: []string,
hostname: string,
image: string,
image_id: string,
init: bool,
init_path: string,
builtin_imgvolumes: []string,
id_mappings: IDMappingOptions,
image_volume_type: string,
interactive: bool,
ipc_mode: string,
labels: [string]string,
log_driver: string,
log_driver_opt: []string,
name: string,
net_mode: string,
network: string,
pid_mode: string,
pod: string,
privileged: bool,
publish: []string,
publish_all: bool,
quiet: bool,
readonly_rootfs: bool,
resources: CreateResourceConfig,
rm: bool,
shm_dir: string,
stop_signal: int,
stop_timeout: int,
subuidmap: string,
subgidmap: string,
subuidname: string,
subgidname: string,
sys_ctl: [string]string,
tmpfs: []string,
tty: bool,
uidmap: []string,
userns_mode: string,
user: string,
uts_mode: string,
volumes: []string,
work_dir: string,
mount_label: string,
process_label: string,
no_new_privs: bool,
apparmor_profile: string,
seccomp_profile_path: string,
security_opts: []string
)
# CreateResourceConfig is an input structure used to describe host attributes during
# container creation. It is only valid inside a [Create](#Create) type.
type CreateResourceConfig (
blkio_weight: int,
blkio_weight_device: []string,
cpu_period: int,
cpu_quota: int,
cpu_rt_period: int,
cpu_rt_runtime: int,
cpu_shares: int,
cpus: float,
cpuset_cpus: string,
cpuset_mems: string,
device_read_bps: []string,
device_read_iops: []string,
device_write_bps: []string,
device_write_iops: []string,
disable_oomkiller: bool,
kernel_memory: int,
memory: int,
memory_reservation: int,
memory_swap: int,
memory_swappiness: int,
oom_score_adj: int,
pids_limit: int,
shm_size: int,
ulimit: []string
)
# IDMappingOptions is an input structure used to described ids during container creation.
type IDMappingOptions (
host_uid_mapping: bool,
host_gid_mapping: bool,
uid_map: IDMap,
gid_map: IDMap
)
# IDMap is used to describe user name spaces during container creation
type IDMap (
container_id: int,
host_id: int,
size: int
addHost: ?[]string,
annotation: ?[]string,
attach: ?[]string,
blkioWeight: ?string,
blkioWeightDevice: ?[]string,
capAdd: ?[]string,
capDrop: ?[]string,
cgroupParent: ?string,
cidFile: ?string,
conmonPidfile: ?string,
command: ?[]string,
cpuPeriod: ?int,
cpuQuota: ?int,
cpuRtPeriod: ?int,
cpuRtRuntime: ?int,
cpuShares: ?int,
cpus: ?float,
cpuSetCpus: ?string,
cpuSetMems: ?string,
detach: ?bool,
detachKeys: ?string,
device: ?[]string,
deviceReadBps: ?[]string,
deviceReadIops: ?[]string,
deviceWriteBps: ?[]string,
deviceWriteIops: ?[]string,
dns: ?[]string,
dnsOpt: ?[]string,
dnsSearch: ?[]string,
dnsServers: ?[]string,
entrypoint: ?string,
env: ?[]string,
envFile: ?[]string,
expose: ?[]string,
gidmap: ?[]string,
groupadd: ?[]string,
healthcheckCommand: ?string,
healthcheckInterval: ?string,
healthcheckRetries: ?int,
healthcheckStartPeriod: ?string,
healthcheckTimeout:?string,
hostname: ?string,
imageVolume: ?string,
init: ?bool,
initPath: ?string,
interactive: ?bool,
ip: ?string,
ipc: ?string,
kernelMemory: ?string,
label: ?[]string,
labelFile: ?[]string,
logDriver: ?string,
logOpt: ?[]string,
macAddress: ?string,
memory: ?string,
memoryReservation: ?string,
memorySwap: ?string,
memorySwappiness: ?int,
name: ?string,
net: ?string,
network: ?string,
noHosts: ?bool,
oomKillDisable: ?bool,
oomScoreAdj: ?int,
pid: ?string,
pidsLimit: ?int,
pod: ?string,
privileged: ?bool,
publish: ?[]string,
publishAll: ?bool,
quiet: ?bool,
readonly: ?bool,
restart: ?string,
rm: ?bool,
rootfs: ?bool,
securityOpt: ?[]string,
shmSize: ?string,
stopSignal: ?string,
stopTimeout: ?int,
storageOpt: ?[]string,
subuidname: ?string,
subgidname: ?string,
sysctl: ?[]string,
systemd: ?bool,
tmpfs: ?[]string,
tty: ?bool,
uidmap: ?[]string,
ulimit: ?[]string,
user: ?string,
userns: ?string,
uts: ?string,
mount: ?[]string,
volume: ?[]string,
volumesFrom: ?[]string,
workDir: ?string
)
# BuildOptions are are used to describe describe physical attributes of the build
@ -498,16 +485,7 @@ method GetContainer(id: string) -> (container: Container)
# user environment, results might differ from what you expect.
method GetContainersByContext(all: bool, latest: bool, args: []string) -> (containers: []string)
# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. The minimum
# input required for CreateContainer is an image name. If the image name is not found, an [ImageNotFound](#ImageNotFound)
# error will be returned. Otherwise, the ID of the newly created container will be returned.
# #### Example
# ~~~
# $ varlink call unix:/run/podman/io.podman/io.podman.CreateContainer '{"create": {"image": "alpine"}}'
# {
# "container": "8759dafbc0a4dc3bcfb57eeb72e4331eb73c5cc09ab968e65ce45b9ad5c4b6bb"
# }
# ~~~
# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input.
method CreateContainer(create: Create) -> (container: string)
# InspectContainer data takes a name or ID of a container returns the inspection
@ -1130,6 +1108,9 @@ method ContainerStateData(name: string) -> (config: string)
# development of Podman only and generally should not be used.
method PodStateData(name: string) -> (config: string)
# This call is for the development of Podman only and should not be used.
method CreateFromCC(in: []string) -> (id: string)
# Sendfile allows a remote client to send a file to the host
method SendFile(type: string, length: int) -> (file_handle: string)

View File

@ -5,12 +5,17 @@ package adapter
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/pkg/errors"
@ -154,3 +159,148 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions)
}
return nil
}
// CreateContainer creates a libpod container
func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) {
results := shared.NewIntermediateLayer(&c.PodmanCommand)
ctr, _, err := shared.CreateContainer(ctx, &results, r.Runtime)
return ctr.ID(), err
}
// Run a libpod container
func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) {
results := shared.NewIntermediateLayer(&c.PodmanCommand)
ctr, createConfig, err := shared.CreateContainer(ctx, &results, r.Runtime)
if err != nil {
return exitCode, err
}
if logrus.GetLevel() == logrus.DebugLevel {
cgroupPath, err := ctr.CGroupPath()
if err == nil {
logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
}
}
// Handle detached start
if createConfig.Detach {
// if the container was created as part of a pod, also start its dependencies, if any.
if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
exitCode = 126
}
return exitCode, err
}
fmt.Printf("%s\n", ctr.ID())
exitCode = 0
return exitCode, nil
}
outputStream := os.Stdout
errorStream := os.Stderr
inputStream := os.Stdin
// If -i is not set, clear stdin
if !c.Bool("interactive") {
inputStream = nil
}
// If attach is set, clear stdin/stdout/stderr and only attach requested
if c.IsSet("attach") || c.IsSet("a") {
outputStream = nil
errorStream = nil
if !c.Bool("interactive") {
inputStream = nil
}
attachTo := c.StringSlice("attach")
for _, stream := range attachTo {
switch strings.ToLower(stream) {
case "stdout":
outputStream = os.Stdout
case "stderr":
errorStream = os.Stderr
case "stdin":
inputStream = os.Stdin
default:
return exitCode, errors.Wrapf(libpod.ErrInvalidArg, "invalid stream %q for --attach - must be one of stdin, stdout, or stderr", stream)
}
}
}
// if the container was created as part of a pod, also start its dependencies, if any.
if err := StartAttachCtr(ctx, ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true, c.IsSet("pod")); err != nil {
// We've manually detached from the container
// Do not perform cleanup, or wait for container exit code
// Just exit immediately
if errors.Cause(err) == libpod.ErrDetach {
exitCode = 0
return exitCode, nil
}
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
exitCode = 126
}
if c.IsSet("rm") {
if deleteError := r.Runtime.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID())
}
}
return exitCode, err
}
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == libpod.ErrNoSuchCtr {
// The container may have been removed
// Go looking for an exit file
config, err := r.Runtime.GetConfig()
if err != nil {
return exitCode, err
}
ctrExitCode, err := ReadExitFile(config.TmpDir, ctr.ID())
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = 127
} else {
exitCode = ctrExitCode
}
}
} else {
exitCode = int(ecode)
}
if c.IsSet("rm") {
r.Runtime.RemoveContainer(ctx, ctr, false, true)
}
return exitCode, nil
}
// ReadExitFile reads a container's exit file
func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
exitFile := filepath.Join(runtimeTmp, "exits", fmt.Sprintf("%s-old", ctrID))
logrus.Debugf("Attempting to read container %s exit code from file %s", ctrID, exitFile)
// Check if it exists
if _, err := os.Stat(exitFile); err != nil {
return 0, errors.Wrapf(err, "error getting exit file for container %s", ctrID)
}
// File exists, read it in and convert to int
statusStr, err := ioutil.ReadFile(exitFile)
if err != nil {
return 0, errors.Wrapf(err, "error reading exit file for container %s", ctrID)
}
exitCode, err := strconv.Atoi(string(statusStr))
if err != nil {
return 0, errors.Wrapf(err, "error parsing exit code for container %s", ctrID)
}
return exitCode, nil
}

View File

@ -262,3 +262,33 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions)
}
return nil
}
// CreateContainer creates a container from the cli over varlink
func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) {
if !c.Bool("detach") {
// TODO need to add attach when that function becomes available
return "", errors.New("the remote client only supports detached containers")
}
results := shared.NewIntermediateLayer(&c.PodmanCommand)
return iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
}
// Run creates a container overvarlink and then starts it
func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) {
// TODO the exit codes for run need to be figured out for remote connections
if !c.Bool("detach") {
return 0, errors.New("the remote client only supports detached containers")
}
results := shared.NewIntermediateLayer(&c.PodmanCommand)
cid, err := iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
if err != nil {
return 0, err
}
fmt.Println(cid)
_, err = iopodman.StartContainer().Call(r.Conn, cid)
return 0, err
}
func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
return 0, libpod.ErrNotImplemented
}

View File

@ -1,4 +1,4 @@
package main
package adapter
import (
"os"
@ -9,6 +9,7 @@ import (
"github.com/sirupsen/logrus"
)
// ProxySignals ...
func ProxySignals(ctr *libpod.Container) {
sigBuffer := make(chan os.Signal, 128)
signal.CatchAll(sigBuffer)

159
pkg/adapter/terminal.go Normal file
View File

@ -0,0 +1,159 @@
package adapter
import (
"context"
"fmt"
"os"
gosignal "os/signal"
"github.com/containers/libpod/libpod"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
"k8s.io/client-go/tools/remotecommand"
)
// RawTtyFormatter ...
type RawTtyFormatter struct {
}
// StartAttachCtr starts and (if required) attaches to a container
func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error {
resize := make(chan remotecommand.TerminalSize)
haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
// Check if we are attached to a terminal. If we are, generate resize
// events, and set the terminal to raw mode
if haveTerminal && ctr.Spec().Process.Terminal {
logrus.Debugf("Handling terminal attach")
subCtx, cancel := context.WithCancel(ctx)
defer cancel()
resizeTty(subCtx, resize)
oldTermState, err := term.SaveState(os.Stdin.Fd())
if err != nil {
return errors.Wrapf(err, "unable to save terminal state")
}
logrus.SetFormatter(&RawTtyFormatter{})
term.SetRawTerminal(os.Stdin.Fd())
defer restoreTerminal(oldTermState)
}
streams := new(libpod.AttachStreams)
streams.OutputStream = stdout
streams.ErrorStream = stderr
streams.InputStream = stdin
streams.AttachOutput = true
streams.AttachError = true
streams.AttachInput = true
if stdout == nil {
logrus.Debugf("Not attaching to stdout")
streams.AttachOutput = false
}
if stderr == nil {
logrus.Debugf("Not attaching to stderr")
streams.AttachError = false
}
if stdin == nil {
logrus.Debugf("Not attaching to stdin")
streams.AttachInput = false
}
if !startContainer {
if sigProxy {
ProxySignals(ctr)
}
return ctr.Attach(streams, detachKeys, resize)
}
attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive)
if err != nil {
return err
}
if sigProxy {
ProxySignals(ctr)
}
if stdout == nil && stderr == nil {
fmt.Printf("%s\n", ctr.ID())
}
err = <-attachChan
if err != nil {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}
return nil
}
// getResize returns a TerminalSize command matching stdin's current
// size on success, and nil on errors.
func getResize() *remotecommand.TerminalSize {
winsize, err := term.GetWinsize(os.Stdin.Fd())
if err != nil {
logrus.Warnf("Could not get terminal size %v", err)
return nil
}
return &remotecommand.TerminalSize{
Width: winsize.Width,
Height: winsize.Height,
}
}
// Helper for prepareAttach - set up a goroutine to generate terminal resize events
func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) {
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
defer close(resize)
// Update the terminal size immediately without waiting
// for a SIGWINCH to get the correct initial size.
resizeEvent := getResize()
for {
if resizeEvent == nil {
select {
case <-ctx.Done():
return
case <-sigchan:
resizeEvent = getResize()
}
} else {
select {
case <-ctx.Done():
return
case <-sigchan:
resizeEvent = getResize()
case resize <- *resizeEvent:
resizeEvent = nil
}
}
}
}()
}
func restoreTerminal(state *term.State) error {
logrus.SetFormatter(&logrus.TextFormatter{})
return term.RestoreTerminal(os.Stdin.Fd(), state)
}
// Format ...
func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
textFormatter := logrus.TextFormatter{}
bytes, err := textFormatter.Format(entry)
if err == nil {
bytes = append(bytes, '\r')
}
return bytes, err
}

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (
@ -583,27 +585,6 @@ func (i *LibpodAPI) GetContainerStatsWithHistory(call iopodman.VarlinkCall, prev
return call.ReplyGetContainerStatsWithHistory(cStats)
}
// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod
// container stats
func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) libpod.ContainerStats {
cstats := libpod.ContainerStats{
ContainerID: stats.Id,
Name: stats.Name,
CPU: stats.Cpu,
CPUNano: uint64(stats.Cpu_nano),
SystemNano: uint64(stats.System_nano),
MemUsage: uint64(stats.Mem_usage),
MemLimit: uint64(stats.Mem_limit),
MemPerc: stats.Mem_perc,
NetInput: uint64(stats.Net_input),
NetOutput: uint64(stats.Net_output),
BlockInput: uint64(stats.Block_input),
BlockOutput: uint64(stats.Block_output),
PIDs: uint64(stats.Pids),
}
return cstats
}
// GetContainersLogs is the varlink endpoint to obtain one or more container logs
func (i *LibpodAPI) GetContainersLogs(call iopodman.VarlinkCall, names []string, follow, latest bool, since string, tail int64, timestamps bool) error {
var wg sync.WaitGroup

View File

@ -1,220 +1,18 @@
// +build varlink
package varlinkapi
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"syscall"
"github.com/containers/libpod/cmd/podman/shared"
"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, err := i.Runtime.GetConfig()
generic := shared.VarlinkCreateToGeneric(config)
ctr, _, err := shared.CreateContainer(getContext(), &generic, i.Runtime)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
ctx := getContext()
newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil)
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) {
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
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...)
}
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
var ImageVolumes map[string]struct{}
if data != nil && create.Image_volume_type != "ignore" {
ImageVolumes = data.Config.Volumes
}
config := &cc.CreateConfig{
Runtime: runtime,
BuiltinImgVolumes: ImageVolumes,
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: uint16(create.Resources.Blkio_weight),
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: create.Resources.Memory,
MemoryReservation: create.Resources.Memory_reservation,
MemorySwap: create.Resources.Memory_swap,
MemorySwappiness: int(create.Resources.Memory_swappiness),
KernelMemory: create.Resources.Kernel_memory,
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
}

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -0,0 +1,29 @@
// +build varlink remoteclient
package varlinkapi
import (
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
)
// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod
// container stats
func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) libpod.ContainerStats {
cstats := libpod.ContainerStats{
ContainerID: stats.Id,
Name: stats.Name,
CPU: stats.Cpu,
CPUNano: uint64(stats.Cpu_nano),
SystemNano: uint64(stats.System_nano),
MemUsage: uint64(stats.Mem_usage),
MemLimit: uint64(stats.Mem_limit),
MemPerc: stats.Mem_perc,
NetInput: uint64(stats.Net_input),
NetOutput: uint64(stats.Net_output),
BlockInput: uint64(stats.Block_input),
BlockOutput: uint64(stats.Block_output),
PIDs: uint64(stats.Pids),
}
return cstats
}

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (

View File

@ -1,3 +1,5 @@
// +build varlink
package varlinkapi
import (