diff options
author | baude <bbaude@redhat.com> | 2019-03-20 13:00:34 -0500 |
---|---|---|
committer | baude <bbaude@redhat.com> | 2019-04-08 09:05:31 -0500 |
commit | ba65301c955454e47c3893ca548f18a845a4c4a9 (patch) | |
tree | 4704ac2ce61efd5790a0e4dc06560d6eda38bc51 | |
parent | d86729e743fb5a58b9364ee5e991b5db2e9dd600 (diff) | |
download | podman-ba65301c955454e47c3893ca548f18a845a4c4a9.tar.gz podman-ba65301c955454e47c3893ca548f18a845a4c4a9.tar.bz2 podman-ba65301c955454e47c3893ca548f18a845a4c4a9.zip |
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>
33 files changed, 1630 insertions, 859 deletions
@@ -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 diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index 86e89cfd7..f326f53c3 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -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()) } diff --git a/cmd/podman/cliconfig/defaults.go b/cmd/podman/cliconfig/defaults.go new file mode 100644 index 000000000..d5dae0874 --- /dev/null +++ b/cmd/podman/cliconfig/defaults.go @@ -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" +) diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index baa349e1a..e9afcbc06 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -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, diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 10fed053e..ba4a3f519 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -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( diff --git a/cmd/podman/container.go b/cmd/podman/container.go index 743dec32f..d1c42f673 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -53,8 +53,10 @@ var ( _containerExistsCommand, _contInspectSubCommand, _diffCommand, + _createCommand, _listSubCommand, _logsCommand, + _runCommand, } ) diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 984323653..1af3920dd 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -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 } diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 1ba58d1f3..b44cf9f0a 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -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, diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 4bd469106..bac5c3c18 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -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 { - 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 + exitCode, err = runtime.Run(getContext(), c, exitCode) + return err } diff --git a/cmd/podman/run_test.go b/cmd/podman/run_test.go index 0bf9cb4d9..27b34c323 100644 --- a/cmd/podman/run_test.go +++ b/cmd/podman/run_test.go @@ -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 } diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index cd82e4f1c..d694027db 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -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") diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go new file mode 100644 index 000000000..9afbd68c8 --- /dev/null +++ b/cmd/podman/shared/intermediate.go @@ -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} +} diff --git a/cmd/podman/shared/intermediate_novarlink.go b/cmd/podman/shared/intermediate_novarlink.go new file mode 100644 index 000000000..26738ce48 --- /dev/null +++ b/cmd/podman/shared/intermediate_novarlink.go @@ -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 +} diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go new file mode 100644 index 000000000..95a0d6287 --- /dev/null +++ b/cmd/podman/shared/intermediate_varlink.go @@ -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)) +} diff --git a/cmd/podman/start.go b/cmd/podman/start.go index d17a78268..7d97319dd 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -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 diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go index 45d081512..c763940db 100644 --- a/cmd/podman/utils.go +++ b/cmd/podman/utils.go @@ -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" + "github.com/spf13/pflag" ) -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 { diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 92fdcd20f..9098a9297 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -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) diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 932d209cd..1bca99cec 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -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 +} diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 2982d6cbb..3730827c7 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -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 +} diff --git a/cmd/podman/sigproxy.go b/pkg/adapter/sigproxy.go index 16861bad0..af968cb89 100644 --- a/cmd/podman/sigproxy.go +++ b/pkg/adapter/sigproxy.go @@ -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) diff --git a/pkg/adapter/terminal.go b/pkg/adapter/terminal.go new file mode 100644 index 000000000..0b608decf --- /dev/null +++ b/pkg/adapter/terminal.go @@ -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 +} diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go index f557d04e5..e75170547 100644 --- a/pkg/varlinkapi/config.go +++ b/pkg/varlinkapi/config.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index 7a6ae3507..ac1352dac 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -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 diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go index 8990ac001..6b23dce5e 100644 --- a/pkg/varlinkapi/containers_create.go +++ b/pkg/varlinkapi/containers_create.go @@ -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() - 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) + generic := shared.VarlinkCreateToGeneric(config) + ctr, _, err := shared.CreateContainer(getContext(), &generic, i.Runtime) 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 -} diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go index 47c628ead..1e5696fbe 100644 --- a/pkg/varlinkapi/events.go +++ b/pkg/varlinkapi/events.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 8cd13e251..95aa1b335 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go index 3b4fe87e3..63ce44291 100644 --- a/pkg/varlinkapi/mount.go +++ b/pkg/varlinkapi/mount.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index c79cee4c2..ac8e24747 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/remote_client.go b/pkg/varlinkapi/remote_client.go new file mode 100644 index 000000000..dd0613494 --- /dev/null +++ b/pkg/varlinkapi/remote_client.go @@ -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 +} diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index 816143e9f..7f436a954 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go index 9a97bc810..96f76bcdc 100644 --- a/pkg/varlinkapi/transfers.go +++ b/pkg/varlinkapi/transfers.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go index 7e487c03a..3c4b9b79a 100644 --- a/pkg/varlinkapi/util.go +++ b/pkg/varlinkapi/util.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go index 02874d2b1..19ba38e7c 100644 --- a/pkg/varlinkapi/volumes.go +++ b/pkg/varlinkapi/volumes.go @@ -1,3 +1,5 @@ +// +build varlink + package varlinkapi import ( |