From 82feafecdda8040432c008d9b79e4f973009adfc Mon Sep 17 00:00:00 2001 From: baude Date: Wed, 16 May 2018 12:38:17 -0500 Subject: podman create, start, getattachsocket First pass at implement API endpoints for create and start. Signed-off-by: baude Closes: #805 Approved by: baude --- API.md | 260 ++- cmd/podman/create.go | 215 +-- cmd/podman/create_cli.go | 3 +- cmd/podman/inspect.go | 3 +- cmd/podman/parse.go | 105 -- cmd/podman/ps.go | 3 +- cmd/podman/run.go | 3 +- cmd/podman/run_test.go | 3 +- cmd/podman/spec.go | 821 -------- cmd/podman/spec_test.go | 45 - cmd/podman/varlink/io.projectatomic.podman.varlink | 151 +- cmd/podman/varlink/ioprojectatomicpodman.go | 1980 ++++++++++++-------- libpod/container_attach.go | 4 +- libpod/container_internal.go | 12 +- pkg/spec/createconfig.go | 508 +++++ pkg/spec/parse.go | 128 ++ pkg/spec/ports.go | 107 ++ pkg/spec/spec.go | 422 +++++ pkg/spec/spec_test.go | 45 + pkg/varlinkapi/containers.go | 45 +- pkg/varlinkapi/containers_create.go | 243 +++ 21 files changed, 3068 insertions(+), 2038 deletions(-) delete mode 100644 cmd/podman/spec.go delete mode 100644 cmd/podman/spec_test.go create mode 100644 pkg/spec/createconfig.go create mode 100644 pkg/spec/parse.go create mode 100644 pkg/spec/ports.go create mode 100644 pkg/spec/spec.go create mode 100644 pkg/spec/spec_test.go create mode 100644 pkg/varlinkapi/containers_create.go diff --git a/API.md b/API.md index ba569d59a..a722918f1 100755 --- a/API.md +++ b/API.md @@ -9,7 +9,7 @@ in the [API.md](https://github.com/projectatomic/libpod/blob/master/API.md) file [func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool) string](#Commit) -[func CreateContainer() NotImplemented](#CreateContainer) +[func CreateContainer(create: Create) string](#CreateContainer) [func CreateImage() NotImplemented](#CreateImage) @@ -21,6 +21,8 @@ in the [API.md](https://github.com/projectatomic/libpod/blob/master/API.md) file [func ExportImage(name: string, destination: string, compress: bool) string](#ExportImage) +[func GetAttachSockets(name: string) Sockets](#GetAttachSockets) + [func GetContainer(name: string) ListContainerData](#GetContainer) [func GetContainerLogs(name: string) []string](#GetContainerLogs) @@ -69,7 +71,7 @@ in the [API.md](https://github.com/projectatomic/libpod/blob/master/API.md) file [func SearchImage(name: string, limit: int) ImageSearch](#SearchImage) -[func StartContainer() NotImplemented](#StartContainer) +[func StartContainer(name: string) string](#StartContainer) [func StopContainer(name: string, timeout: int) string](#StopContainer) @@ -91,6 +93,14 @@ in the [API.md](https://github.com/projectatomic/libpod/blob/master/API.md) file [type ContainerStats](#ContainerStats) +[type Create](#Create) + +[type CreateResourceConfig](#CreateResourceConfig) + +[type IDMap](#IDMap) + +[type IDMappingOptions](#IDMappingOptions) + [type ImageHistory](#ImageHistory) [type ImageInList](#ImageInList) @@ -111,6 +121,8 @@ in the [API.md](https://github.com/projectatomic/libpod/blob/master/API.md) file [type PodmanInfo](#PodmanInfo) +[type Sockets](#Sockets) + [type StringResponse](#StringResponse) [type Version](#Version) @@ -148,8 +160,8 @@ the resulting image's ID will be returned as a string. ### func CreateContainer
-method CreateContainer() [NotImplemented](#NotImplemented)
-This method is not implemented yet. +method CreateContainer(create: [Create](#Create)) [string](https://godoc.org/builtin#string) +CreateContainer creates a new container from an image. It uses a (Create)[#Create] type for input. ### func CreateImage
@@ -182,6 +194,25 @@ method ExportImage(name: [string](https://godoc.org/builtin#string), destination ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also a booleon option to force compression. Upon completion, the ID of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound) error will be returned. See also [ImportImage](ImportImage). +### func GetAttachSockets +
+ +method GetAttachSockets(name: [string](https://godoc.org/builtin#string)) [Sockets](#Sockets)
+GetAttachSockets takes the name or ID of an existing container. It returns file paths for two sockets needed +to properly communicate with a container. The first is the actual I/O socket that the container uses. The +second is a "control" socket where things like resizing the TTY events are sent. If the container cannot be +found, a [ContainerNotFound](#ContainerNotFound) error will be returned. +#### Example +~~~ +$ varlink call -m unix:/run/io.projectatomic.podman/io.projectatomic.podman.GetAttachSockets '{"name": "b7624e775431219161"}' +{ + "sockets": { + "container_id": "b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca", + "control_socket": "/var/lib/containers/storage/overlay-containers/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/userdata/ctl", + "io_socket": "/var/run/libpod/socket/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/attach" + } +} +~~~ ### func GetContainer
@@ -357,8 +388,8 @@ the image cannot be found in local storage; otherwise the ID of the image will b method RemoveContainer(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)
RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running container can be stopped and removed. Upon sucessful removal of the container, its ID is returned. If the -container cannot be found by name or ID, an [ContainerNotFound](#ContainerNotFound) error will be returned. -#### Error +container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned. +#### Example ~~~ $ varlink call -m unix:/run/podman/io.projectatomic.podman/io.projectatomic.podman.RemoveContainer '{"name": "62f4fd98cb57"}' { @@ -407,8 +438,10 @@ ImageSearch structures which contain information about the image as well as its ### func StartContainer
-method StartContainer() [NotImplemented](#NotImplemented)
-This method has not be implemented yet. +method StartContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)
+StartContainer starts a created or stopped container. It takes the name or ID of container. It returns +the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) +error will be returned. See also [CreateContainer](#CreateContainer). ### func StopContainer
@@ -446,7 +479,7 @@ This method has not be implemented yet.
method WaitContainer(name: [string](https://godoc.org/builtin#string)) [int](https://godoc.org/builtin#int)
-WaitContainer takes the name of ID of a container and waits until the container stops. Upon stopping, the return +WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID or name, a [ContainerNotFound](#ContainerNotFound) error is returned. ## Types @@ -529,6 +562,206 @@ block_output [int](https://godoc.org/builtin#int) block_input [int](https://godoc.org/builtin#int) pids [int](https://godoc.org/builtin#int) +### type Create + +Create is an input structure for creating containers. It closely resembles the +CreateConfig structure in libpod/pkg/spec. + +args [[]string](#[]string) + +cap_add [[]string](#[]string) + +cap_drop [[]string](#[]string) + +conmon_pidfile [string](https://godoc.org/builtin#string) + +cgroup_parent [string](https://godoc.org/builtin#string) + +command [[]string](#[]string) + +detach [bool](https://godoc.org/builtin#bool) + +devices [[]string](#[]string) + +dns_opt [[]string](#[]string) + +dns_search [[]string](#[]string) + +dns_servers [[]string](#[]string) + +entrypoint [[]string](#[]string) + +env [map[string]](#map[string]) + +exposed_ports [[]string](#[]string) + +gidmap [[]string](#[]string) + +group_add [[]string](#[]string) + +host_add [[]string](#[]string) + +hostname [string](https://godoc.org/builtin#string) + +image [string](https://godoc.org/builtin#string) + +image_id [string](https://godoc.org/builtin#string) + +builtin_imgvolumes [[]string](#[]string) + +id_mappings [IDMappingOptions](#IDMappingOptions) + +image_volume_type [string](https://godoc.org/builtin#string) + +interactive [bool](https://godoc.org/builtin#bool) + +ipc_mode [string](https://godoc.org/builtin#string) + +labels [map[string]](#map[string]) + +log_driver [string](https://godoc.org/builtin#string) + +log_driver_opt [[]string](#[]string) + +name [string](https://godoc.org/builtin#string) + +net_mode [string](https://godoc.org/builtin#string) + +network [string](https://godoc.org/builtin#string) + +pid_mode [string](https://godoc.org/builtin#string) + +pod [string](https://godoc.org/builtin#string) + +privileged [bool](https://godoc.org/builtin#bool) + +publish [[]string](#[]string) + +publish_all [bool](https://godoc.org/builtin#bool) + +quiet [bool](https://godoc.org/builtin#bool) + +readonly_rootfs [bool](https://godoc.org/builtin#bool) + +resources [CreateResourceConfig](#CreateResourceConfig) + +rm [bool](https://godoc.org/builtin#bool) + +shm_dir [string](https://godoc.org/builtin#string) + +stop_signal [int](https://godoc.org/builtin#int) + +stop_timeout [int](https://godoc.org/builtin#int) + +subuidmap [string](https://godoc.org/builtin#string) + +subgidmap [string](https://godoc.org/builtin#string) + +subuidname [string](https://godoc.org/builtin#string) + +subgidname [string](https://godoc.org/builtin#string) + +sys_ctl [map[string]](#map[string]) + +tmpfs [[]string](#[]string) + +tty [bool](https://godoc.org/builtin#bool) + +uidmap [[]string](#[]string) + +userns_mode [string](https://godoc.org/builtin#string) + +user [string](https://godoc.org/builtin#string) + +uts_mode [string](https://godoc.org/builtin#string) + +volumes [[]string](#[]string) + +work_dir [string](https://godoc.org/builtin#string) + +mount_label [string](https://godoc.org/builtin#string) + +process_label [string](https://godoc.org/builtin#string) + +no_new_privs [bool](https://godoc.org/builtin#bool) + +apparmor_profile [string](https://godoc.org/builtin#string) + +seccomp_profile_path [string](https://godoc.org/builtin#string) + +security_opts [[]string](#[]string) +### type CreateResourceConfig + +CreateResourceConfig is an input structure used to describe host attributes during +container creation. It is only valid inside a (Create)[#Create] type. + +blkio_weight [int](https://godoc.org/builtin#int) + +blkio_weight_device [[]string](#[]string) + +cpu_period [int](https://godoc.org/builtin#int) + +cpu_quota [int](https://godoc.org/builtin#int) + +cpu_rt_period [int](https://godoc.org/builtin#int) + +cpu_rt_runtime [int](https://godoc.org/builtin#int) + +cpu_shares [int](https://godoc.org/builtin#int) + +cpus [float](https://golang.org/src/builtin/builtin.go#L58) + +cpuset_cpus [string](https://godoc.org/builtin#string) + +cpuset_mems [string](https://godoc.org/builtin#string) + +device_read_bps [[]string](#[]string) + +device_read_iops [[]string](#[]string) + +device_write_bps [[]string](#[]string) + +device_write_iops [[]string](#[]string) + +disable_oomkiller [bool](https://godoc.org/builtin#bool) + +kernel_memory [int](https://godoc.org/builtin#int) + +memory [int](https://godoc.org/builtin#int) + +memory_reservation [int](https://godoc.org/builtin#int) + +memory_swap [int](https://godoc.org/builtin#int) + +memory_swappiness [int](https://godoc.org/builtin#int) + +oom_score_adj [int](https://godoc.org/builtin#int) + +pids_limit [int](https://godoc.org/builtin#int) + +shm_size [int](https://godoc.org/builtin#int) + +ulimit [[]string](#[]string) +### 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) +### 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) ### type ImageHistory ImageHistory describes the returned structure from ImageHistory. @@ -691,6 +924,15 @@ insecure_registries [[]string](#[]string) store [InfoStore](#InfoStore) podman [InfoPodmanBinary](#InfoPodmanBinary) +### type Sockets + +Sockets describes sockets location for a container + +container_id [string](https://godoc.org/builtin#string) + +io_socket [string](https://godoc.org/builtin#string) + +control_socket [string](https://godoc.org/builtin#string) ### type StringResponse diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 7740da8e1..293762ff3 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "net" "os" "strconv" "strings" @@ -21,23 +20,12 @@ import ( "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod/image" "github.com/projectatomic/libpod/pkg/inspect" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) -type mountType string - -// Type constants -const ( - // TypeBind is the type for mounting host dir - TypeBind mountType = "bind" - // TypeVolume is the type for remote storage volumes - // TypeVolume mountType = "volume" // re-enable upon use - // TypeTmpfs is the type for mounting tmpfs - TypeTmpfs mountType = "tmpfs" -) - var ( defaultEnvVariables = map[string]string{ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", @@ -45,100 +33,6 @@ var ( } ) -type createResourceConfig struct { - BlkioWeight uint16 // blkio-weight - BlkioWeightDevice []string // blkio-weight-device - CPUPeriod uint64 // cpu-period - CPUQuota int64 // cpu-quota - CPURtPeriod uint64 // cpu-rt-period - CPURtRuntime int64 // cpu-rt-runtime - CPUShares uint64 // cpu-shares - CPUs float64 // cpus - CPUsetCPUs string - CPUsetMems string // cpuset-mems - DeviceReadBps []string // device-read-bps - DeviceReadIOps []string // device-read-iops - DeviceWriteBps []string // device-write-bps - DeviceWriteIOps []string // device-write-iops - DisableOomKiller bool // oom-kill-disable - KernelMemory int64 // kernel-memory - Memory int64 //memory - MemoryReservation int64 // memory-reservation - MemorySwap int64 //memory-swap - MemorySwappiness int // memory-swappiness - OomScoreAdj int //oom-score-adj - PidsLimit int64 // pids-limit - ShmSize int64 - Ulimit []string //ulimit -} - -type createConfig struct { - Runtime *libpod.Runtime - Args []string - CapAdd []string // cap-add - CapDrop []string // cap-drop - CidFile string - ConmonPidFile string - CgroupParent string // cgroup-parent - Command []string - Detach bool // detach - Devices []string // device - DNSOpt []string //dns-opt - DNSSearch []string //dns-search - DNSServers []string //dns - Entrypoint []string //entrypoint - Env map[string]string //env - ExposedPorts map[nat.Port]struct{} - GroupAdd []string // group-add - HostAdd []string //add-host - Hostname string //hostname - Image string - ImageID string - BuiltinImgVolumes map[string]struct{} // volumes defined in the image config - IDMappings *storage.IDMappingOptions - ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore - Interactive bool //interactive - IpcMode container.IpcMode //ipc - IP6Address string //ipv6 - IPAddress string //ip - Labels map[string]string //label - LinkLocalIP []string // link-local-ip - LogDriver string // log-driver - LogDriverOpt []string // log-opt - MacAddress string //mac-address - Name string //name - NetMode container.NetworkMode //net - Network string //network - NetworkAlias []string //network-alias - PidMode container.PidMode //pid - Pod string //pod - PortBindings nat.PortMap - Privileged bool //privileged - Publish []string //publish - PublishAll bool //publish-all - Quiet bool //quiet - ReadOnlyRootfs bool //read-only - Resources createResourceConfig - Rm bool //rm - ShmDir string - StopSignal syscall.Signal // stop-signal - StopTimeout uint // stop-timeout - Sysctl map[string]string //sysctl - Tmpfs []string // tmpfs - Tty bool //tty - UsernsMode container.UsernsMode //userns - User string //user - UtsMode container.UTSMode //uts - Volumes []string //volume - WorkDir string //workdir - MountLabel string //SecurityOpts - ProcessLabel string //SecurityOpts - NoNewPrivs bool //SecurityOpts - ApparmorProfile string //SecurityOpts - SeccompProfilePath string //SecurityOpts - SecurityOpts []string -} - var createDescription = "Creates a new container from the given image or" + " storage and prepares it for running the specified command. The" + " container ID is then printed to stdout. You can then start it at" + @@ -205,7 +99,7 @@ func createCmd(c *cli.Context) error { } useImageVolumes := createConfig.ImageVolumeType == "bind" - runtimeSpec, err := createConfigToOCISpec(createConfig) + runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) if err != nil { return err } @@ -248,7 +142,7 @@ func createCmd(c *cli.Context) error { return nil } -func parseSecurityOpt(config *createConfig, securityOpts []string) error { +func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error { var ( labelOpts []string err error @@ -338,95 +232,9 @@ func isPortInImagePorts(exposedPorts map[string]struct{}, port string) bool { return false } -func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[nat.Port][]nat.PortBinding, error) { - containerPorts := make(map[string]string) - - // add expose ports from the image itself - for expose := range imageExposedPorts { - _, port := nat.SplitProtoPort(expose) - containerPorts[port] = "" - } - - // add the expose ports from the user (--expose) - // can be single or a range - for _, expose := range c.StringSlice("expose") { - //support two formats for expose, original format /[] or /[] - _, port := nat.SplitProtoPort(expose) - //parse the start and end port and create a sequence of ports to expose - //if expose a port, the start and end port are the same - start, end, err := nat.ParsePortRange(port) - if err != nil { - return nil, fmt.Errorf("invalid range format for --expose: %s, error: %s", expose, err) - } - for i := start; i <= end; i++ { - containerPorts[strconv.Itoa(int(i))] = "" - } - } - - // parse user input'd port bindings - pbPorts, portBindings, err := nat.ParsePortSpecs(c.StringSlice("publish")) - if err != nil { - return nil, err - } - - // delete exposed container ports if being used by -p - for i := range pbPorts { - delete(containerPorts, i.Port()) - } - - // iterate container ports and make port bindings from them - if c.Bool("publish-all") { - for e := range containerPorts { - //support two formats for expose, original format /[] or /[] - //proto, port := nat.SplitProtoPort(e) - p, err := nat.NewPort("tcp", e) - if err != nil { - return nil, err - } - rp, err := getRandomPort() - if err != nil { - return nil, err - } - logrus.Debug(fmt.Sprintf("Using random host port %d with container port %d", rp, p.Int())) - portBindings[p] = CreatePortBinding(rp, "") - } - } - - // We need to see if any host ports are not populated and if so, we need to assign a - // random port to them. - for k, pb := range portBindings { - if pb[0].HostPort == "" { - hostPort, err := getRandomPort() - if err != nil { - return nil, err - } - logrus.Debug(fmt.Sprintf("Using random host port %d with container port %s", hostPort, k.Port())) - pb[0].HostPort = strconv.Itoa(hostPort) - } - } - return portBindings, nil -} - -func getRandomPort() (int, error) { - l, err := net.Listen("tcp", ":0") - if err != nil { - return 0, errors.Wrapf(err, "unable to get free port") - } - defer l.Close() - _, randomPort, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return 0, errors.Wrapf(err, "unable to determine free port") - } - rp, err := strconv.Atoi(randomPort) - if err != nil { - return 0, errors.Wrapf(err, "unable to convert random port to int") - } - return rp, nil -} - // 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 *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*createConfig, error) { +func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) { var ( inputCommand, command []string memoryLimit, memoryReservation, memorySwap, memoryKernel int64 @@ -605,7 +413,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } // EXPOSED PORTS - portBindings, err := exposedPorts(c, data.ContainerConfig.ExposedPorts) + portBindings, err := cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.ContainerConfig.ExposedPorts) if err != nil { return nil, err } @@ -656,7 +464,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim return nil, errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.String("image-volume")) } - config := &createConfig{ + config := &cc.CreateConfig{ Runtime: runtime, BuiltinImgVolumes: ImageVolumes, ConmonPidFile: c.String("conmon-pidfile"), @@ -701,7 +509,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim PortBindings: portBindings, Quiet: c.Bool("quiet"), ReadOnlyRootfs: c.Bool("read-only"), - Resources: createResourceConfig{ + Resources: cc.CreateResourceConfig{ BlkioWeight: blkioWeight, BlkioWeightDevice: c.StringSlice("blkio-weight-device"), CPUShares: c.Uint64("cpu-shares"), @@ -756,12 +564,3 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } return config, nil } - -//CreatePortBinding takes port (int) and IP (string) and creates an array of portbinding structs -func CreatePortBinding(hostPort int, hostIP string) []nat.PortBinding { - pb := nat.PortBinding{ - HostPort: strconv.Itoa(hostPort), - } - pb.HostIP = hostIP - return []nat.PortBinding{pb} -} diff --git a/cmd/podman/create_cli.go b/cmd/podman/create_cli.go index 11a5d3533..8ae4b6c64 100644 --- a/cmd/podman/create_cli.go +++ b/cmd/podman/create_cli.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/pkg/sysinfo" "github.com/pkg/errors" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/sirupsen/logrus" ) @@ -141,7 +142,7 @@ func validateVolumeOpts(option string) error { return nil } -func verifyContainerResources(config *createConfig, update bool) ([]string, error) { +func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) { warnings := []string{} sysInfo := sysinfo.New(true) diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 0fd1760a9..abc9cfb39 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -11,6 +11,7 @@ import ( "github.com/projectatomic/libpod/cmd/podman/libpodruntime" "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/pkg/inspect" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -183,7 +184,7 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI pidsLimit := getPidsInfo(spec) cgroup := getCgroup(spec) - var createArtifact createConfig + var createArtifact cc.CreateConfig artifact, err := ctr.GetArtifact("create-config") if err == nil { if err := json.Unmarshal(artifact, &createArtifact); err != nil { diff --git a/cmd/podman/parse.go b/cmd/podman/parse.go index 484b9723f..22197ba20 100644 --- a/cmd/podman/parse.go +++ b/cmd/podman/parse.go @@ -16,7 +16,6 @@ import ( "strconv" "strings" - units "github.com/docker/go-units" "github.com/pkg/errors" ) @@ -107,40 +106,6 @@ func validateBlkioWeight(val int64) (int64, error) { //nolint return -1, errors.Errorf("invalid blkio weight %q, should be between 10 and 1000", val) } -// weightDevice is a structure that holds device:weight pair -type weightDevice struct { - path string - weight uint16 -} - -func (w *weightDevice) String() string { - return fmt.Sprintf("%s:%d", w.path, w.weight) -} - -// validateweightDevice validates that the specified string has a valid device-weight format -// for blkio-weight-device flag -func validateweightDevice(val string) (*weightDevice, error) { - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return nil, fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return nil, fmt.Errorf("bad format for device path: %s", val) - } - weight, err := strconv.ParseUint(split[1], 10, 0) - if err != nil { - return nil, fmt.Errorf("invalid weight for device: %s", val) - } - if weight > 0 && (weight < 10 || weight > 1000) { - return nil, fmt.Errorf("invalid weight for device: %s", val) - } - - return &weightDevice{ - path: split[0], - weight: uint16(weight), - }, nil -} - // parseDevice parses a device mapping string to a container.DeviceMapping struct // for device flag func parseDevice(device string) (*HostDevice, error) { //nolint @@ -250,64 +215,6 @@ func validatePath(val string, validator func(string) bool) (string, error) { return val, nil } -// throttleDevice is a structure that holds device:rate_per_second pair -type throttleDevice struct { - path string - rate uint64 -} - -func (t *throttleDevice) String() string { - return fmt.Sprintf("%s:%d", t.path, t.rate) -} - -// validateBpsDevice validates that the specified string has a valid device-rate format -// for device-read-bps and device-write-bps flags -func validateBpsDevice(val string) (*throttleDevice, error) { - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return nil, fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return nil, fmt.Errorf("bad format for device path: %s", val) - } - rate, err := units.RAMInBytes(split[1]) - if err != nil { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :[]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) - } - if rate < 0 { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :[]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) - } - - return &throttleDevice{ - path: split[0], - rate: uint64(rate), - }, nil -} - -// validateIOpsDevice validates that the specified string has a valid device-rate format -// for device-write-iops and device-read-iops flags -func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return nil, fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return nil, fmt.Errorf("bad format for device path: %s", val) - } - rate, err := strconv.ParseUint(split[1], 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :. Number must be a positive integer", val) - } - if rate < 0 { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :. Number must be a positive integer", val) - } - - return &throttleDevice{ - path: split[0], - rate: uint64(rate), - }, nil -} - // validateDNSSearch validates domain for resolvconf search configuration. // A zero length domain is represented by a dot (.). // for dns-search flag @@ -805,18 +712,6 @@ func stringSlicetoUint32Slice(inputSlice []string) ([]uint32, error) { return outputSlice, nil } -func getLoggingPath(opts []string) string { - for _, opt := range opts { - arr := strings.SplitN(opt, "=", 2) - if len(arr) == 2 { - if strings.TrimSpace(arr[0]) == "path" { - return strings.TrimSpace(arr[1]) - } - } - } - return "" -} - // validateFileName returns an error if filename contains ":" // as it is currently not supported func validateFileName(filename string) error { diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index a0b6f134b..9f5bdfc26 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -16,6 +16,7 @@ import ( "github.com/projectatomic/libpod/cmd/podman/formats" "github.com/projectatomic/libpod/cmd/podman/libpodruntime" "github.com/projectatomic/libpod/libpod" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -401,7 +402,7 @@ func getTemplateOutput(containers []*libpod.Container, opts batchcontainer.PsOpt createdAt := batchInfo.ConConfig.CreatedTime.Format("2006-01-02 15:04:05 -0700 MST") imageName := batchInfo.ConConfig.RootfsImageName - var createArtifact createConfig + var createArtifact cc.CreateConfig artifact, err := ctr.GetArtifact("create-config") if err == nil { if err := json.Unmarshal(artifact, &createArtifact); err != nil { diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 79e238da0..f12a241fa 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -14,6 +14,7 @@ import ( "github.com/projectatomic/libpod/cmd/podman/libpodruntime" "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod/image" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -91,7 +92,7 @@ func runCmd(c *cli.Context) error { } useImageVolumes := createConfig.ImageVolumeType == "bind" - runtimeSpec, err := createConfigToOCISpec(createConfig) + runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) if err != nil { return err } diff --git a/cmd/podman/run_test.go b/cmd/podman/run_test.go index bbcdcc60a..e2d500187 100644 --- a/cmd/podman/run_test.go +++ b/cmd/podman/run_test.go @@ -7,6 +7,7 @@ import ( ociv1 "github.com/opencontainers/image-spec/specs-go/v1" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/projectatomic/libpod/pkg/inspect" + cc "github.com/projectatomic/libpod/pkg/spec" "github.com/stretchr/testify/assert" "github.com/urfave/cli" ) @@ -80,7 +81,7 @@ func getRuntimeSpec(c *cli.Context) (*spec.Spec, error) { if err != nil { return nil, err } - runtimeSpec, err := createConfigToOCISpec(createConfig) + runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) if err != nil { return nil, err } diff --git a/cmd/podman/spec.go b/cmd/podman/spec.go deleted file mode 100644 index 747d76359..000000000 --- a/cmd/podman/spec.go +++ /dev/null @@ -1,821 +0,0 @@ -package main - -import ( - "io/ioutil" - "os" - "strconv" - "strings" - - "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/docker/docker/daemon/caps" - "github.com/docker/docker/pkg/mount" - "github.com/docker/docker/profiles/seccomp" - "github.com/docker/go-units" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/devices" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" - "github.com/projectatomic/libpod/libpod" - ann "github.com/projectatomic/libpod/pkg/annotations" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -const cpuPeriod = 100000 - -func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } -func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } - -func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator) { - if !config.Privileged { - for _, mp := range []string{ - "/proc/kcore", - "/proc/latency_stats", - "/proc/timer_list", - "/proc/timer_stats", - "/proc/sched_debug", - "/proc/scsi", - "/sys/firmware", - } { - g.AddLinuxMaskedPaths(mp) - } - - for _, rp := range []string{ - "/proc/asound", - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger", - } { - g.AddLinuxReadonlyPaths(rp) - } - } -} - -func addPidNS(config *createConfig, g *generate.Generator) error { - pidMode := config.PidMode - if pidMode.IsHost() { - return g.RemoveLinuxNamespace(string(spec.PIDNamespace)) - } - if pidMode.IsContainer() { - logrus.Debug("using container pidmode") - } - return nil -} - -func addUserNS(config *createConfig, g *generate.Generator) error { - if (len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0) && !config.UsernsMode.IsHost() { - g.AddOrReplaceLinuxNamespace(spec.UserNamespace, "") - } - return nil -} - -func addNetNS(config *createConfig, g *generate.Generator) error { - netMode := config.NetMode - if netMode.IsHost() { - logrus.Debug("Using host netmode") - return g.RemoveLinuxNamespace(spec.NetworkNamespace) - } else if netMode.IsNone() { - logrus.Debug("Using none netmode") - return nil - } else if netMode.IsBridge() { - logrus.Debug("Using bridge netmode") - return nil - } else if netMode.IsContainer() { - logrus.Debug("Using container netmode") - } else { - return errors.Errorf("unknown network mode") - } - return nil -} - -func addUTSNS(config *createConfig, g *generate.Generator) error { - utsMode := config.UtsMode - if utsMode.IsHost() { - return g.RemoveLinuxNamespace(spec.UTSNamespace) - } - return nil -} - -func addIpcNS(config *createConfig, g *generate.Generator) error { - ipcMode := config.IpcMode - if ipcMode.IsHost() { - return g.RemoveLinuxNamespace(spec.IPCNamespace) - } - if ipcMode.IsContainer() { - logrus.Debug("Using container ipcmode") - } - - return nil -} - -func addRlimits(config *createConfig, g *generate.Generator) error { - var ( - ul *units.Ulimit - err error - ) - - for _, u := range config.Resources.Ulimit { - if ul, err = units.ParseUlimit(u); err != nil { - return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u) - } - - g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft)) - } - return nil -} - -func setupCapabilities(config *createConfig, configSpec *spec.Spec) error { - var err error - var caplist []string - caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, config.CapAdd, config.CapDrop) - if err != nil { - return err - } - - configSpec.Process.Capabilities.Bounding = caplist - configSpec.Process.Capabilities.Permitted = caplist - configSpec.Process.Capabilities.Inheritable = caplist - configSpec.Process.Capabilities.Effective = caplist - return nil -} - -func addDevice(g *generate.Generator, device string) error { - dev, err := devices.DeviceFromPath(device, "rwm") - if err != nil { - return errors.Wrapf(err, "%s is not a valid device", device) - } - linuxdev := spec.LinuxDevice{ - Path: dev.Path, - Type: string(dev.Type), - Major: dev.Major, - Minor: dev.Minor, - FileMode: &dev.FileMode, - UID: &dev.Uid, - GID: &dev.Gid, - } - g.AddDevice(linuxdev) - g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, dev.Permissions) - return nil -} - -// Parses information needed to create a container into an OCI runtime spec -func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) { - cgroupPerm := "ro" - g := generate.New() - g.HostSpecific = true - addCgroup := true - if config.Privileged { - cgroupPerm = "rw" - g.RemoveMount("/sys") - sysMnt := spec.Mount{ - Destination: "/sys", - Type: "sysfs", - Source: "sysfs", - Options: []string{"nosuid", "noexec", "nodev", "rw"}, - } - g.AddMount(sysMnt) - } else if !config.UsernsMode.IsHost() && config.NetMode.IsHost() { - addCgroup = false - g.RemoveMount("/sys") - sysMnt := spec.Mount{ - Destination: "/sys", - Type: "bind", - Source: "/sys", - Options: []string{"nosuid", "noexec", "nodev", "ro", "rbind"}, - } - g.AddMount(sysMnt) - } - - if addCgroup { - cgroupMnt := spec.Mount{ - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"nosuid", "noexec", "nodev", "relatime", cgroupPerm}, - } - g.AddMount(cgroupMnt) - } - g.SetProcessCwd(config.WorkDir) - g.SetProcessArgs(config.Command) - g.SetProcessTerminal(config.Tty) - - for key, val := range config.GetAnnotations() { - g.AddAnnotation(key, val) - } - g.SetRootReadonly(config.ReadOnlyRootfs) - g.SetHostname(config.Hostname) - if config.Hostname != "" { - g.AddProcessEnv("HOSTNAME", config.Hostname) - } - for sysctlKey, sysctlVal := range config.Sysctl { - g.AddLinuxSysctl(sysctlKey, sysctlVal) - } - g.AddProcessEnv("container", "podman") - - // RESOURCES - MEMORY - if config.Resources.Memory != 0 { - g.SetLinuxResourcesMemoryLimit(config.Resources.Memory) - } - if config.Resources.MemoryReservation != 0 { - g.SetLinuxResourcesMemoryReservation(config.Resources.MemoryReservation) - } - if config.Resources.MemorySwap != 0 { - g.SetLinuxResourcesMemorySwap(config.Resources.MemorySwap) - } - if config.Resources.KernelMemory != 0 { - g.SetLinuxResourcesMemoryKernel(config.Resources.KernelMemory) - } - if config.Resources.MemorySwappiness != -1 { - g.SetLinuxResourcesMemorySwappiness(uint64(config.Resources.MemorySwappiness)) - } - g.SetLinuxResourcesMemoryDisableOOMKiller(config.Resources.DisableOomKiller) - g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj) - - // RESOURCES - CPU - if config.Resources.CPUShares != 0 { - g.SetLinuxResourcesCPUShares(config.Resources.CPUShares) - } - if config.Resources.CPUQuota != 0 { - g.SetLinuxResourcesCPUQuota(config.Resources.CPUQuota) - } - if config.Resources.CPUPeriod != 0 { - g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod) - } - if config.Resources.CPUs != 0 { - g.SetLinuxResourcesCPUPeriod(cpuPeriod) - g.SetLinuxResourcesCPUQuota(int64(config.Resources.CPUs * cpuPeriod)) - } - if config.Resources.CPURtRuntime != 0 { - g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime) - } - if config.Resources.CPURtPeriod != 0 { - g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod) - } - if config.Resources.CPUsetCPUs != "" { - g.SetLinuxResourcesCPUCpus(config.Resources.CPUsetCPUs) - } - if config.Resources.CPUsetMems != "" { - g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems) - } - - // Devices - if config.Privileged { - // If privileged, we need to add all the host devices to the - // spec. We do not add the user provided ones because we are - // already adding them all. - if err := config.AddPrivilegedDevices(&g); err != nil { - return nil, err - } - } else { - for _, device := range config.Devices { - if err := addDevice(&g, device); err != nil { - return nil, err - } - } - } - - for _, uidmap := range config.IDMappings.UIDMap { - g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size)) - } - for _, gidmap := range config.IDMappings.GIDMap { - g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size)) - } - // SECURITY OPTS - g.SetProcessNoNewPrivileges(config.NoNewPrivs) - g.SetProcessApparmorProfile(config.ApparmorProfile) - g.SetProcessSelinuxLabel(config.ProcessLabel) - g.SetLinuxMountLabel(config.MountLabel) - blockAccessToKernelFilesystems(config, &g) - - // RESOURCES - PIDS - if config.Resources.PidsLimit != 0 { - g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit) - } - - for _, i := range config.Tmpfs { - // Default options if nothing passed - options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"} - spliti := strings.SplitN(i, ":", 2) - if len(spliti) > 1 { - if _, _, err := mount.ParseTmpfsOptions(spliti[1]); err != nil { - return nil, err - } - options = strings.Split(spliti[1], ",") - } - tmpfsMnt := spec.Mount{ - Destination: spliti[0], - Type: "tmpfs", - Source: "tmpfs", - Options: append(options, "tmpcopyup"), - } - g.AddMount(tmpfsMnt) - } - - for name, val := range config.Env { - g.AddProcessEnv(name, val) - } - - if err := addRlimits(config, &g); err != nil { - return nil, err - } - - if err := addPidNS(config, &g); err != nil { - return nil, err - } - - if err := addUserNS(config, &g); err != nil { - return nil, err - } - - if err := addNetNS(config, &g); err != nil { - return nil, err - } - - if err := addUTSNS(config, &g); err != nil { - return nil, err - } - - if err := addIpcNS(config, &g); err != nil { - return nil, err - } - configSpec := g.Spec() - - // HANDLE CAPABILITIES - // NOTE: Must happen before SECCOMP - if !config.Privileged { - if err := setupCapabilities(config, configSpec); err != nil { - return nil, err - } - } else { - g.SetupPrivileged(true) - } - - // HANDLE SECCOMP - if config.SeccompProfilePath != "unconfined" { - if config.SeccompProfilePath != "" { - seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath) - if err != nil { - return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath) - } - seccompConfig, err := seccomp.LoadProfile(string(seccompProfile), configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) - } - configSpec.Linux.Seccomp = seccompConfig - } else { - seccompConfig, err := seccomp.GetDefaultProfile(configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) - } - configSpec.Linux.Seccomp = seccompConfig - } - } - - // Clear default Seccomp profile from Generator for privileged containers - if config.SeccompProfilePath == "unconfined" || config.Privileged { - configSpec.Linux.Seccomp = nil - } - - // BIND MOUNTS - mounts, err := config.GetVolumeMounts(configSpec.Mounts) - if err != nil { - return nil, errors.Wrapf(err, "error getting volume mounts") - } - configSpec.Mounts = append(configSpec.Mounts, mounts...) - for _, mount := range configSpec.Mounts { - for _, opt := range mount.Options { - switch opt { - case "private", "rprivate", "slave", "rslave", "shared", "rshared": - if err := g.SetLinuxRootPropagation(opt); err != nil { - return nil, errors.Wrapf(err, "error setting root propagation for %q", mount.Destination) - } - } - } - } - - // BLOCK IO - blkio, err := config.createBlockIO() - if err != nil { - return nil, errors.Wrapf(err, "error creating block io") - } - if blkio != nil { - configSpec.Linux.Resources.BlockIO = blkio - } - - /* - //Annotations - Resources: &configSpec.LinuxResources{ - BlockIO: &blkio, - //HugepageLimits: - Network: &configSpec.LinuxNetwork{ - // ClassID *uint32 - // Priorites []LinuxInterfacePriority - }, - }, - //CgroupsPath: - //Namespaces: []LinuxNamespace - // DefaultAction: - // Architectures - // Syscalls: - }, - // RootfsPropagation - // MaskedPaths - // ReadonlyPaths: - // IntelRdt - }, - } - */ - return configSpec, nil -} - -const ( - bps = iota - iops -) - -func (c *createConfig) createBlockIO() (*spec.LinuxBlockIO, error) { - bio := &spec.LinuxBlockIO{} - bio.Weight = &c.Resources.BlkioWeight - if len(c.Resources.BlkioWeightDevice) > 0 { - var lwds []spec.LinuxWeightDevice - for _, i := range c.Resources.BlkioWeightDevice { - wd, err := validateweightDevice(i) - if err != nil { - return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") - } - wdStat, err := getStatFromPath(wd.path) - if err != nil { - return bio, errors.Wrapf(err, "error getting stat from path %q", wd.path) - } - lwd := spec.LinuxWeightDevice{ - Weight: &wd.weight, - } - lwd.Major = int64(unix.Major(wdStat.Rdev)) - lwd.Minor = int64(unix.Minor(wdStat.Rdev)) - lwds = append(lwds, lwd) - } - bio.WeightDevice = lwds - } - if len(c.Resources.DeviceReadBps) > 0 { - readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps) - if err != nil { - return bio, err - } - bio.ThrottleReadBpsDevice = readBps - } - if len(c.Resources.DeviceWriteBps) > 0 { - writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps) - if err != nil { - return bio, err - } - bio.ThrottleWriteBpsDevice = writeBpds - } - if len(c.Resources.DeviceReadIOps) > 0 { - readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops) - if err != nil { - return bio, err - } - bio.ThrottleReadIOPSDevice = readIOps - } - if len(c.Resources.DeviceWriteIOps) > 0 { - writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops) - if err != nil { - return bio, err - } - bio.ThrottleWriteIOPSDevice = writeIOps - } - return bio, nil -} - -func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { - var ( - ltds []spec.LinuxThrottleDevice - t *throttleDevice - err error - ) - for _, i := range throttleInput { - if rateType == bps { - t, err = validateBpsDevice(i) - } else { - t, err = validateIOpsDevice(i) - } - if err != nil { - return []spec.LinuxThrottleDevice{}, err - } - ltdStat, err := getStatFromPath(t.path) - if err != nil { - return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path) - } - ltd := spec.LinuxThrottleDevice{ - Rate: t.rate, - } - ltd.Major = int64(unix.Major(ltdStat.Rdev)) - ltd.Minor = int64(unix.Minor(ltdStat.Rdev)) - ltds = append(ltds, ltd) - } - return ltds, nil -} - -// GetAnnotations returns the all the annotations for the container -func (c *createConfig) GetAnnotations() map[string]string { - a := getDefaultAnnotations() - // TODO - Which annotations do we want added by default - // TODO - This should be added to the DB long term - if c.Tty { - a["io.kubernetes.cri-o.TTY"] = "true" - } - return a -} - -func getDefaultAnnotations() map[string]string { - var annotations map[string]string - annotations = make(map[string]string) - annotations[ann.Annotations] = "" - annotations[ann.ContainerID] = "" - annotations[ann.ContainerName] = "" - annotations[ann.ContainerType] = "sandbox" - annotations[ann.Created] = "" - annotations[ann.HostName] = "" - annotations[ann.IP] = "" - annotations[ann.Image] = "" - annotations[ann.ImageName] = "" - annotations[ann.ImageRef] = "" - annotations[ann.KubeName] = "" - annotations[ann.Labels] = "" - annotations[ann.LogPath] = "" - annotations[ann.Metadata] = "" - annotations[ann.Name] = "" - annotations[ann.PrivilegedRuntime] = "" - annotations[ann.ResolvPath] = "" - annotations[ann.HostnamePath] = "" - annotations[ann.SandboxID] = "" - annotations[ann.SandboxName] = "" - annotations[ann.ShmPath] = "" - annotations[ann.MountPoint] = "" - annotations[ann.TrustedSandbox] = "" - annotations[ann.TTY] = "false" - annotations[ann.Stdin] = "" - annotations[ann.StdinOnce] = "" - annotations[ann.Volumes] = "" - - return annotations -} - -//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs -func (c *createConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) { - var m []spec.Mount - var options []string - for _, i := range c.Volumes { - // We need to handle SELinux options better here, specifically :Z - spliti := strings.Split(i, ":") - if len(spliti) > 2 { - options = strings.Split(spliti[2], ",") - } - if libpod.MountExists(specMounts, spliti[1]) { - continue - } - options = append(options, "rbind") - var foundrw, foundro, foundz, foundZ bool - var rootProp string - for _, opt := range options { - switch opt { - case "rw": - foundrw = true - case "ro": - foundro = true - case "z": - foundz = true - case "Z": - foundZ = true - case "private", "rprivate", "slave", "rslave", "shared", "rshared": - rootProp = opt - } - } - if !foundrw && !foundro { - options = append(options, "rw") - } - if foundz { - if err := label.Relabel(spliti[0], c.MountLabel, true); err != nil { - return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) - } - } - if foundZ { - if err := label.Relabel(spliti[0], c.MountLabel, false); err != nil { - return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) - } - } - if rootProp == "" { - options = append(options, "private") - } - - m = append(m, spec.Mount{ - Destination: spliti[1], - Type: string(TypeBind), - Source: spliti[0], - Options: options, - }) - } - - // volumes from image config - if c.ImageVolumeType != "tmpfs" { - return m, nil - } - for vol := range c.BuiltinImgVolumes { - if libpod.MountExists(specMounts, vol) { - continue - } - mount := spec.Mount{ - Destination: vol, - Type: string(TypeTmpfs), - Source: string(TypeTmpfs), - Options: []string{"rw", "noexec", "nosuid", "nodev", "tmpcopyup"}, - } - m = append(m, mount) - } - return m, nil -} - -//GetTmpfsMounts takes user provided input for Tmpfs mounts and creates Mount structs -func (c *createConfig) GetTmpfsMounts() []spec.Mount { - var m []spec.Mount - for _, i := range c.Tmpfs { - // Default options if nothing passed - options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"} - spliti := strings.Split(i, ":") - destPath := spliti[0] - if len(spliti) > 1 { - options = strings.Split(spliti[1], ",") - } - m = append(m, spec.Mount{ - Destination: destPath, - Type: string(TypeTmpfs), - Options: options, - Source: string(TypeTmpfs), - }) - } - return m -} - -func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, error) { - var options []libpod.CtrCreateOption - var portBindings []ocicni.PortMapping - var err error - - // Uncomment after talking to mheon about unimplemented funcs - // options = append(options, libpod.WithLabels(c.labels)) - - if c.Interactive { - options = append(options, libpod.WithStdin()) - } - if c.Name != "" { - logrus.Debugf("appending name %s", c.Name) - options = append(options, libpod.WithName(c.Name)) - } - - if len(c.PortBindings) > 0 { - portBindings, err = c.CreatePortBindings() - if err != nil { - return nil, errors.Wrapf(err, "unable to create port bindings") - } - } - - if len(c.Volumes) != 0 { - // Volumes consist of multiple, comma-delineated fields - // The image spec only includes one part of that, so drop the - // others, if they are included - volumes := make([]string, 0, len(c.Volumes)) - for _, vol := range c.Volumes { - volumes = append(volumes, strings.SplitN(vol, ":", 2)[0]) - } - - options = append(options, libpod.WithUserVolumes(volumes)) - } - - if len(c.Command) != 0 { - options = append(options, libpod.WithCommand(c.Command)) - } - - // Add entrypoint unconditionally - // If it's empty it's because it was explicitly set to "" or the image - // does not have one - options = append(options, libpod.WithEntrypoint(c.Entrypoint)) - - if c.NetMode.IsContainer() { - connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer()) - } - options = append(options, libpod.WithNetNSFrom(connectedCtr)) - } else if !c.NetMode.IsHost() && !c.NetMode.IsNone() { - postConfigureNetNS := (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() - options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}, postConfigureNetNS)) - options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS)) - } - - if c.PidMode.IsContainer() { - connectedCtr, err := c.Runtime.LookupContainer(c.PidMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container()) - } - - options = append(options, libpod.WithPIDNSFrom(connectedCtr)) - } - if c.IpcMode.IsContainer() { - connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container()) - } - - options = append(options, libpod.WithIPCNSFrom(connectedCtr)) - } - - options = append(options, libpod.WithStopSignal(c.StopSignal)) - options = append(options, libpod.WithStopTimeout(c.StopTimeout)) - if len(c.DNSSearch) > 0 { - options = append(options, libpod.WithDNSSearch(c.DNSSearch)) - } - if len(c.DNSServers) > 0 { - options = append(options, libpod.WithDNS(c.DNSServers)) - } - if len(c.DNSOpt) > 0 { - options = append(options, libpod.WithDNSOption(c.DNSOpt)) - } - if len(c.HostAdd) > 0 { - options = append(options, libpod.WithHosts(c.HostAdd)) - } - logPath := getLoggingPath(c.LogDriverOpt) - if logPath != "" { - options = append(options, libpod.WithLogPath(logPath)) - } - - options = append(options, libpod.WithPrivileged(c.Privileged)) - return options, nil -} - -func getStatFromPath(path string) (unix.Stat_t, error) { - s := unix.Stat_t{} - err := unix.Stat(path, &s) - return s, err -} - -// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands -func (c *createConfig) CreatePortBindings() ([]ocicni.PortMapping, error) { - var portBindings []ocicni.PortMapping - for containerPb, hostPb := range c.PortBindings { - var pm ocicni.PortMapping - pm.ContainerPort = int32(containerPb.Int()) - for _, i := range hostPb { - var hostPort int - var err error - pm.HostIP = i.HostIP - if i.HostPort == "" { - hostPort = containerPb.Int() - } else { - hostPort, err = strconv.Atoi(i.HostPort) - if err != nil { - return nil, errors.Wrapf(err, "unable to convert host port to integer") - } - } - - pm.HostPort = int32(hostPort) - // CNI requires us to make both udp and tcp structs - pm.Protocol = "udp" - portBindings = append(portBindings, pm) - pm.Protocol = "tcp" - portBindings = append(portBindings, pm) - } - } - return portBindings, nil -} - -// AddPrivilegedDevices iterates through host devices and adds all -// host devices to the spec -func (c *createConfig) AddPrivilegedDevices(g *generate.Generator) error { - hostDevices, err := devices.HostDevices() - if err != nil { - return err - } - g.ClearLinuxDevices() - for _, d := range hostDevices { - g.AddDevice(Device(d)) - } - g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") - return nil -} - -// Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. -func Device(d *configs.Device) spec.LinuxDevice { - return spec.LinuxDevice{ - Type: string(d.Type), - Path: d.Path, - Major: d.Major, - Minor: d.Minor, - FileMode: fmPtr(int64(d.FileMode)), - UID: u32Ptr(int64(d.Uid)), - GID: u32Ptr(int64(d.Gid)), - } -} diff --git a/cmd/podman/spec_test.go b/cmd/podman/spec_test.go deleted file mode 100644 index 1e1064df9..000000000 --- a/cmd/podman/spec_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "reflect" - "testing" - - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/stretchr/testify/assert" -) - -func TestCreateConfig_GetVolumeMounts(t *testing.T) { - data := spec.Mount{ - Destination: "/foobar", - Type: "bind", - Source: "foobar", - Options: []string{"ro", "rbind", "private"}, - } - config := createConfig{ - Volumes: []string{"foobar:/foobar:ro"}, - } - specMount, err := config.GetVolumeMounts([]spec.Mount{}) - assert.NoError(t, err) - assert.True(t, reflect.DeepEqual(data, specMount[0])) -} - -func TestCreateConfig_GetAnnotations(t *testing.T) { - config := createConfig{} - annotations := config.GetAnnotations() - assert.True(t, reflect.DeepEqual("sandbox", annotations["io.kubernetes.cri-o.ContainerType"])) -} - -func TestCreateConfig_GetTmpfsMounts(t *testing.T) { - data := spec.Mount{ - Destination: "/homer", - Type: "tmpfs", - Source: "tmpfs", - Options: []string{"rw", "size=787448k", "mode=1777"}, - } - config := createConfig{ - Tmpfs: []string{"/homer:rw,size=787448k,mode=1777"}, - } - tmpfsMount := config.GetTmpfsMounts() - assert.True(t, reflect.DeepEqual(data, tmpfsMount[0])) - -} diff --git a/cmd/podman/varlink/io.projectatomic.podman.varlink b/cmd/podman/varlink/io.projectatomic.podman.varlink index 70879b46c..6583065e9 100644 --- a/cmd/podman/varlink/io.projectatomic.podman.varlink +++ b/cmd/podman/varlink/io.projectatomic.podman.varlink @@ -173,6 +173,124 @@ type PodmanInfo ( podman: InfoPodmanBinary ) +# Sockets describes sockets location for a container +type Sockets( + container_id: string, + io_socket: string, + control_socket: string +) + +# Create is an input structure for creating containers. It closely resembles the +# CreateConfig structure in libpod/pkg/spec. +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, + 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 +) + # Ping provides a response for developers to ensure their varlink setup is working. # #### Example # ~~~ @@ -202,8 +320,8 @@ method ListContainers() -> (containers: []ListContainerData) # See also [ListContainers](ListContainers) and [InspectContainer](InspectContainer). method GetContainer(name: string) -> (container: ListContainerData) -# This method is not implemented yet. -method CreateContainer() -> (notimplemented: NotImplemented) +# 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 # data in string format. You can then serialize the string into JSON. A [ContainerNotFound](#ContainerNotFound) @@ -274,8 +392,10 @@ method GetContainerStats(name: string) -> (container: ContainerStats) # This method has not be implemented yet. method ResizeContainerTty() -> (notimplemented: NotImplemented) -# This method has not be implemented yet. -method StartContainer() -> (notimplemented: NotImplemented) +# StartContainer starts a created or stopped container. It takes the name or ID of container. It returns +# the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) +# error will be returned. See also [CreateContainer](#CreateContainer). +method StartContainer(name: string) -> (container: string) # StopContainer stops a container given a timeout. It takes the name or ID of a container as well as a # timeout value. The timeout value the time before a forceable stop to the container is applied. It @@ -320,15 +440,32 @@ method UnpauseContainer(name: string) -> (container: string) # This method has not be implemented yet. method AttachToContainer() -> (notimplemented: NotImplemented) -# WaitContainer takes the name of ID of a container and waits until the container stops. Upon stopping, the return +# GetAttachSockets takes the name or ID of an existing container. It returns file paths for two sockets needed +# to properly communicate with a container. The first is the actual I/O socket that the container uses. The +# second is a "control" socket where things like resizing the TTY events are sent. If the container cannot be +# found, a [ContainerNotFound](#ContainerNotFound) error will be returned. +# #### Example +# ~~~ +# $ varlink call -m unix:/run/io.projectatomic.podman/io.projectatomic.podman.GetAttachSockets '{"name": "b7624e775431219161"}' +# { +# "sockets": { +# "container_id": "b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca", +# "control_socket": "/var/lib/containers/storage/overlay-containers/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/userdata/ctl", +# "io_socket": "/var/run/libpod/socket/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/attach" +# } +# } +# ~~~ +method GetAttachSockets(name: string) -> (sockets: Sockets) + +# WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return # code of the container is returned. If the container container cannot be found by ID or name, # a [ContainerNotFound](#ContainerNotFound) error is returned. method WaitContainer(name: string) -> (exitcode: int) # RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running # container can be stopped and removed. Upon sucessful removal of the container, its ID is returned. If the -# container cannot be found by name or ID, an [ContainerNotFound](#ContainerNotFound) error will be returned. -# #### Error +# container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned. +# #### Example # ~~~ # $ varlink call -m unix:/run/podman/io.projectatomic.podman/io.projectatomic.podman.RemoveContainer '{"name": "62f4fd98cb57"}' # { diff --git a/cmd/podman/varlink/ioprojectatomicpodman.go b/cmd/podman/varlink/ioprojectatomicpodman.go index 51812f19f..19226ebd4 100644 --- a/cmd/podman/varlink/ioprojectatomicpodman.go +++ b/cmd/podman/varlink/ioprojectatomicpodman.go @@ -4,11 +4,17 @@ package ioprojectatomicpodman import "github.com/varlink/go/varlink" // Type declarations -type ContainerMount struct { - Destination string `json:"destination"` - Type string `json:"type"` - Source string `json:"source"` - Options []string `json:"options"` +type InfoHost struct { + Mem_free int64 `json:"mem_free"` + Mem_total int64 `json:"mem_total"` + Swap_free int64 `json:"swap_free"` + Swap_total int64 `json:"swap_total"` + Arch string `json:"arch"` + Cpus int64 `json:"cpus"` + Hostname string `json:"hostname"` + Kernel string `json:"kernel"` + Os string `json:"os"` + Uptime string `json:"uptime"` } type InfoStore struct { @@ -21,14 +27,6 @@ type InfoStore struct { Run_root string `json:"run_root"` } -type PodmanInfo struct { - Host InfoHost `json:"host"` - Registries []string `json:"registries"` - Insecure_registries []string `json:"insecure_registries"` - Store InfoStore `json:"store"` - Podman InfoPodmanBinary `json:"podman"` -} - type Version struct { Version string `json:"version"` Go_version string `json:"go_version"` @@ -37,16 +35,6 @@ type Version struct { Os_arch string `json:"os_arch"` } -type StringResponse struct { - Message string `json:"message"` -} - -type ContainerChanges struct { - Changed []string `json:"changed"` - Added []string `json:"added"` - Deleted []string `json:"deleted"` -} - type ListContainerData struct { Id string `json:"id"` Image string `json:"image"` @@ -65,11 +53,27 @@ type ListContainerData struct { Namespaces ContainerNameSpace `json:"namespaces"` } -type InfoPodmanBinary struct { - Compiler string `json:"compiler"` - Go_version string `json:"go_version"` - Podman_version string `json:"podman_version"` - Git_commit string `json:"git_commit"` +type IDMappingOptions struct { + Host_uid_mapping bool `json:"host_uid_mapping"` + Host_gid_mapping bool `json:"host_gid_mapping"` + Uid_map IDMap `json:"uid_map"` + Gid_map IDMap `json:"gid_map"` +} + +type NotImplemented struct { + Comment string `json:"comment"` +} + +type ImageInList struct { + Id string `json:"id"` + ParentId string `json:"parentId"` + RepoTags []string `json:"repoTags"` + RepoDigests []string `json:"repoDigests"` + Created string `json:"created"` + Size int64 `json:"size"` + VirtualSize int64 `json:"virtualSize"` + Containers int64 `json:"containers"` + Labels map[string]string `json:"labels"` } type ImageSearch struct { @@ -80,20 +84,11 @@ type ImageSearch struct { Star_count int64 `json:"star_count"` } -type ContainerStats struct { - Id string `json:"id"` - Name string `json:"name"` - Cpu float64 `json:"cpu"` - Cpu_nano int64 `json:"cpu_nano"` - System_nano int64 `json:"system_nano"` - Mem_usage int64 `json:"mem_usage"` - Mem_limit int64 `json:"mem_limit"` - Mem_perc float64 `json:"mem_perc"` - Net_input int64 `json:"net_input"` - Net_output int64 `json:"net_output"` - Block_output int64 `json:"block_output"` - Block_input int64 `json:"block_input"` - Pids int64 `json:"pids"` +type ContainerMount struct { + Destination string `json:"destination"` + Type string `json:"type"` + Source string `json:"source"` + Options []string `json:"options"` } type ContainerPortMappings struct { @@ -103,26 +98,110 @@ type ContainerPortMappings struct { Container_port string `json:"container_port"` } +type ContainerNameSpace struct { + User string `json:"user"` + Uts string `json:"uts"` + Pidns string `json:"pidns"` + Pid string `json:"pid"` + Cgroup string `json:"cgroup"` + Net string `json:"net"` + Mnt string `json:"mnt"` + Ipc string `json:"ipc"` +} + type InfoGraphStatus struct { Backing_filesystem string `json:"backing_filesystem"` Native_overlay_diff string `json:"native_overlay_diff"` Supports_d_type string `json:"supports_d_type"` } -type NotImplemented struct { - Comment string `json:"comment"` +type PodmanInfo struct { + Host InfoHost `json:"host"` + Registries []string `json:"registries"` + Insecure_registries []string `json:"insecure_registries"` + Store InfoStore `json:"store"` + Podman InfoPodmanBinary `json:"podman"` } -type ImageInList struct { - Id string `json:"id"` - ParentId string `json:"parentId"` - RepoTags []string `json:"repoTags"` - RepoDigests []string `json:"repoDigests"` - Created string `json:"created"` - Size int64 `json:"size"` - VirtualSize int64 `json:"virtualSize"` - Containers int64 `json:"containers"` - Labels map[string]string `json:"labels"` +type StringResponse struct { + Message string `json:"message"` +} + +type Create struct { + Args []string `json:"args"` + Cap_add []string `json:"cap_add"` + Cap_drop []string `json:"cap_drop"` + Conmon_pidfile string `json:"conmon_pidfile"` + Cgroup_parent string `json:"cgroup_parent"` + Command []string `json:"command"` + Detach bool `json:"detach"` + Devices []string `json:"devices"` + Dns_opt []string `json:"dns_opt"` + Dns_search []string `json:"dns_search"` + Dns_servers []string `json:"dns_servers"` + Entrypoint []string `json:"entrypoint"` + Env map[string]string `json:"env"` + Exposed_ports []string `json:"exposed_ports"` + Gidmap []string `json:"gidmap"` + Group_add []string `json:"group_add"` + Host_add []string `json:"host_add"` + Hostname string `json:"hostname"` + Image string `json:"image"` + Image_id string `json:"image_id"` + Builtin_imgvolumes []string `json:"builtin_imgvolumes"` + Id_mappings IDMappingOptions `json:"id_mappings"` + Image_volume_type string `json:"image_volume_type"` + Interactive bool `json:"interactive"` + Ipc_mode string `json:"ipc_mode"` + Labels map[string]string `json:"labels"` + Log_driver string `json:"log_driver"` + Log_driver_opt []string `json:"log_driver_opt"` + Name string `json:"name"` + Net_mode string `json:"net_mode"` + Network string `json:"network"` + Pid_mode string `json:"pid_mode"` + Pod string `json:"pod"` + Privileged bool `json:"privileged"` + Publish []string `json:"publish"` + Publish_all bool `json:"publish_all"` + Quiet bool `json:"quiet"` + Readonly_rootfs bool `json:"readonly_rootfs"` + Resources CreateResourceConfig `json:"resources"` + Rm bool `json:"rm"` + Shm_dir string `json:"shm_dir"` + Stop_signal int64 `json:"stop_signal"` + Stop_timeout int64 `json:"stop_timeout"` + Subuidmap string `json:"subuidmap"` + Subgidmap string `json:"subgidmap"` + Subuidname string `json:"subuidname"` + Subgidname string `json:"subgidname"` + Sys_ctl map[string]string `json:"sys_ctl"` + Tmpfs []string `json:"tmpfs"` + Tty bool `json:"tty"` + Uidmap []string `json:"uidmap"` + Userns_mode string `json:"userns_mode"` + User string `json:"user"` + Uts_mode string `json:"uts_mode"` + Volumes []string `json:"volumes"` + Work_dir string `json:"work_dir"` + Mount_label string `json:"mount_label"` + Process_label string `json:"process_label"` + No_new_privs bool `json:"no_new_privs"` + Apparmor_profile string `json:"apparmor_profile"` + Seccomp_profile_path string `json:"seccomp_profile_path"` + Security_opts []string `json:"security_opts"` +} + +type IDMap struct { + Container_id int64 `json:"container_id"` + Host_id int64 `json:"host_id"` + Size int64 `json:"size"` +} + +type Sockets struct { + Container_id string `json:"container_id"` + Io_socket string `json:"io_socket"` + Control_socket string `json:"control_socket"` } type ImageHistory struct { @@ -134,186 +213,232 @@ type ImageHistory struct { Comment string `json:"comment"` } -type ContainerNameSpace struct { - User string `json:"user"` - Uts string `json:"uts"` - Pidns string `json:"pidns"` - Pid string `json:"pid"` - Cgroup string `json:"cgroup"` - Net string `json:"net"` - Mnt string `json:"mnt"` - Ipc string `json:"ipc"` +type ContainerStats struct { + Id string `json:"id"` + Name string `json:"name"` + Cpu float64 `json:"cpu"` + Cpu_nano int64 `json:"cpu_nano"` + System_nano int64 `json:"system_nano"` + Mem_usage int64 `json:"mem_usage"` + Mem_limit int64 `json:"mem_limit"` + Mem_perc float64 `json:"mem_perc"` + Net_input int64 `json:"net_input"` + Net_output int64 `json:"net_output"` + Block_output int64 `json:"block_output"` + Block_input int64 `json:"block_input"` + Pids int64 `json:"pids"` } -type InfoHost struct { - Mem_free int64 `json:"mem_free"` - Mem_total int64 `json:"mem_total"` - Swap_free int64 `json:"swap_free"` - Swap_total int64 `json:"swap_total"` - Arch string `json:"arch"` - Cpus int64 `json:"cpus"` - Hostname string `json:"hostname"` - Kernel string `json:"kernel"` - Os string `json:"os"` - Uptime string `json:"uptime"` +type InfoPodmanBinary struct { + Compiler string `json:"compiler"` + Go_version string `json:"go_version"` + Podman_version string `json:"podman_version"` + Git_commit string `json:"git_commit"` +} + +type CreateResourceConfig struct { + Blkio_weight int64 `json:"blkio_weight"` + Blkio_weight_device []string `json:"blkio_weight_device"` + Cpu_period int64 `json:"cpu_period"` + Cpu_quota int64 `json:"cpu_quota"` + Cpu_rt_period int64 `json:"cpu_rt_period"` + Cpu_rt_runtime int64 `json:"cpu_rt_runtime"` + Cpu_shares int64 `json:"cpu_shares"` + Cpus float64 `json:"cpus"` + Cpuset_cpus string `json:"cpuset_cpus"` + Cpuset_mems string `json:"cpuset_mems"` + Device_read_bps []string `json:"device_read_bps"` + Device_read_iops []string `json:"device_read_iops"` + Device_write_bps []string `json:"device_write_bps"` + Device_write_iops []string `json:"device_write_iops"` + Disable_oomkiller bool `json:"disable_oomkiller"` + Kernel_memory int64 `json:"kernel_memory"` + Memory int64 `json:"memory"` + Memory_reservation int64 `json:"memory_reservation"` + Memory_swap int64 `json:"memory_swap"` + Memory_swappiness int64 `json:"memory_swappiness"` + Oom_score_adj int64 `json:"oom_score_adj"` + Pids_limit int64 `json:"pids_limit"` + Shm_size int64 `json:"shm_size"` + Ulimit []string `json:"ulimit"` +} + +type ContainerChanges struct { + Changed []string `json:"changed"` + Added []string `json:"added"` + Deleted []string `json:"deleted"` } // Client method calls -type UpdateContainer_methods struct{} +type DeleteUnusedImages_methods struct{} -func UpdateContainer() UpdateContainer_methods { return UpdateContainer_methods{} } +func DeleteUnusedImages() DeleteUnusedImages_methods { return DeleteUnusedImages_methods{} } -func (m UpdateContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { +func (m DeleteUnusedImages_methods) Call(c *varlink.Connection) (images_out_ []string, err_ error) { receive, err_ := m.Send(c, 0) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + images_out_, _, err_ = receive() return } -func (m UpdateContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.UpdateContainer", nil, flags) +func (m DeleteUnusedImages_methods) Send(c *varlink.Connection, flags uint64) (func() ([]string, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.DeleteUnusedImages", nil, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (images_out_ []string, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Images []string `json:"images"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + images_out_ = []string(out.Images) return }, nil } -type InspectImage_methods struct{} +type InspectContainer_methods struct{} -func InspectImage() InspectImage_methods { return InspectImage_methods{} } +func InspectContainer() InspectContainer_methods { return InspectContainer_methods{} } -func (m InspectImage_methods) Call(c *varlink.Connection, name_in_ string) (image_out_ string, err_ error) { +func (m InspectContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - image_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m InspectImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { +func (m InspectContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { var in struct { Name string `json:"name"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.InspectImage", in, flags) + receive, err := c.Send("io.projectatomic.podman.InspectContainer", in, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Image string `json:"image"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + container_out_ = out.Container return }, nil } -type GetInfo_methods struct{} +type GetAttachSockets_methods struct{} -func GetInfo() GetInfo_methods { return GetInfo_methods{} } +func GetAttachSockets() GetAttachSockets_methods { return GetAttachSockets_methods{} } -func (m GetInfo_methods) Call(c *varlink.Connection) (info_out_ PodmanInfo, err_ error) { - receive, err_ := m.Send(c, 0) +func (m GetAttachSockets_methods) Call(c *varlink.Connection, name_in_ string) (sockets_out_ Sockets, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - info_out_, _, err_ = receive() + sockets_out_, _, err_ = receive() return } -func (m GetInfo_methods) Send(c *varlink.Connection, flags uint64) (func() (PodmanInfo, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.GetInfo", nil, flags) +func (m GetAttachSockets_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (Sockets, uint64, error), error) { + var in struct { + Name string `json:"name"` + } + in.Name = name_in_ + receive, err := c.Send("io.projectatomic.podman.GetAttachSockets", in, flags) if err != nil { return nil, err } - return func() (info_out_ PodmanInfo, flags uint64, err error) { + return func() (sockets_out_ Sockets, flags uint64, err error) { var out struct { - Info PodmanInfo `json:"info"` + Sockets Sockets `json:"sockets"` } flags, err = receive(&out) if err != nil { return } - info_out_ = out.Info + sockets_out_ = out.Sockets return }, nil } -type ResizeContainerTty_methods struct{} +type InspectImage_methods struct{} -func ResizeContainerTty() ResizeContainerTty_methods { return ResizeContainerTty_methods{} } +func InspectImage() InspectImage_methods { return InspectImage_methods{} } -func (m ResizeContainerTty_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { - receive, err_ := m.Send(c, 0) +func (m InspectImage_methods) Call(c *varlink.Connection, name_in_ string) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m ResizeContainerTty_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.ResizeContainerTty", nil, flags) +func (m InspectImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + } + in.Name = name_in_ + receive, err := c.Send("io.projectatomic.podman.InspectImage", in, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + image_out_ = out.Image return }, nil } -type StartContainer_methods struct{} +type TagImage_methods struct{} -func StartContainer() StartContainer_methods { return StartContainer_methods{} } +func TagImage() TagImage_methods { return TagImage_methods{} } -func (m StartContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { - receive, err_ := m.Send(c, 0) +func (m TagImage_methods) Call(c *varlink.Connection, name_in_ string, tagged_in_ string) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, tagged_in_) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m StartContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.StartContainer", nil, flags) +func (m TagImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, tagged_in_ string) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + Tagged string `json:"tagged"` + } + in.Name = name_in_ + in.Tagged = tagged_in_ + receive, err := c.Send("io.projectatomic.podman.TagImage", in, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + image_out_ = out.Image return }, nil } @@ -355,215 +480,213 @@ func (m StopContainer_methods) Send(c *varlink.Connection, flags uint64, name_in }, nil } -type AttachToContainer_methods struct{} +type RemoveContainer_methods struct{} -func AttachToContainer() AttachToContainer_methods { return AttachToContainer_methods{} } +func RemoveContainer() RemoveContainer_methods { return RemoveContainer_methods{} } -func (m AttachToContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { - receive, err_ := m.Send(c, 0) +func (m RemoveContainer_methods) Call(c *varlink.Connection, name_in_ string, force_in_ bool) (container_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, force_in_) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m AttachToContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.AttachToContainer", nil, flags) +func (m RemoveContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, force_in_ bool) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + Force bool `json:"force"` + } + in.Name = name_in_ + in.Force = force_in_ + receive, err := c.Send("io.projectatomic.podman.RemoveContainer", in, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + container_out_ = out.Container return }, nil } -type BuildImage_methods struct{} +type PullImage_methods struct{} -func BuildImage() BuildImage_methods { return BuildImage_methods{} } +func PullImage() PullImage_methods { return PullImage_methods{} } -func (m BuildImage_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { - receive, err_ := m.Send(c, 0) +func (m PullImage_methods) Call(c *varlink.Connection, name_in_ string) (id_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + id_out_, _, err_ = receive() return } -func (m BuildImage_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.BuildImage", nil, flags) +func (m PullImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + } + in.Name = name_in_ + receive, err := c.Send("io.projectatomic.podman.PullImage", in, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (id_out_ string, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Id string `json:"id"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + id_out_ = out.Id return }, nil } -type CreateImage_methods struct{} +type Ping_methods struct{} -func CreateImage() CreateImage_methods { return CreateImage_methods{} } +func Ping() Ping_methods { return Ping_methods{} } -func (m CreateImage_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { +func (m Ping_methods) Call(c *varlink.Connection) (ping_out_ StringResponse, err_ error) { receive, err_ := m.Send(c, 0) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + ping_out_, _, err_ = receive() return } -func (m CreateImage_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.CreateImage", nil, flags) +func (m Ping_methods) Send(c *varlink.Connection, flags uint64) (func() (StringResponse, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.Ping", nil, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (ping_out_ StringResponse, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Ping StringResponse `json:"ping"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + ping_out_ = out.Ping return }, nil } -type HistoryImage_methods struct{} +type ResizeContainerTty_methods struct{} -func HistoryImage() HistoryImage_methods { return HistoryImage_methods{} } +func ResizeContainerTty() ResizeContainerTty_methods { return ResizeContainerTty_methods{} } -func (m HistoryImage_methods) Call(c *varlink.Connection, name_in_ string) (history_out_ []ImageHistory, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m ResizeContainerTty_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { + receive, err_ := m.Send(c, 0) if err_ != nil { return } - history_out_, _, err_ = receive() + notimplemented_out_, _, err_ = receive() return } -func (m HistoryImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() ([]ImageHistory, uint64, error), error) { - var in struct { - Name string `json:"name"` - } - in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.HistoryImage", in, flags) +func (m ResizeContainerTty_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.ResizeContainerTty", nil, flags) if err != nil { return nil, err } - return func() (history_out_ []ImageHistory, flags uint64, err error) { + return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { var out struct { - History []ImageHistory `json:"history"` + Notimplemented NotImplemented `json:"notimplemented"` } flags, err = receive(&out) if err != nil { return } - history_out_ = []ImageHistory(out.History) + notimplemented_out_ = out.Notimplemented return }, nil } -type Commit_methods struct{} +type SearchImage_methods struct{} -func Commit() Commit_methods { return Commit_methods{} } +func SearchImage() SearchImage_methods { return SearchImage_methods{} } -func (m Commit_methods) Call(c *varlink.Connection, name_in_ string, image_name_in_ string, changes_in_ []string, author_in_ string, message_in_ string, pause_in_ bool) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, image_name_in_, changes_in_, author_in_, message_in_, pause_in_) +func (m SearchImage_methods) Call(c *varlink.Connection, name_in_ string, limit_in_ int64) (images_out_ []ImageSearch, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, limit_in_) if err_ != nil { return } - image_out_, _, err_ = receive() + images_out_, _, err_ = receive() return } -func (m Commit_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, image_name_in_ string, changes_in_ []string, author_in_ string, message_in_ string, pause_in_ bool) (func() (string, uint64, error), error) { +func (m SearchImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, limit_in_ int64) (func() ([]ImageSearch, uint64, error), error) { var in struct { - Name string `json:"name"` - Image_name string `json:"image_name"` - Changes []string `json:"changes"` - Author string `json:"author"` - Message string `json:"message"` - Pause bool `json:"pause"` + Name string `json:"name"` + Limit int64 `json:"limit"` } in.Name = name_in_ - in.Image_name = image_name_in_ - in.Changes = []string(changes_in_) - in.Author = author_in_ - in.Message = message_in_ - in.Pause = pause_in_ - receive, err := c.Send("io.projectatomic.podman.Commit", in, flags) + in.Limit = limit_in_ + receive, err := c.Send("io.projectatomic.podman.SearchImage", in, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (images_out_ []ImageSearch, flags uint64, err error) { var out struct { - Image string `json:"image"` + Images []ImageSearch `json:"images"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + images_out_ = []ImageSearch(out.Images) return }, nil } -type ListContainers_methods struct{} +type RenameContainer_methods struct{} -func ListContainers() ListContainers_methods { return ListContainers_methods{} } +func RenameContainer() RenameContainer_methods { return RenameContainer_methods{} } -func (m ListContainers_methods) Call(c *varlink.Connection) (containers_out_ []ListContainerData, err_ error) { +func (m RenameContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { receive, err_ := m.Send(c, 0) if err_ != nil { return } - containers_out_, _, err_ = receive() + notimplemented_out_, _, err_ = receive() return } -func (m ListContainers_methods) Send(c *varlink.Connection, flags uint64) (func() ([]ListContainerData, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.ListContainers", nil, flags) +func (m RenameContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.RenameContainer", nil, flags) if err != nil { return nil, err } - return func() (containers_out_ []ListContainerData, flags uint64, err error) { + return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { var out struct { - Containers []ListContainerData `json:"containers"` + Notimplemented NotImplemented `json:"notimplemented"` } flags, err = receive(&out) if err != nil { return } - containers_out_ = []ListContainerData(out.Containers) + notimplemented_out_ = out.Notimplemented return }, nil } -type GetContainer_methods struct{} +type PauseContainer_methods struct{} -func GetContainer() GetContainer_methods { return GetContainer_methods{} } +func PauseContainer() PauseContainer_methods { return PauseContainer_methods{} } -func (m GetContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ListContainerData, err_ error) { +func (m PauseContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return @@ -572,18 +695,18 @@ func (m GetContainer_methods) Call(c *varlink.Connection, name_in_ string) (cont return } -func (m GetContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ListContainerData, uint64, error), error) { +func (m PauseContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { var in struct { Name string `json:"name"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.GetContainer", in, flags) + receive, err := c.Send("io.projectatomic.podman.PauseContainer", in, flags) if err != nil { return nil, err } - return func() (container_out_ ListContainerData, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Container ListContainerData `json:"container"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { @@ -594,111 +717,113 @@ func (m GetContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ }, nil } -type ExportContainer_methods struct{} +type AttachToContainer_methods struct{} -func ExportContainer() ExportContainer_methods { return ExportContainer_methods{} } +func AttachToContainer() AttachToContainer_methods { return AttachToContainer_methods{} } -func (m ExportContainer_methods) Call(c *varlink.Connection, name_in_ string, path_in_ string) (tarfile_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, path_in_) +func (m AttachToContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { + receive, err_ := m.Send(c, 0) if err_ != nil { return } - tarfile_out_, _, err_ = receive() + notimplemented_out_, _, err_ = receive() return } -func (m ExportContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, path_in_ string) (func() (string, uint64, error), error) { - var in struct { - Name string `json:"name"` - Path string `json:"path"` - } - in.Name = name_in_ - in.Path = path_in_ - receive, err := c.Send("io.projectatomic.podman.ExportContainer", in, flags) +func (m AttachToContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.AttachToContainer", nil, flags) if err != nil { return nil, err } - return func() (tarfile_out_ string, flags uint64, err error) { + return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { var out struct { - Tarfile string `json:"tarfile"` + Notimplemented NotImplemented `json:"notimplemented"` } flags, err = receive(&out) if err != nil { return } - tarfile_out_ = out.Tarfile + notimplemented_out_ = out.Notimplemented return }, nil } -type ListImages_methods struct{} +type PushImage_methods struct{} -func ListImages() ListImages_methods { return ListImages_methods{} } +func PushImage() PushImage_methods { return PushImage_methods{} } -func (m ListImages_methods) Call(c *varlink.Connection) (images_out_ []ImageInList, err_ error) { - receive, err_ := m.Send(c, 0) +func (m PushImage_methods) Call(c *varlink.Connection, name_in_ string, tag_in_ string, tlsverify_in_ bool) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, tag_in_, tlsverify_in_) if err_ != nil { return } - images_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m ListImages_methods) Send(c *varlink.Connection, flags uint64) (func() ([]ImageInList, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.ListImages", nil, flags) +func (m PushImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, tag_in_ string, tlsverify_in_ bool) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + Tag string `json:"tag"` + Tlsverify bool `json:"tlsverify"` + } + in.Name = name_in_ + in.Tag = tag_in_ + in.Tlsverify = tlsverify_in_ + receive, err := c.Send("io.projectatomic.podman.PushImage", in, flags) if err != nil { return nil, err } - return func() (images_out_ []ImageInList, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Images []ImageInList `json:"images"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - images_out_ = []ImageInList(out.Images) + image_out_ = out.Image return }, nil } -type DeleteUnusedImages_methods struct{} +type ListContainers_methods struct{} -func DeleteUnusedImages() DeleteUnusedImages_methods { return DeleteUnusedImages_methods{} } +func ListContainers() ListContainers_methods { return ListContainers_methods{} } -func (m DeleteUnusedImages_methods) Call(c *varlink.Connection) (images_out_ []string, err_ error) { +func (m ListContainers_methods) Call(c *varlink.Connection) (containers_out_ []ListContainerData, err_ error) { receive, err_ := m.Send(c, 0) if err_ != nil { return } - images_out_, _, err_ = receive() + containers_out_, _, err_ = receive() return } -func (m DeleteUnusedImages_methods) Send(c *varlink.Connection, flags uint64) (func() ([]string, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.DeleteUnusedImages", nil, flags) +func (m ListContainers_methods) Send(c *varlink.Connection, flags uint64) (func() ([]ListContainerData, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.ListContainers", nil, flags) if err != nil { return nil, err } - return func() (images_out_ []string, flags uint64, err error) { + return func() (containers_out_ []ListContainerData, flags uint64, err error) { var out struct { - Images []string `json:"images"` + Containers []ListContainerData `json:"containers"` } flags, err = receive(&out) if err != nil { return } - images_out_ = []string(out.Images) + containers_out_ = []ListContainerData(out.Containers) return }, nil } -type GetContainerStats_methods struct{} +type CreateContainer_methods struct{} -func GetContainerStats() GetContainerStats_methods { return GetContainerStats_methods{} } +func CreateContainer() CreateContainer_methods { return CreateContainer_methods{} } -func (m GetContainerStats_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ContainerStats, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m CreateContainer_methods) Call(c *varlink.Connection, create_in_ Create) (container_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, create_in_) if err_ != nil { return } @@ -706,18 +831,18 @@ func (m GetContainerStats_methods) Call(c *varlink.Connection, name_in_ string) return } -func (m GetContainerStats_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ContainerStats, uint64, error), error) { +func (m CreateContainer_methods) Send(c *varlink.Connection, flags uint64, create_in_ Create) (func() (string, uint64, error), error) { var in struct { - Name string `json:"name"` + Create Create `json:"create"` } - in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.GetContainerStats", in, flags) + in.Create = create_in_ + receive, err := c.Send("io.projectatomic.podman.CreateContainer", in, flags) if err != nil { return nil, err } - return func() (container_out_ ContainerStats, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Container ContainerStats `json:"container"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { @@ -728,103 +853,74 @@ func (m GetContainerStats_methods) Send(c *varlink.Connection, flags uint64, nam }, nil } -type UnpauseContainer_methods struct{} +type ExportContainer_methods struct{} -func UnpauseContainer() UnpauseContainer_methods { return UnpauseContainer_methods{} } +func ExportContainer() ExportContainer_methods { return ExportContainer_methods{} } -func (m UnpauseContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m ExportContainer_methods) Call(c *varlink.Connection, name_in_ string, path_in_ string) (tarfile_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, path_in_) if err_ != nil { return } - container_out_, _, err_ = receive() + tarfile_out_, _, err_ = receive() return } -func (m UnpauseContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { +func (m ExportContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, path_in_ string) (func() (string, uint64, error), error) { var in struct { Name string `json:"name"` + Path string `json:"path"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.UnpauseContainer", in, flags) + in.Path = path_in_ + receive, err := c.Send("io.projectatomic.podman.ExportContainer", in, flags) if err != nil { return nil, err } - return func() (container_out_ string, flags uint64, err error) { + return func() (tarfile_out_ string, flags uint64, err error) { var out struct { - Container string `json:"container"` + Tarfile string `json:"tarfile"` } flags, err = receive(&out) if err != nil { return } - container_out_ = out.Container + tarfile_out_ = out.Tarfile return }, nil } -type PullImage_methods struct{} +type StartContainer_methods struct{} -func PullImage() PullImage_methods { return PullImage_methods{} } +func StartContainer() StartContainer_methods { return StartContainer_methods{} } -func (m PullImage_methods) Call(c *varlink.Connection, name_in_ string) (id_out_ string, err_ error) { +func (m StartContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - id_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m PullImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { +func (m StartContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { var in struct { Name string `json:"name"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.PullImage", in, flags) - if err != nil { - return nil, err - } - return func() (id_out_ string, flags uint64, err error) { - var out struct { - Id string `json:"id"` - } - flags, err = receive(&out) - if err != nil { - return - } - id_out_ = out.Id - return - }, nil -} - -type Ping_methods struct{} - -func Ping() Ping_methods { return Ping_methods{} } - -func (m Ping_methods) Call(c *varlink.Connection) (ping_out_ StringResponse, err_ error) { - receive, err_ := m.Send(c, 0) - if err_ != nil { - return - } - ping_out_, _, err_ = receive() - return -} - -func (m Ping_methods) Send(c *varlink.Connection, flags uint64) (func() (StringResponse, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.Ping", nil, flags) + receive, err := c.Send("io.projectatomic.podman.StartContainer", in, flags) if err != nil { return nil, err } - return func() (ping_out_ StringResponse, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Ping StringResponse `json:"ping"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { return } - ping_out_ = out.Ping + container_out_ = out.Container return }, nil } @@ -860,43 +956,47 @@ func (m GetVersion_methods) Send(c *varlink.Connection, flags uint64) (func() (V }, nil } -type CreateContainer_methods struct{} +type GetContainer_methods struct{} -func CreateContainer() CreateContainer_methods { return CreateContainer_methods{} } +func GetContainer() GetContainer_methods { return GetContainer_methods{} } -func (m CreateContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { - receive, err_ := m.Send(c, 0) +func (m GetContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ListContainerData, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - notimplemented_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m CreateContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.CreateContainer", nil, flags) +func (m GetContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ListContainerData, uint64, error), error) { + var in struct { + Name string `json:"name"` + } + in.Name = name_in_ + receive, err := c.Send("io.projectatomic.podman.GetContainer", in, flags) if err != nil { return nil, err } - return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + return func() (container_out_ ListContainerData, flags uint64, err error) { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Container ListContainerData `json:"container"` } flags, err = receive(&out) if err != nil { return } - notimplemented_out_ = out.Notimplemented + container_out_ = out.Container return }, nil } -type KillContainer_methods struct{} +type GetContainerLogs_methods struct{} -func KillContainer() KillContainer_methods { return KillContainer_methods{} } +func GetContainerLogs() GetContainerLogs_methods { return GetContainerLogs_methods{} } -func (m KillContainer_methods) Call(c *varlink.Connection, name_in_ string, signal_in_ int64) (container_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, signal_in_) +func (m GetContainerLogs_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ []string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } @@ -904,36 +1004,34 @@ func (m KillContainer_methods) Call(c *varlink.Connection, name_in_ string, sign return } -func (m KillContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, signal_in_ int64) (func() (string, uint64, error), error) { +func (m GetContainerLogs_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() ([]string, uint64, error), error) { var in struct { - Name string `json:"name"` - Signal int64 `json:"signal"` + Name string `json:"name"` } in.Name = name_in_ - in.Signal = signal_in_ - receive, err := c.Send("io.projectatomic.podman.KillContainer", in, flags) + receive, err := c.Send("io.projectatomic.podman.GetContainerLogs", in, flags) if err != nil { return nil, err } - return func() (container_out_ string, flags uint64, err error) { + return func() (container_out_ []string, flags uint64, err error) { var out struct { - Container string `json:"container"` + Container []string `json:"container"` } flags, err = receive(&out) if err != nil { return } - container_out_ = out.Container + container_out_ = []string(out.Container) return }, nil } -type RemoveContainer_methods struct{} +type ListContainerProcesses_methods struct{} -func RemoveContainer() RemoveContainer_methods { return RemoveContainer_methods{} } +func ListContainerProcesses() ListContainerProcesses_methods { return ListContainerProcesses_methods{} } -func (m RemoveContainer_methods) Call(c *varlink.Connection, name_in_ string, force_in_ bool) (container_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, force_in_) +func (m ListContainerProcesses_methods) Call(c *varlink.Connection, name_in_ string, opts_in_ []string) (container_out_ []string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, opts_in_) if err_ != nil { return } @@ -941,258 +1039,300 @@ func (m RemoveContainer_methods) Call(c *varlink.Connection, name_in_ string, fo return } -func (m RemoveContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, force_in_ bool) (func() (string, uint64, error), error) { +func (m ListContainerProcesses_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, opts_in_ []string) (func() ([]string, uint64, error), error) { var in struct { - Name string `json:"name"` - Force bool `json:"force"` + Name string `json:"name"` + Opts []string `json:"opts"` } in.Name = name_in_ - in.Force = force_in_ - receive, err := c.Send("io.projectatomic.podman.RemoveContainer", in, flags) + in.Opts = []string(opts_in_) + receive, err := c.Send("io.projectatomic.podman.ListContainerProcesses", in, flags) if err != nil { return nil, err } - return func() (container_out_ string, flags uint64, err error) { + return func() (container_out_ []string, flags uint64, err error) { var out struct { - Container string `json:"container"` + Container []string `json:"container"` } flags, err = receive(&out) if err != nil { return } - container_out_ = out.Container + container_out_ = []string(out.Container) return }, nil } -type RemoveImage_methods struct{} +type ListContainerChanges_methods struct{} -func RemoveImage() RemoveImage_methods { return RemoveImage_methods{} } +func ListContainerChanges() ListContainerChanges_methods { return ListContainerChanges_methods{} } -func (m RemoveImage_methods) Call(c *varlink.Connection, name_in_ string, force_in_ bool) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, force_in_) +func (m ListContainerChanges_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ContainerChanges, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - image_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m RemoveImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, force_in_ bool) (func() (string, uint64, error), error) { +func (m ListContainerChanges_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ContainerChanges, uint64, error), error) { var in struct { - Name string `json:"name"` - Force bool `json:"force"` + Name string `json:"name"` } in.Name = name_in_ - in.Force = force_in_ - receive, err := c.Send("io.projectatomic.podman.RemoveImage", in, flags) + receive, err := c.Send("io.projectatomic.podman.ListContainerChanges", in, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (container_out_ ContainerChanges, flags uint64, err error) { var out struct { - Image string `json:"image"` + Container ContainerChanges `json:"container"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + container_out_ = out.Container return }, nil } -type ImportImage_methods struct{} +type RestartContainer_methods struct{} -func ImportImage() ImportImage_methods { return ImportImage_methods{} } +func RestartContainer() RestartContainer_methods { return RestartContainer_methods{} } -func (m ImportImage_methods) Call(c *varlink.Connection, source_in_ string, reference_in_ string, message_in_ string, changes_in_ []string) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, source_in_, reference_in_, message_in_, changes_in_) +func (m RestartContainer_methods) Call(c *varlink.Connection, name_in_ string, timeout_in_ int64) (container_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, timeout_in_) if err_ != nil { return } - image_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m ImportImage_methods) Send(c *varlink.Connection, flags uint64, source_in_ string, reference_in_ string, message_in_ string, changes_in_ []string) (func() (string, uint64, error), error) { +func (m RestartContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, timeout_in_ int64) (func() (string, uint64, error), error) { var in struct { - Source string `json:"source"` - Reference string `json:"reference"` - Message string `json:"message"` - Changes []string `json:"changes"` + Name string `json:"name"` + Timeout int64 `json:"timeout"` } - in.Source = source_in_ - in.Reference = reference_in_ - in.Message = message_in_ - in.Changes = []string(changes_in_) - receive, err := c.Send("io.projectatomic.podman.ImportImage", in, flags) + in.Name = name_in_ + in.Timeout = timeout_in_ + receive, err := c.Send("io.projectatomic.podman.RestartContainer", in, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Image string `json:"image"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + container_out_ = out.Container return }, nil } -type ExportImage_methods struct{} +type DeleteStoppedContainers_methods struct{} -func ExportImage() ExportImage_methods { return ExportImage_methods{} } +func DeleteStoppedContainers() DeleteStoppedContainers_methods { + return DeleteStoppedContainers_methods{} +} -func (m ExportImage_methods) Call(c *varlink.Connection, name_in_ string, destination_in_ string, compress_in_ bool) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, destination_in_, compress_in_) +func (m DeleteStoppedContainers_methods) Call(c *varlink.Connection) (containers_out_ []string, err_ error) { + receive, err_ := m.Send(c, 0) if err_ != nil { return } - image_out_, _, err_ = receive() + containers_out_, _, err_ = receive() return } -func (m ExportImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, destination_in_ string, compress_in_ bool) (func() (string, uint64, error), error) { - var in struct { - Name string `json:"name"` - Destination string `json:"destination"` - Compress bool `json:"compress"` - } - in.Name = name_in_ - in.Destination = destination_in_ - in.Compress = compress_in_ - receive, err := c.Send("io.projectatomic.podman.ExportImage", in, flags) +func (m DeleteStoppedContainers_methods) Send(c *varlink.Connection, flags uint64) (func() ([]string, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.DeleteStoppedContainers", nil, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (containers_out_ []string, flags uint64, err error) { var out struct { - Image string `json:"image"` + Containers []string `json:"containers"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + containers_out_ = []string(out.Containers) return }, nil } -type InspectContainer_methods struct{} +type WaitContainer_methods struct{} -func InspectContainer() InspectContainer_methods { return InspectContainer_methods{} } +func WaitContainer() WaitContainer_methods { return WaitContainer_methods{} } -func (m InspectContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { +func (m WaitContainer_methods) Call(c *varlink.Connection, name_in_ string) (exitcode_out_ int64, err_ error) { receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - container_out_, _, err_ = receive() + exitcode_out_, _, err_ = receive() return } -func (m InspectContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { +func (m WaitContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (int64, uint64, error), error) { var in struct { Name string `json:"name"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.InspectContainer", in, flags) + receive, err := c.Send("io.projectatomic.podman.WaitContainer", in, flags) if err != nil { return nil, err } - return func() (container_out_ string, flags uint64, err error) { + return func() (exitcode_out_ int64, flags uint64, err error) { var out struct { - Container string `json:"container"` + Exitcode int64 `json:"exitcode"` } flags, err = receive(&out) if err != nil { return } - container_out_ = out.Container + exitcode_out_ = out.Exitcode return }, nil } -type GetContainerLogs_methods struct{} +type ListImages_methods struct{} -func GetContainerLogs() GetContainerLogs_methods { return GetContainerLogs_methods{} } +func ListImages() ListImages_methods { return ListImages_methods{} } -func (m GetContainerLogs_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ []string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m ListImages_methods) Call(c *varlink.Connection) (images_out_ []ImageInList, err_ error) { + receive, err_ := m.Send(c, 0) if err_ != nil { return } - container_out_, _, err_ = receive() + images_out_, _, err_ = receive() return } -func (m GetContainerLogs_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() ([]string, uint64, error), error) { - var in struct { - Name string `json:"name"` - } - in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.GetContainerLogs", in, flags) +func (m ListImages_methods) Send(c *varlink.Connection, flags uint64) (func() ([]ImageInList, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.ListImages", nil, flags) if err != nil { return nil, err } - return func() (container_out_ []string, flags uint64, err error) { + return func() (images_out_ []ImageInList, flags uint64, err error) { var out struct { - Container []string `json:"container"` + Images []ImageInList `json:"images"` } flags, err = receive(&out) if err != nil { return } - container_out_ = []string(out.Container) + images_out_ = []ImageInList(out.Images) return }, nil } -type ListContainerChanges_methods struct{} +type BuildImage_methods struct{} -func ListContainerChanges() ListContainerChanges_methods { return ListContainerChanges_methods{} } +func BuildImage() BuildImage_methods { return BuildImage_methods{} } -func (m ListContainerChanges_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ContainerChanges, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m BuildImage_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { + receive, err_ := m.Send(c, 0) if err_ != nil { return } - container_out_, _, err_ = receive() + notimplemented_out_, _, err_ = receive() return } -func (m ListContainerChanges_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ContainerChanges, uint64, error), error) { - var in struct { - Name string `json:"name"` +func (m BuildImage_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.BuildImage", nil, flags) + if err != nil { + return nil, err } - in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.ListContainerChanges", in, flags) + return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { + var out struct { + Notimplemented NotImplemented `json:"notimplemented"` + } + flags, err = receive(&out) + if err != nil { + return + } + notimplemented_out_ = out.Notimplemented + return + }, nil +} + +type CreateImage_methods struct{} + +func CreateImage() CreateImage_methods { return CreateImage_methods{} } + +func (m CreateImage_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { + receive, err_ := m.Send(c, 0) + if err_ != nil { + return + } + notimplemented_out_, _, err_ = receive() + return +} + +func (m CreateImage_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.CreateImage", nil, flags) if err != nil { return nil, err } - return func() (container_out_ ContainerChanges, flags uint64, err error) { + return func() (notimplemented_out_ NotImplemented, flags uint64, err error) { var out struct { - Container ContainerChanges `json:"container"` + Notimplemented NotImplemented `json:"notimplemented"` } flags, err = receive(&out) if err != nil { return } - container_out_ = out.Container + notimplemented_out_ = out.Notimplemented return }, nil } -type RestartContainer_methods struct{} +type GetInfo_methods struct{} -func RestartContainer() RestartContainer_methods { return RestartContainer_methods{} } +func GetInfo() GetInfo_methods { return GetInfo_methods{} } -func (m RestartContainer_methods) Call(c *varlink.Connection, name_in_ string, timeout_in_ int64) (container_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, timeout_in_) +func (m GetInfo_methods) Call(c *varlink.Connection) (info_out_ PodmanInfo, err_ error) { + receive, err_ := m.Send(c, 0) + if err_ != nil { + return + } + info_out_, _, err_ = receive() + return +} + +func (m GetInfo_methods) Send(c *varlink.Connection, flags uint64) (func() (PodmanInfo, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.GetInfo", nil, flags) + if err != nil { + return nil, err + } + return func() (info_out_ PodmanInfo, flags uint64, err error) { + var out struct { + Info PodmanInfo `json:"info"` + } + flags, err = receive(&out) + if err != nil { + return + } + info_out_ = out.Info + return + }, nil +} + +type GetContainerStats_methods struct{} + +func GetContainerStats() GetContainerStats_methods { return GetContainerStats_methods{} } + +func (m GetContainerStats_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ ContainerStats, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } @@ -1200,20 +1340,18 @@ func (m RestartContainer_methods) Call(c *varlink.Connection, name_in_ string, t return } -func (m RestartContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, timeout_in_ int64) (func() (string, uint64, error), error) { +func (m GetContainerStats_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (ContainerStats, uint64, error), error) { var in struct { - Name string `json:"name"` - Timeout int64 `json:"timeout"` + Name string `json:"name"` } in.Name = name_in_ - in.Timeout = timeout_in_ - receive, err := c.Send("io.projectatomic.podman.RestartContainer", in, flags) + receive, err := c.Send("io.projectatomic.podman.GetContainerStats", in, flags) if err != nil { return nil, err } - return func() (container_out_ string, flags uint64, err error) { + return func() (container_out_ ContainerStats, flags uint64, err error) { var out struct { - Container string `json:"container"` + Container ContainerStats `json:"container"` } flags, err = receive(&out) if err != nil { @@ -1224,11 +1362,11 @@ func (m RestartContainer_methods) Send(c *varlink.Connection, flags uint64, name }, nil } -type RenameContainer_methods struct{} +type UpdateContainer_methods struct{} -func RenameContainer() RenameContainer_methods { return RenameContainer_methods{} } +func UpdateContainer() UpdateContainer_methods { return UpdateContainer_methods{} } -func (m RenameContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { +func (m UpdateContainer_methods) Call(c *varlink.Connection) (notimplemented_out_ NotImplemented, err_ error) { receive, err_ := m.Send(c, 0) if err_ != nil { return @@ -1237,8 +1375,8 @@ func (m RenameContainer_methods) Call(c *varlink.Connection) (notimplemented_out return } -func (m RenameContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.RenameContainer", nil, flags) +func (m UpdateContainer_methods) Send(c *varlink.Connection, flags uint64) (func() (NotImplemented, uint64, error), error) { + receive, err := c.Send("io.projectatomic.podman.UpdateContainer", nil, flags) if err != nil { return nil, err } @@ -1255,11 +1393,11 @@ func (m RenameContainer_methods) Send(c *varlink.Connection, flags uint64) (func }, nil } -type PauseContainer_methods struct{} +type UnpauseContainer_methods struct{} -func PauseContainer() PauseContainer_methods { return PauseContainer_methods{} } +func UnpauseContainer() UnpauseContainer_methods { return UnpauseContainer_methods{} } -func (m PauseContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { +func (m UnpauseContainer_methods) Call(c *varlink.Connection, name_in_ string) (container_out_ string, err_ error) { receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return @@ -1268,12 +1406,12 @@ func (m PauseContainer_methods) Call(c *varlink.Connection, name_in_ string) (co return } -func (m PauseContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { +func (m UnpauseContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (string, uint64, error), error) { var in struct { Name string `json:"name"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.PauseContainer", in, flags) + receive, err := c.Send("io.projectatomic.podman.UnpauseContainer", in, flags) if err != nil { return nil, err } @@ -1290,156 +1428,166 @@ func (m PauseContainer_methods) Send(c *varlink.Connection, flags uint64, name_i }, nil } -type PushImage_methods struct{} +type HistoryImage_methods struct{} -func PushImage() PushImage_methods { return PushImage_methods{} } +func HistoryImage() HistoryImage_methods { return HistoryImage_methods{} } -func (m PushImage_methods) Call(c *varlink.Connection, name_in_ string, tag_in_ string, tlsverify_in_ bool) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, tag_in_, tlsverify_in_) +func (m HistoryImage_methods) Call(c *varlink.Connection, name_in_ string) (history_out_ []ImageHistory, err_ error) { + receive, err_ := m.Send(c, 0, name_in_) if err_ != nil { return } - image_out_, _, err_ = receive() + history_out_, _, err_ = receive() return } -func (m PushImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, tag_in_ string, tlsverify_in_ bool) (func() (string, uint64, error), error) { +func (m HistoryImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() ([]ImageHistory, uint64, error), error) { var in struct { - Name string `json:"name"` - Tag string `json:"tag"` - Tlsverify bool `json:"tlsverify"` + Name string `json:"name"` } in.Name = name_in_ - in.Tag = tag_in_ - in.Tlsverify = tlsverify_in_ - receive, err := c.Send("io.projectatomic.podman.PushImage", in, flags) + receive, err := c.Send("io.projectatomic.podman.HistoryImage", in, flags) if err != nil { return nil, err } - return func() (image_out_ string, flags uint64, err error) { + return func() (history_out_ []ImageHistory, flags uint64, err error) { var out struct { - Image string `json:"image"` + History []ImageHistory `json:"history"` } flags, err = receive(&out) if err != nil { return } - image_out_ = out.Image + history_out_ = []ImageHistory(out.History) return }, nil } -type ListContainerProcesses_methods struct{} +type RemoveImage_methods struct{} -func ListContainerProcesses() ListContainerProcesses_methods { return ListContainerProcesses_methods{} } +func RemoveImage() RemoveImage_methods { return RemoveImage_methods{} } -func (m ListContainerProcesses_methods) Call(c *varlink.Connection, name_in_ string, opts_in_ []string) (container_out_ []string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, opts_in_) +func (m RemoveImage_methods) Call(c *varlink.Connection, name_in_ string, force_in_ bool) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, force_in_) if err_ != nil { return } - container_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m ListContainerProcesses_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, opts_in_ []string) (func() ([]string, uint64, error), error) { +func (m RemoveImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, force_in_ bool) (func() (string, uint64, error), error) { var in struct { - Name string `json:"name"` - Opts []string `json:"opts"` + Name string `json:"name"` + Force bool `json:"force"` } in.Name = name_in_ - in.Opts = []string(opts_in_) - receive, err := c.Send("io.projectatomic.podman.ListContainerProcesses", in, flags) + in.Force = force_in_ + receive, err := c.Send("io.projectatomic.podman.RemoveImage", in, flags) if err != nil { return nil, err } - return func() (container_out_ []string, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Container []string `json:"container"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - container_out_ = []string(out.Container) + image_out_ = out.Image return }, nil } -type WaitContainer_methods struct{} +type Commit_methods struct{} -func WaitContainer() WaitContainer_methods { return WaitContainer_methods{} } +func Commit() Commit_methods { return Commit_methods{} } -func (m WaitContainer_methods) Call(c *varlink.Connection, name_in_ string) (exitcode_out_ int64, err_ error) { - receive, err_ := m.Send(c, 0, name_in_) +func (m Commit_methods) Call(c *varlink.Connection, name_in_ string, image_name_in_ string, changes_in_ []string, author_in_ string, message_in_ string, pause_in_ bool) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, image_name_in_, changes_in_, author_in_, message_in_, pause_in_) if err_ != nil { return } - exitcode_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m WaitContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string) (func() (int64, uint64, error), error) { +func (m Commit_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, image_name_in_ string, changes_in_ []string, author_in_ string, message_in_ string, pause_in_ bool) (func() (string, uint64, error), error) { var in struct { - Name string `json:"name"` + Name string `json:"name"` + Image_name string `json:"image_name"` + Changes []string `json:"changes"` + Author string `json:"author"` + Message string `json:"message"` + Pause bool `json:"pause"` } in.Name = name_in_ - receive, err := c.Send("io.projectatomic.podman.WaitContainer", in, flags) + in.Image_name = image_name_in_ + in.Changes = []string(changes_in_) + in.Author = author_in_ + in.Message = message_in_ + in.Pause = pause_in_ + receive, err := c.Send("io.projectatomic.podman.Commit", in, flags) if err != nil { return nil, err } - return func() (exitcode_out_ int64, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Exitcode int64 `json:"exitcode"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - exitcode_out_ = out.Exitcode + image_out_ = out.Image return }, nil } -type DeleteStoppedContainers_methods struct{} +type KillContainer_methods struct{} -func DeleteStoppedContainers() DeleteStoppedContainers_methods { - return DeleteStoppedContainers_methods{} -} +func KillContainer() KillContainer_methods { return KillContainer_methods{} } -func (m DeleteStoppedContainers_methods) Call(c *varlink.Connection) (containers_out_ []string, err_ error) { - receive, err_ := m.Send(c, 0) +func (m KillContainer_methods) Call(c *varlink.Connection, name_in_ string, signal_in_ int64) (container_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, signal_in_) if err_ != nil { return } - containers_out_, _, err_ = receive() + container_out_, _, err_ = receive() return } -func (m DeleteStoppedContainers_methods) Send(c *varlink.Connection, flags uint64) (func() ([]string, uint64, error), error) { - receive, err := c.Send("io.projectatomic.podman.DeleteStoppedContainers", nil, flags) +func (m KillContainer_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, signal_in_ int64) (func() (string, uint64, error), error) { + var in struct { + Name string `json:"name"` + Signal int64 `json:"signal"` + } + in.Name = name_in_ + in.Signal = signal_in_ + receive, err := c.Send("io.projectatomic.podman.KillContainer", in, flags) if err != nil { return nil, err } - return func() (containers_out_ []string, flags uint64, err error) { + return func() (container_out_ string, flags uint64, err error) { var out struct { - Containers []string `json:"containers"` + Container string `json:"container"` } flags, err = receive(&out) if err != nil { return } - containers_out_ = []string(out.Containers) + container_out_ = out.Container return }, nil } -type TagImage_methods struct{} +type ImportImage_methods struct{} -func TagImage() TagImage_methods { return TagImage_methods{} } +func ImportImage() ImportImage_methods { return ImportImage_methods{} } -func (m TagImage_methods) Call(c *varlink.Connection, name_in_ string, tagged_in_ string) (image_out_ string, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, tagged_in_) +func (m ImportImage_methods) Call(c *varlink.Connection, source_in_ string, reference_in_ string, message_in_ string, changes_in_ []string) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, source_in_, reference_in_, message_in_, changes_in_) if err_ != nil { return } @@ -1447,14 +1595,18 @@ func (m TagImage_methods) Call(c *varlink.Connection, name_in_ string, tagged_in return } -func (m TagImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, tagged_in_ string) (func() (string, uint64, error), error) { +func (m ImportImage_methods) Send(c *varlink.Connection, flags uint64, source_in_ string, reference_in_ string, message_in_ string, changes_in_ []string) (func() (string, uint64, error), error) { var in struct { - Name string `json:"name"` - Tagged string `json:"tagged"` + Source string `json:"source"` + Reference string `json:"reference"` + Message string `json:"message"` + Changes []string `json:"changes"` } - in.Name = name_in_ - in.Tagged = tagged_in_ - receive, err := c.Send("io.projectatomic.podman.TagImage", in, flags) + in.Source = source_in_ + in.Reference = reference_in_ + in.Message = message_in_ + in.Changes = []string(changes_in_) + receive, err := c.Send("io.projectatomic.podman.ImportImage", in, flags) if err != nil { return nil, err } @@ -1471,98 +1623,93 @@ func (m TagImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ str }, nil } -type SearchImage_methods struct{} +type ExportImage_methods struct{} -func SearchImage() SearchImage_methods { return SearchImage_methods{} } +func ExportImage() ExportImage_methods { return ExportImage_methods{} } -func (m SearchImage_methods) Call(c *varlink.Connection, name_in_ string, limit_in_ int64) (images_out_ []ImageSearch, err_ error) { - receive, err_ := m.Send(c, 0, name_in_, limit_in_) +func (m ExportImage_methods) Call(c *varlink.Connection, name_in_ string, destination_in_ string, compress_in_ bool) (image_out_ string, err_ error) { + receive, err_ := m.Send(c, 0, name_in_, destination_in_, compress_in_) if err_ != nil { return } - images_out_, _, err_ = receive() + image_out_, _, err_ = receive() return } -func (m SearchImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, limit_in_ int64) (func() ([]ImageSearch, uint64, error), error) { +func (m ExportImage_methods) Send(c *varlink.Connection, flags uint64, name_in_ string, destination_in_ string, compress_in_ bool) (func() (string, uint64, error), error) { var in struct { - Name string `json:"name"` - Limit int64 `json:"limit"` + Name string `json:"name"` + Destination string `json:"destination"` + Compress bool `json:"compress"` } in.Name = name_in_ - in.Limit = limit_in_ - receive, err := c.Send("io.projectatomic.podman.SearchImage", in, flags) + in.Destination = destination_in_ + in.Compress = compress_in_ + receive, err := c.Send("io.projectatomic.podman.ExportImage", in, flags) if err != nil { return nil, err } - return func() (images_out_ []ImageSearch, flags uint64, err error) { + return func() (image_out_ string, flags uint64, err error) { var out struct { - Images []ImageSearch `json:"images"` + Image string `json:"image"` } flags, err = receive(&out) if err != nil { return } - images_out_ = []ImageSearch(out.Images) + image_out_ = out.Image return }, nil } // Service interface with all methods type ioprojectatomicpodmanInterface interface { - GetContainerStats(c VarlinkCall, name_ string) error - UnpauseContainer(c VarlinkCall, name_ string) error + DeleteUnusedImages(c VarlinkCall) error + InspectContainer(c VarlinkCall, name_ string) error + GetAttachSockets(c VarlinkCall, name_ string) error + InspectImage(c VarlinkCall, name_ string) error + TagImage(c VarlinkCall, name_ string, tagged_ string) error + StopContainer(c VarlinkCall, name_ string, timeout_ int64) error + RemoveContainer(c VarlinkCall, name_ string, force_ bool) error PullImage(c VarlinkCall, name_ string) error - ExportImage(c VarlinkCall, name_ string, destination_ string, compress_ bool) error Ping(c VarlinkCall) error - GetVersion(c VarlinkCall) error - CreateContainer(c VarlinkCall) error - KillContainer(c VarlinkCall, name_ string, signal_ int64) error - RemoveContainer(c VarlinkCall, name_ string, force_ bool) error - RemoveImage(c VarlinkCall, name_ string, force_ bool) error - ImportImage(c VarlinkCall, source_ string, reference_ string, message_ string, changes_ []string) error - InspectContainer(c VarlinkCall, name_ string) error - GetContainerLogs(c VarlinkCall, name_ string) error - ListContainerChanges(c VarlinkCall, name_ string) error - RestartContainer(c VarlinkCall, name_ string, timeout_ int64) error + ResizeContainerTty(c VarlinkCall) error + SearchImage(c VarlinkCall, name_ string, limit_ int64) error RenameContainer(c VarlinkCall) error PauseContainer(c VarlinkCall, name_ string) error + AttachToContainer(c VarlinkCall) error PushImage(c VarlinkCall, name_ string, tag_ string, tlsverify_ bool) error + ListContainers(c VarlinkCall) error + CreateContainer(c VarlinkCall, create_ Create) error + ExportContainer(c VarlinkCall, name_ string, path_ string) error + StartContainer(c VarlinkCall, name_ string) error + GetVersion(c VarlinkCall) error + GetContainer(c VarlinkCall, name_ string) error + GetContainerLogs(c VarlinkCall, name_ string) error ListContainerProcesses(c VarlinkCall, name_ string, opts_ []string) error - WaitContainer(c VarlinkCall, name_ string) error + ListContainerChanges(c VarlinkCall, name_ string) error + RestartContainer(c VarlinkCall, name_ string, timeout_ int64) error DeleteStoppedContainers(c VarlinkCall) error - TagImage(c VarlinkCall, name_ string, tagged_ string) error - SearchImage(c VarlinkCall, name_ string, limit_ int64) error - UpdateContainer(c VarlinkCall) error - InspectImage(c VarlinkCall, name_ string) error - HistoryImage(c VarlinkCall, name_ string) error - GetInfo(c VarlinkCall) error - ResizeContainerTty(c VarlinkCall) error - StartContainer(c VarlinkCall) error - StopContainer(c VarlinkCall, name_ string, timeout_ int64) error - AttachToContainer(c VarlinkCall) error + WaitContainer(c VarlinkCall, name_ string) error + ListImages(c VarlinkCall) error BuildImage(c VarlinkCall) error CreateImage(c VarlinkCall) error + GetInfo(c VarlinkCall) error + GetContainerStats(c VarlinkCall, name_ string) error + UpdateContainer(c VarlinkCall) error + UnpauseContainer(c VarlinkCall, name_ string) error + HistoryImage(c VarlinkCall, name_ string) error + RemoveImage(c VarlinkCall, name_ string, force_ bool) error Commit(c VarlinkCall, name_ string, image_name_ string, changes_ []string, author_ string, message_ string, pause_ bool) error - ListContainers(c VarlinkCall) error - GetContainer(c VarlinkCall, name_ string) error - ExportContainer(c VarlinkCall, name_ string, path_ string) error - ListImages(c VarlinkCall) error - DeleteUnusedImages(c VarlinkCall) error + KillContainer(c VarlinkCall, name_ string, signal_ int64) error + ImportImage(c VarlinkCall, source_ string, reference_ string, message_ string, changes_ []string) error + ExportImage(c VarlinkCall, name_ string, destination_ string, compress_ bool) error } // Service object with all methods type VarlinkCall struct{ varlink.Call } // Reply methods for all varlink errors -func (c *VarlinkCall) ReplyContainerNotFound(name_ string) error { - var out struct { - Name string `json:"name"` - } - out.Name = name_ - return c.ReplyError("io.projectatomic.podman.ContainerNotFound", &out) -} - func (c *VarlinkCall) ReplyErrorOccurred(reason_ string) error { var out struct { Reason string `json:"reason"` @@ -1587,44 +1734,36 @@ func (c *VarlinkCall) ReplyImageNotFound(name_ string) error { return c.ReplyError("io.projectatomic.podman.ImageNotFound", &out) } -// Reply methods for all varlink methods -func (c *VarlinkCall) ReplyListContainerProcesses(container_ []string) error { - var out struct { - Container []string `json:"container"` - } - out.Container = []string(container_) - return c.Reply(&out) -} - -func (c *VarlinkCall) ReplyWaitContainer(exitcode_ int64) error { +func (c *VarlinkCall) ReplyContainerNotFound(name_ string) error { var out struct { - Exitcode int64 `json:"exitcode"` + Name string `json:"name"` } - out.Exitcode = exitcode_ - return c.Reply(&out) + out.Name = name_ + return c.ReplyError("io.projectatomic.podman.ContainerNotFound", &out) } -func (c *VarlinkCall) ReplyDeleteStoppedContainers(containers_ []string) error { +// Reply methods for all varlink methods +func (c *VarlinkCall) ReplyCreateImage(notimplemented_ NotImplemented) error { var out struct { - Containers []string `json:"containers"` + Notimplemented NotImplemented `json:"notimplemented"` } - out.Containers = []string(containers_) + out.Notimplemented = notimplemented_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyTagImage(image_ string) error { +func (c *VarlinkCall) ReplyGetInfo(info_ PodmanInfo) error { var out struct { - Image string `json:"image"` + Info PodmanInfo `json:"info"` } - out.Image = image_ + out.Info = info_ return c.Reply(&out) } -func (c *VarlinkCall) ReplySearchImage(images_ []ImageSearch) error { +func (c *VarlinkCall) ReplyGetContainerStats(container_ ContainerStats) error { var out struct { - Images []ImageSearch `json:"images"` + Container ContainerStats `json:"container"` } - out.Images = []ImageSearch(images_) + out.Container = container_ return c.Reply(&out) } @@ -1636,31 +1775,31 @@ func (c *VarlinkCall) ReplyUpdateContainer(notimplemented_ NotImplemented) error return c.Reply(&out) } -func (c *VarlinkCall) ReplyInspectImage(image_ string) error { +func (c *VarlinkCall) ReplyUnpauseContainer(container_ string) error { var out struct { - Image string `json:"image"` + Container string `json:"container"` } - out.Image = image_ + out.Container = container_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyAttachToContainer(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyWaitContainer(exitcode_ int64) error { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Exitcode int64 `json:"exitcode"` } - out.Notimplemented = notimplemented_ + out.Exitcode = exitcode_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyBuildImage(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyListImages(images_ []ImageInList) error { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Images []ImageInList `json:"images"` } - out.Notimplemented = notimplemented_ + out.Images = []ImageInList(images_) return c.Reply(&out) } -func (c *VarlinkCall) ReplyCreateImage(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyBuildImage(notimplemented_ NotImplemented) error { var out struct { Notimplemented NotImplemented `json:"notimplemented"` } @@ -1676,39 +1815,39 @@ func (c *VarlinkCall) ReplyHistoryImage(history_ []ImageHistory) error { return c.Reply(&out) } -func (c *VarlinkCall) ReplyGetInfo(info_ PodmanInfo) error { +func (c *VarlinkCall) ReplyRemoveImage(image_ string) error { var out struct { - Info PodmanInfo `json:"info"` + Image string `json:"image"` } - out.Info = info_ + out.Image = image_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyResizeContainerTty(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyCommit(image_ string) error { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Image string `json:"image"` } - out.Notimplemented = notimplemented_ + out.Image = image_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyStartContainer(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyKillContainer(container_ string) error { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Container string `json:"container"` } - out.Notimplemented = notimplemented_ + out.Container = container_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyStopContainer(container_ string) error { +func (c *VarlinkCall) ReplyImportImage(image_ string) error { var out struct { - Container string `json:"container"` + Image string `json:"image"` } - out.Container = container_ + out.Image = image_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyCommit(image_ string) error { +func (c *VarlinkCall) ReplyExportImage(image_ string) error { var out struct { Image string `json:"image"` } @@ -1716,55 +1855,55 @@ func (c *VarlinkCall) ReplyCommit(image_ string) error { return c.Reply(&out) } -func (c *VarlinkCall) ReplyDeleteUnusedImages(images_ []string) error { +func (c *VarlinkCall) ReplyInspectContainer(container_ string) error { var out struct { - Images []string `json:"images"` + Container string `json:"container"` } - out.Images = []string(images_) + out.Container = container_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyListContainers(containers_ []ListContainerData) error { +func (c *VarlinkCall) ReplyGetAttachSockets(sockets_ Sockets) error { var out struct { - Containers []ListContainerData `json:"containers"` + Sockets Sockets `json:"sockets"` } - out.Containers = []ListContainerData(containers_) + out.Sockets = sockets_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyGetContainer(container_ ListContainerData) error { +func (c *VarlinkCall) ReplyInspectImage(image_ string) error { var out struct { - Container ListContainerData `json:"container"` + Image string `json:"image"` } - out.Container = container_ + out.Image = image_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyExportContainer(tarfile_ string) error { +func (c *VarlinkCall) ReplyTagImage(image_ string) error { var out struct { - Tarfile string `json:"tarfile"` + Image string `json:"image"` } - out.Tarfile = tarfile_ + out.Image = image_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyListImages(images_ []ImageInList) error { +func (c *VarlinkCall) ReplyDeleteUnusedImages(images_ []string) error { var out struct { - Images []ImageInList `json:"images"` + Images []string `json:"images"` } - out.Images = []ImageInList(images_) + out.Images = []string(images_) return c.Reply(&out) } -func (c *VarlinkCall) ReplyGetContainerStats(container_ ContainerStats) error { +func (c *VarlinkCall) ReplyStopContainer(container_ string) error { var out struct { - Container ContainerStats `json:"container"` + Container string `json:"container"` } out.Container = container_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyUnpauseContainer(container_ string) error { +func (c *VarlinkCall) ReplyRemoveContainer(container_ string) error { var out struct { Container string `json:"container"` } @@ -1780,31 +1919,31 @@ func (c *VarlinkCall) ReplyPullImage(id_ string) error { return c.Reply(&out) } -func (c *VarlinkCall) ReplyRemoveContainer(container_ string) error { +func (c *VarlinkCall) ReplyPing(ping_ StringResponse) error { var out struct { - Container string `json:"container"` + Ping StringResponse `json:"ping"` } - out.Container = container_ + out.Ping = ping_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyRemoveImage(image_ string) error { +func (c *VarlinkCall) ReplyResizeContainerTty(notimplemented_ NotImplemented) error { var out struct { - Image string `json:"image"` + Notimplemented NotImplemented `json:"notimplemented"` } - out.Image = image_ + out.Notimplemented = notimplemented_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyImportImage(image_ string) error { +func (c *VarlinkCall) ReplySearchImage(images_ []ImageSearch) error { var out struct { - Image string `json:"image"` + Images []ImageSearch `json:"images"` } - out.Image = image_ + out.Images = []ImageSearch(images_) return c.Reply(&out) } -func (c *VarlinkCall) ReplyExportImage(image_ string) error { +func (c *VarlinkCall) ReplyPushImage(image_ string) error { var out struct { Image string `json:"image"` } @@ -1812,31 +1951,31 @@ func (c *VarlinkCall) ReplyExportImage(image_ string) error { return c.Reply(&out) } -func (c *VarlinkCall) ReplyPing(ping_ StringResponse) error { +func (c *VarlinkCall) ReplyListContainers(containers_ []ListContainerData) error { var out struct { - Ping StringResponse `json:"ping"` + Containers []ListContainerData `json:"containers"` } - out.Ping = ping_ + out.Containers = []ListContainerData(containers_) return c.Reply(&out) } -func (c *VarlinkCall) ReplyGetVersion(version_ Version) error { +func (c *VarlinkCall) ReplyCreateContainer(container_ string) error { var out struct { - Version Version `json:"version"` + Container string `json:"container"` } - out.Version = version_ + out.Container = container_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyCreateContainer(notimplemented_ NotImplemented) error { +func (c *VarlinkCall) ReplyExportContainer(tarfile_ string) error { var out struct { - Notimplemented NotImplemented `json:"notimplemented"` + Tarfile string `json:"tarfile"` } - out.Notimplemented = notimplemented_ + out.Tarfile = tarfile_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyKillContainer(container_ string) error { +func (c *VarlinkCall) ReplyStartContainer(container_ string) error { var out struct { Container string `json:"container"` } @@ -1860,17 +1999,25 @@ func (c *VarlinkCall) ReplyPauseContainer(container_ string) error { return c.Reply(&out) } -func (c *VarlinkCall) ReplyPushImage(image_ string) error { +func (c *VarlinkCall) ReplyAttachToContainer(notimplemented_ NotImplemented) error { var out struct { - Image string `json:"image"` + Notimplemented NotImplemented `json:"notimplemented"` } - out.Image = image_ + out.Notimplemented = notimplemented_ return c.Reply(&out) } -func (c *VarlinkCall) ReplyInspectContainer(container_ string) error { +func (c *VarlinkCall) ReplyGetVersion(version_ Version) error { var out struct { - Container string `json:"container"` + Version Version `json:"version"` + } + out.Version = version_ + return c.Reply(&out) +} + +func (c *VarlinkCall) ReplyGetContainer(container_ ListContainerData) error { + var out struct { + Container ListContainerData `json:"container"` } out.Container = container_ return c.Reply(&out) @@ -1884,6 +2031,14 @@ func (c *VarlinkCall) ReplyGetContainerLogs(container_ []string) error { return c.Reply(&out) } +func (c *VarlinkCall) ReplyListContainerProcesses(container_ []string) error { + var out struct { + Container []string `json:"container"` + } + out.Container = []string(container_) + return c.Reply(&out) +} + func (c *VarlinkCall) ReplyListContainerChanges(container_ ContainerChanges) error { var out struct { Container ContainerChanges `json:"container"` @@ -1900,33 +2055,53 @@ func (c *VarlinkCall) ReplyRestartContainer(container_ string) error { return c.Reply(&out) } +func (c *VarlinkCall) ReplyDeleteStoppedContainers(containers_ []string) error { + var out struct { + Containers []string `json:"containers"` + } + out.Containers = []string(containers_) + return c.Reply(&out) +} + // Dummy implementations for all varlink methods -func (s *VarlinkInterface) UpdateContainer(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.UpdateContainer") +func (s *VarlinkInterface) GetVersion(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetVersion") } -func (s *VarlinkInterface) InspectImage(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.InspectImage") +func (s *VarlinkInterface) GetContainer(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainer") } -func (s *VarlinkInterface) GetInfo(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetInfo") +func (s *VarlinkInterface) GetContainerLogs(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainerLogs") } -func (s *VarlinkInterface) ResizeContainerTty(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ResizeContainerTty") +func (s *VarlinkInterface) DeleteStoppedContainers(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.DeleteStoppedContainers") } -func (s *VarlinkInterface) StartContainer(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.StartContainer") +func (s *VarlinkInterface) ListContainerProcesses(c VarlinkCall, name_ string, opts_ []string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainerProcesses") } -func (s *VarlinkInterface) StopContainer(c VarlinkCall, name_ string, timeout_ int64) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.StopContainer") +func (s *VarlinkInterface) ListContainerChanges(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainerChanges") } -func (s *VarlinkInterface) AttachToContainer(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.AttachToContainer") +func (s *VarlinkInterface) RestartContainer(c VarlinkCall, name_ string, timeout_ int64) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.RestartContainer") +} + +func (s *VarlinkInterface) UnpauseContainer(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.UnpauseContainer") +} + +func (s *VarlinkInterface) WaitContainer(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.WaitContainer") +} + +func (s *VarlinkInterface) ListImages(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListImages") } func (s *VarlinkInterface) BuildImage(c VarlinkCall) error { @@ -1937,92 +2112,88 @@ func (s *VarlinkInterface) CreateImage(c VarlinkCall) error { return c.ReplyMethodNotImplemented("io.projectatomic.podman.CreateImage") } -func (s *VarlinkInterface) HistoryImage(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.HistoryImage") -} - -func (s *VarlinkInterface) Commit(c VarlinkCall, name_ string, image_name_ string, changes_ []string, author_ string, message_ string, pause_ bool) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.Commit") +func (s *VarlinkInterface) GetInfo(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetInfo") } -func (s *VarlinkInterface) ListContainers(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainers") +func (s *VarlinkInterface) GetContainerStats(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainerStats") } -func (s *VarlinkInterface) GetContainer(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainer") +func (s *VarlinkInterface) UpdateContainer(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.UpdateContainer") } -func (s *VarlinkInterface) ExportContainer(c VarlinkCall, name_ string, path_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ExportContainer") +func (s *VarlinkInterface) HistoryImage(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.HistoryImage") } -func (s *VarlinkInterface) ListImages(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListImages") +func (s *VarlinkInterface) RemoveImage(c VarlinkCall, name_ string, force_ bool) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.RemoveImage") } -func (s *VarlinkInterface) DeleteUnusedImages(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.DeleteUnusedImages") +func (s *VarlinkInterface) Commit(c VarlinkCall, name_ string, image_name_ string, changes_ []string, author_ string, message_ string, pause_ bool) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.Commit") } -func (s *VarlinkInterface) GetContainerStats(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainerStats") +func (s *VarlinkInterface) KillContainer(c VarlinkCall, name_ string, signal_ int64) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.KillContainer") } -func (s *VarlinkInterface) UnpauseContainer(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.UnpauseContainer") +func (s *VarlinkInterface) ImportImage(c VarlinkCall, source_ string, reference_ string, message_ string, changes_ []string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ImportImage") } -func (s *VarlinkInterface) PullImage(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.PullImage") +func (s *VarlinkInterface) ExportImage(c VarlinkCall, name_ string, destination_ string, compress_ bool) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ExportImage") } -func (s *VarlinkInterface) Ping(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.Ping") +func (s *VarlinkInterface) TagImage(c VarlinkCall, name_ string, tagged_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.TagImage") } -func (s *VarlinkInterface) GetVersion(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetVersion") +func (s *VarlinkInterface) DeleteUnusedImages(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.DeleteUnusedImages") } -func (s *VarlinkInterface) CreateContainer(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.CreateContainer") +func (s *VarlinkInterface) InspectContainer(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.InspectContainer") } -func (s *VarlinkInterface) KillContainer(c VarlinkCall, name_ string, signal_ int64) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.KillContainer") +func (s *VarlinkInterface) GetAttachSockets(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetAttachSockets") } -func (s *VarlinkInterface) RemoveContainer(c VarlinkCall, name_ string, force_ bool) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.RemoveContainer") +func (s *VarlinkInterface) InspectImage(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.InspectImage") } -func (s *VarlinkInterface) RemoveImage(c VarlinkCall, name_ string, force_ bool) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.RemoveImage") +func (s *VarlinkInterface) StopContainer(c VarlinkCall, name_ string, timeout_ int64) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.StopContainer") } -func (s *VarlinkInterface) ImportImage(c VarlinkCall, source_ string, reference_ string, message_ string, changes_ []string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ImportImage") +func (s *VarlinkInterface) RemoveContainer(c VarlinkCall, name_ string, force_ bool) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.RemoveContainer") } -func (s *VarlinkInterface) ExportImage(c VarlinkCall, name_ string, destination_ string, compress_ bool) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ExportImage") +func (s *VarlinkInterface) PullImage(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.PullImage") } -func (s *VarlinkInterface) InspectContainer(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.InspectContainer") +func (s *VarlinkInterface) Ping(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.Ping") } -func (s *VarlinkInterface) GetContainerLogs(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.GetContainerLogs") +func (s *VarlinkInterface) ResizeContainerTty(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ResizeContainerTty") } -func (s *VarlinkInterface) ListContainerChanges(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainerChanges") +func (s *VarlinkInterface) SearchImage(c VarlinkCall, name_ string, limit_ int64) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.SearchImage") } -func (s *VarlinkInterface) RestartContainer(c VarlinkCall, name_ string, timeout_ int64) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.RestartContainer") +func (s *VarlinkInterface) StartContainer(c VarlinkCall, name_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.StartContainer") } func (s *VarlinkInterface) RenameContainer(c VarlinkCall) error { @@ -2033,101 +2204,110 @@ func (s *VarlinkInterface) PauseContainer(c VarlinkCall, name_ string) error { return c.ReplyMethodNotImplemented("io.projectatomic.podman.PauseContainer") } -func (s *VarlinkInterface) PushImage(c VarlinkCall, name_ string, tag_ string, tlsverify_ bool) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.PushImage") -} - -func (s *VarlinkInterface) ListContainerProcesses(c VarlinkCall, name_ string, opts_ []string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainerProcesses") +func (s *VarlinkInterface) AttachToContainer(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.AttachToContainer") } -func (s *VarlinkInterface) WaitContainer(c VarlinkCall, name_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.WaitContainer") +func (s *VarlinkInterface) PushImage(c VarlinkCall, name_ string, tag_ string, tlsverify_ bool) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.PushImage") } -func (s *VarlinkInterface) DeleteStoppedContainers(c VarlinkCall) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.DeleteStoppedContainers") +func (s *VarlinkInterface) ListContainers(c VarlinkCall) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ListContainers") } -func (s *VarlinkInterface) TagImage(c VarlinkCall, name_ string, tagged_ string) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.TagImage") +func (s *VarlinkInterface) CreateContainer(c VarlinkCall, create_ Create) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.CreateContainer") } -func (s *VarlinkInterface) SearchImage(c VarlinkCall, name_ string, limit_ int64) error { - return c.ReplyMethodNotImplemented("io.projectatomic.podman.SearchImage") +func (s *VarlinkInterface) ExportContainer(c VarlinkCall, name_ string, path_ string) error { + return c.ReplyMethodNotImplemented("io.projectatomic.podman.ExportContainer") } // Method call dispatcher func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error { switch methodname { - case "GetVersion": - return s.ioprojectatomicpodmanInterface.GetVersion(VarlinkCall{call}) - - case "CreateContainer": - return s.ioprojectatomicpodmanInterface.CreateContainer(VarlinkCall{call}) + case "ListContainerProcesses": + var in struct { + Name string `json:"name"` + Opts []string `json:"opts"` + } + err := call.GetParameters(&in) + if err != nil { + return call.ReplyInvalidParameter("parameters") + } + return s.ioprojectatomicpodmanInterface.ListContainerProcesses(VarlinkCall{call}, in.Name, []string(in.Opts)) - case "KillContainer": + case "ListContainerChanges": var in struct { - Name string `json:"name"` - Signal int64 `json:"signal"` + Name string `json:"name"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.KillContainer(VarlinkCall{call}, in.Name, in.Signal) + return s.ioprojectatomicpodmanInterface.ListContainerChanges(VarlinkCall{call}, in.Name) - case "RemoveContainer": + case "RestartContainer": var in struct { - Name string `json:"name"` - Force bool `json:"force"` + Name string `json:"name"` + Timeout int64 `json:"timeout"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.RemoveContainer(VarlinkCall{call}, in.Name, in.Force) + return s.ioprojectatomicpodmanInterface.RestartContainer(VarlinkCall{call}, in.Name, in.Timeout) - case "RemoveImage": + case "DeleteStoppedContainers": + return s.ioprojectatomicpodmanInterface.DeleteStoppedContainers(VarlinkCall{call}) + + case "BuildImage": + return s.ioprojectatomicpodmanInterface.BuildImage(VarlinkCall{call}) + + case "CreateImage": + return s.ioprojectatomicpodmanInterface.CreateImage(VarlinkCall{call}) + + case "GetInfo": + return s.ioprojectatomicpodmanInterface.GetInfo(VarlinkCall{call}) + + case "GetContainerStats": var in struct { - Name string `json:"name"` - Force bool `json:"force"` + Name string `json:"name"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.RemoveImage(VarlinkCall{call}, in.Name, in.Force) + return s.ioprojectatomicpodmanInterface.GetContainerStats(VarlinkCall{call}, in.Name) - case "ImportImage": + case "UpdateContainer": + return s.ioprojectatomicpodmanInterface.UpdateContainer(VarlinkCall{call}) + + case "UnpauseContainer": var in struct { - Source string `json:"source"` - Reference string `json:"reference"` - Message string `json:"message"` - Changes []string `json:"changes"` + Name string `json:"name"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.ImportImage(VarlinkCall{call}, in.Source, in.Reference, in.Message, []string(in.Changes)) + return s.ioprojectatomicpodmanInterface.UnpauseContainer(VarlinkCall{call}, in.Name) - case "ExportImage": + case "WaitContainer": var in struct { - Name string `json:"name"` - Destination string `json:"destination"` - Compress bool `json:"compress"` + Name string `json:"name"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.ExportImage(VarlinkCall{call}, in.Name, in.Destination, in.Compress) + return s.ioprojectatomicpodmanInterface.WaitContainer(VarlinkCall{call}, in.Name) - case "Ping": - return s.ioprojectatomicpodmanInterface.Ping(VarlinkCall{call}) + case "ListImages": + return s.ioprojectatomicpodmanInterface.ListImages(VarlinkCall{call}) - case "GetContainerLogs": + case "HistoryImage": var in struct { Name string `json:"name"` } @@ -2135,53 +2315,69 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.GetContainerLogs(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.HistoryImage(VarlinkCall{call}, in.Name) - case "ListContainerChanges": + case "RemoveImage": var in struct { - Name string `json:"name"` + Name string `json:"name"` + Force bool `json:"force"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.ListContainerChanges(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.RemoveImage(VarlinkCall{call}, in.Name, in.Force) - case "RestartContainer": + case "Commit": var in struct { - Name string `json:"name"` - Timeout int64 `json:"timeout"` + Name string `json:"name"` + Image_name string `json:"image_name"` + Changes []string `json:"changes"` + Author string `json:"author"` + Message string `json:"message"` + Pause bool `json:"pause"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.RestartContainer(VarlinkCall{call}, in.Name, in.Timeout) + return s.ioprojectatomicpodmanInterface.Commit(VarlinkCall{call}, in.Name, in.Image_name, []string(in.Changes), in.Author, in.Message, in.Pause) - case "RenameContainer": - return s.ioprojectatomicpodmanInterface.RenameContainer(VarlinkCall{call}) + case "KillContainer": + var in struct { + Name string `json:"name"` + Signal int64 `json:"signal"` + } + err := call.GetParameters(&in) + if err != nil { + return call.ReplyInvalidParameter("parameters") + } + return s.ioprojectatomicpodmanInterface.KillContainer(VarlinkCall{call}, in.Name, in.Signal) - case "PauseContainer": + case "ImportImage": var in struct { - Name string `json:"name"` + Source string `json:"source"` + Reference string `json:"reference"` + Message string `json:"message"` + Changes []string `json:"changes"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.PauseContainer(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.ImportImage(VarlinkCall{call}, in.Source, in.Reference, in.Message, []string(in.Changes)) - case "PushImage": + case "ExportImage": var in struct { - Name string `json:"name"` - Tag string `json:"tag"` - Tlsverify bool `json:"tlsverify"` + Name string `json:"name"` + Destination string `json:"destination"` + Compress bool `json:"compress"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.PushImage(VarlinkCall{call}, in.Name, in.Tag, in.Tlsverify) + return s.ioprojectatomicpodmanInterface.ExportImage(VarlinkCall{call}, in.Name, in.Destination, in.Compress) case "InspectContainer": var in struct { @@ -2193,7 +2389,7 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) } return s.ioprojectatomicpodmanInterface.InspectContainer(VarlinkCall{call}, in.Name) - case "WaitContainer": + case "GetAttachSockets": var in struct { Name string `json:"name"` } @@ -2201,10 +2397,17 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.WaitContainer(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.GetAttachSockets(VarlinkCall{call}, in.Name) - case "DeleteStoppedContainers": - return s.ioprojectatomicpodmanInterface.DeleteStoppedContainers(VarlinkCall{call}) + case "InspectImage": + var in struct { + Name string `json:"name"` + } + err := call.GetParameters(&in) + if err != nil { + return call.ReplyInvalidParameter("parameters") + } + return s.ioprojectatomicpodmanInterface.InspectImage(VarlinkCall{call}, in.Name) case "TagImage": var in struct { @@ -2217,29 +2420,32 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) } return s.ioprojectatomicpodmanInterface.TagImage(VarlinkCall{call}, in.Name, in.Tagged) - case "ListContainerProcesses": + case "DeleteUnusedImages": + return s.ioprojectatomicpodmanInterface.DeleteUnusedImages(VarlinkCall{call}) + + case "StopContainer": var in struct { - Name string `json:"name"` - Opts []string `json:"opts"` + Name string `json:"name"` + Timeout int64 `json:"timeout"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.ListContainerProcesses(VarlinkCall{call}, in.Name, []string(in.Opts)) + return s.ioprojectatomicpodmanInterface.StopContainer(VarlinkCall{call}, in.Name, in.Timeout) - case "SearchImage": + case "RemoveContainer": var in struct { Name string `json:"name"` - Limit int64 `json:"limit"` + Force bool `json:"force"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.SearchImage(VarlinkCall{call}, in.Name, in.Limit) + return s.ioprojectatomicpodmanInterface.RemoveContainer(VarlinkCall{call}, in.Name, in.Force) - case "InspectImage": + case "PullImage": var in struct { Name string `json:"name"` } @@ -2247,96 +2453,78 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.InspectImage(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.PullImage(VarlinkCall{call}, in.Name) - case "UpdateContainer": - return s.ioprojectatomicpodmanInterface.UpdateContainer(VarlinkCall{call}) + case "Ping": + return s.ioprojectatomicpodmanInterface.Ping(VarlinkCall{call}) case "ResizeContainerTty": return s.ioprojectatomicpodmanInterface.ResizeContainerTty(VarlinkCall{call}) - case "StartContainer": - return s.ioprojectatomicpodmanInterface.StartContainer(VarlinkCall{call}) - - case "StopContainer": + case "SearchImage": var in struct { - Name string `json:"name"` - Timeout int64 `json:"timeout"` + Name string `json:"name"` + Limit int64 `json:"limit"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.StopContainer(VarlinkCall{call}, in.Name, in.Timeout) + return s.ioprojectatomicpodmanInterface.SearchImage(VarlinkCall{call}, in.Name, in.Limit) case "AttachToContainer": return s.ioprojectatomicpodmanInterface.AttachToContainer(VarlinkCall{call}) - case "BuildImage": - return s.ioprojectatomicpodmanInterface.BuildImage(VarlinkCall{call}) - - case "CreateImage": - return s.ioprojectatomicpodmanInterface.CreateImage(VarlinkCall{call}) - - case "HistoryImage": + case "PushImage": var in struct { - Name string `json:"name"` + Name string `json:"name"` + Tag string `json:"tag"` + Tlsverify bool `json:"tlsverify"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.HistoryImage(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.PushImage(VarlinkCall{call}, in.Name, in.Tag, in.Tlsverify) - case "GetInfo": - return s.ioprojectatomicpodmanInterface.GetInfo(VarlinkCall{call}) + case "ListContainers": + return s.ioprojectatomicpodmanInterface.ListContainers(VarlinkCall{call}) - case "Commit": + case "CreateContainer": var in struct { - Name string `json:"name"` - Image_name string `json:"image_name"` - Changes []string `json:"changes"` - Author string `json:"author"` - Message string `json:"message"` - Pause bool `json:"pause"` + Create Create `json:"create"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.Commit(VarlinkCall{call}, in.Name, in.Image_name, []string(in.Changes), in.Author, in.Message, in.Pause) + return s.ioprojectatomicpodmanInterface.CreateContainer(VarlinkCall{call}, in.Create) - case "GetContainer": + case "ExportContainer": var in struct { Name string `json:"name"` + Path string `json:"path"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.GetContainer(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.ExportContainer(VarlinkCall{call}, in.Name, in.Path) - case "ExportContainer": + case "StartContainer": var in struct { Name string `json:"name"` - Path string `json:"path"` } err := call.GetParameters(&in) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.ExportContainer(VarlinkCall{call}, in.Name, in.Path) - - case "ListImages": - return s.ioprojectatomicpodmanInterface.ListImages(VarlinkCall{call}) + return s.ioprojectatomicpodmanInterface.StartContainer(VarlinkCall{call}, in.Name) - case "DeleteUnusedImages": - return s.ioprojectatomicpodmanInterface.DeleteUnusedImages(VarlinkCall{call}) - - case "ListContainers": - return s.ioprojectatomicpodmanInterface.ListContainers(VarlinkCall{call}) + case "RenameContainer": + return s.ioprojectatomicpodmanInterface.RenameContainer(VarlinkCall{call}) - case "UnpauseContainer": + case "PauseContainer": var in struct { Name string `json:"name"` } @@ -2344,9 +2532,12 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.UnpauseContainer(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.PauseContainer(VarlinkCall{call}, in.Name) - case "PullImage": + case "GetVersion": + return s.ioprojectatomicpodmanInterface.GetVersion(VarlinkCall{call}) + + case "GetContainer": var in struct { Name string `json:"name"` } @@ -2354,9 +2545,9 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.PullImage(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.GetContainer(VarlinkCall{call}, in.Name) - case "GetContainerStats": + case "GetContainerLogs": var in struct { Name string `json:"name"` } @@ -2364,7 +2555,7 @@ func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) if err != nil { return call.ReplyInvalidParameter("parameters") } - return s.ioprojectatomicpodmanInterface.GetContainerStats(VarlinkCall{call}, in.Name) + return s.ioprojectatomicpodmanInterface.GetContainerLogs(VarlinkCall{call}, in.Name) default: return call.ReplyMethodNotFound(methodname) @@ -2553,6 +2744,124 @@ type PodmanInfo ( podman: InfoPodmanBinary ) +# Sockets describes sockets location for a container +type Sockets( + container_id: string, + io_socket: string, + control_socket: string +) + +# Create is an input structure for creating containers. It closely resembles the +# CreateConfig structure in libpod/pkg/spec. +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, + 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 +) + # Ping provides a response for developers to ensure their varlink setup is working. # #### Example # ~~~ @@ -2582,8 +2891,8 @@ method ListContainers() -> (containers: []ListContainerData) # See also [ListContainers](ListContainers) and [InspectContainer](InspectContainer). method GetContainer(name: string) -> (container: ListContainerData) -# This method is not implemented yet. -method CreateContainer() -> (notimplemented: NotImplemented) +# 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 # data in string format. You can then serialize the string into JSON. A [ContainerNotFound](#ContainerNotFound) @@ -2654,8 +2963,10 @@ method GetContainerStats(name: string) -> (container: ContainerStats) # This method has not be implemented yet. method ResizeContainerTty() -> (notimplemented: NotImplemented) -# This method has not be implemented yet. -method StartContainer() -> (notimplemented: NotImplemented) +# StartContainer starts a created or stopped container. It takes the name or ID of container. It returns +# the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) +# error will be returned. See also [CreateContainer](#CreateContainer). +method StartContainer(name: string) -> (container: string) # StopContainer stops a container given a timeout. It takes the name or ID of a container as well as a # timeout value. The timeout value the time before a forceable stop to the container is applied. It @@ -2700,15 +3011,32 @@ method UnpauseContainer(name: string) -> (container: string) # This method has not be implemented yet. method AttachToContainer() -> (notimplemented: NotImplemented) -# WaitContainer takes the name of ID of a container and waits until the container stops. Upon stopping, the return +# GetAttachSockets takes the name or ID of an existing container. It returns file paths for two sockets needed +# to properly communicate with a container. The first is the actual I/O socket that the container uses. The +# second is a "control" socket where things like resizing the TTY events are sent. If the container cannot be +# found, a [ContainerNotFound](#ContainerNotFound) error will be returned. +# #### Example +# ~~~ +# $ varlink call -m unix:/run/io.projectatomic.podman/io.projectatomic.podman.GetAttachSockets '{"name": "b7624e775431219161"}' +# { +# "sockets": { +# "container_id": "b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca", +# "control_socket": "/var/lib/containers/storage/overlay-containers/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/userdata/ctl", +# "io_socket": "/var/run/libpod/socket/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/attach" +# } +# } +# ~~~ +method GetAttachSockets(name: string) -> (sockets: Sockets) + +# WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return # code of the container is returned. If the container container cannot be found by ID or name, # a [ContainerNotFound](#ContainerNotFound) error is returned. method WaitContainer(name: string) -> (exitcode: int) # RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running # container can be stopped and removed. Upon sucessful removal of the container, its ID is returned. If the -# container cannot be found by name or ID, an [ContainerNotFound](#ContainerNotFound) error will be returned. -# #### Error +# container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned. +# #### Example # ~~~ # $ varlink call -m unix:/run/podman/io.projectatomic.podman/io.projectatomic.podman.RemoveContainer '{"name": "62f4fd98cb57"}' # { diff --git a/libpod/container_attach.go b/libpod/container_attach.go index 3677a3d78..65c878bff 100644 --- a/libpod/container_attach.go +++ b/libpod/container_attach.go @@ -81,9 +81,9 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi logrus.Warnf("Failed to write to control file to resize terminal: %v", err) } }) - logrus.Debug("connecting to socket ", c.attachSocketPath()) + logrus.Debug("connecting to socket ", c.AttachSocketPath()) - conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: c.attachSocketPath(), Net: "unixpacket"}) + conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: c.AttachSocketPath(), Net: "unixpacket"}) if err != nil { return errors.Wrapf(err, "failed to connect to container's attach socket: %v") } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 39a665bb1..e34a79eb1 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -106,14 +106,20 @@ func (c *Container) rwSize() (int64, error) { return c.runtime.store.DiffSize(layer.Parent, layer.ID) } -// The path to the container's root filesystem - where the OCI spec will be +// bundlePath returns the path to the container's root filesystem - where the OCI spec will be // placed, amongst other things func (c *Container) bundlePath() string { return c.config.StaticDir } -// Retrieves the path of the container's attach socket -func (c *Container) attachSocketPath() string { +// ControlSocketPath returns the path to the containers control socket for things like tty +// resizing +func (c *Container) ControlSocketPath() string { + return filepath.Join(c.bundlePath(), "ctl") +} + +// AttachSocketPath retrieves the path of the container's attach socket +func (c *Container) AttachSocketPath() string { return filepath.Join(c.runtime.ociRuntime.socketsDir, c.ID(), "attach") } diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go new file mode 100644 index 000000000..de6e0f593 --- /dev/null +++ b/pkg/spec/createconfig.go @@ -0,0 +1,508 @@ +package createconfig + +import ( + "os" + "strconv" + "strings" + "syscall" + + "github.com/containers/storage" + "github.com/cri-o/ocicni/pkg/ocicni" + "github.com/docker/docker/api/types/container" + "github.com/docker/go-connections/nat" + "github.com/opencontainers/runc/libcontainer/devices" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + "github.com/projectatomic/libpod/libpod" + ann "github.com/projectatomic/libpod/pkg/annotations" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +type mountType string + +// Type constants +const ( + bps = iota + iops + // TypeBind is the type for mounting host dir + TypeBind mountType = "bind" + // TypeVolume is the type for remote storage volumes + // TypeVolume mountType = "volume" // re-enable upon use + // TypeTmpfs is the type for mounting tmpfs + TypeTmpfs mountType = "tmpfs" +) + +// CreateResourceConfig represents resource elements in CreateConfig +// structures +type CreateResourceConfig struct { + BlkioWeight uint16 // blkio-weight + BlkioWeightDevice []string // blkio-weight-device + CPUPeriod uint64 // cpu-period + CPUQuota int64 // cpu-quota + CPURtPeriod uint64 // cpu-rt-period + CPURtRuntime int64 // cpu-rt-runtime + CPUShares uint64 // cpu-shares + CPUs float64 // cpus + CPUsetCPUs string + CPUsetMems string // cpuset-mems + DeviceReadBps []string // device-read-bps + DeviceReadIOps []string // device-read-iops + DeviceWriteBps []string // device-write-bps + DeviceWriteIOps []string // device-write-iops + DisableOomKiller bool // oom-kill-disable + KernelMemory int64 // kernel-memory + Memory int64 //memory + MemoryReservation int64 // memory-reservation + MemorySwap int64 //memory-swap + MemorySwappiness int // memory-swappiness + OomScoreAdj int //oom-score-adj + PidsLimit int64 // pids-limit + ShmSize int64 + Ulimit []string //ulimit +} + +// CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI +type CreateConfig struct { + Runtime *libpod.Runtime + Args []string + CapAdd []string // cap-add + CapDrop []string // cap-drop + CidFile string + ConmonPidFile string + CgroupParent string // cgroup-parent + Command []string + Detach bool // detach + Devices []string // device + DNSOpt []string //dns-opt + DNSSearch []string //dns-search + DNSServers []string //dns + Entrypoint []string //entrypoint + Env map[string]string //env + ExposedPorts map[nat.Port]struct{} + GroupAdd []string // group-add + HostAdd []string //add-host + Hostname string //hostname + Image string + ImageID string + BuiltinImgVolumes map[string]struct{} // volumes defined in the image config + IDMappings *storage.IDMappingOptions + ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore + Interactive bool //interactive + IpcMode container.IpcMode //ipc + IP6Address string //ipv6 + IPAddress string //ip + Labels map[string]string //label + LinkLocalIP []string // link-local-ip + LogDriver string // log-driver + LogDriverOpt []string // log-opt + MacAddress string //mac-address + Name string //name + NetMode container.NetworkMode //net + Network string //network + NetworkAlias []string //network-alias + PidMode container.PidMode //pid + Pod string //pod + PortBindings nat.PortMap + Privileged bool //privileged + Publish []string //publish + PublishAll bool //publish-all + Quiet bool //quiet + ReadOnlyRootfs bool //read-only + Resources CreateResourceConfig + Rm bool //rm + ShmDir string + StopSignal syscall.Signal // stop-signal + StopTimeout uint // stop-timeout + Sysctl map[string]string //sysctl + Tmpfs []string // tmpfs + Tty bool //tty + UsernsMode container.UsernsMode //userns + User string //user + UtsMode container.UTSMode //uts + Volumes []string //volume + WorkDir string //workdir + MountLabel string //SecurityOpts + ProcessLabel string //SecurityOpts + NoNewPrivs bool //SecurityOpts + ApparmorProfile string //SecurityOpts + SeccompProfilePath string //SecurityOpts + SecurityOpts []string +} + +func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } +func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } + +// CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig +func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { + bio := &spec.LinuxBlockIO{} + bio.Weight = &c.Resources.BlkioWeight + if len(c.Resources.BlkioWeightDevice) > 0 { + var lwds []spec.LinuxWeightDevice + for _, i := range c.Resources.BlkioWeightDevice { + wd, err := validateweightDevice(i) + if err != nil { + return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") + } + wdStat, err := getStatFromPath(wd.path) + if err != nil { + return bio, errors.Wrapf(err, "error getting stat from path %q", wd.path) + } + lwd := spec.LinuxWeightDevice{ + Weight: &wd.weight, + } + lwd.Major = int64(unix.Major(wdStat.Rdev)) + lwd.Minor = int64(unix.Minor(wdStat.Rdev)) + lwds = append(lwds, lwd) + } + bio.WeightDevice = lwds + } + if len(c.Resources.DeviceReadBps) > 0 { + readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps) + if err != nil { + return bio, err + } + bio.ThrottleReadBpsDevice = readBps + } + if len(c.Resources.DeviceWriteBps) > 0 { + writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps) + if err != nil { + return bio, err + } + bio.ThrottleWriteBpsDevice = writeBpds + } + if len(c.Resources.DeviceReadIOps) > 0 { + readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops) + if err != nil { + return bio, err + } + bio.ThrottleReadIOPSDevice = readIOps + } + if len(c.Resources.DeviceWriteIOps) > 0 { + writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops) + if err != nil { + return bio, err + } + bio.ThrottleWriteIOPSDevice = writeIOps + } + return bio, nil +} + +func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { + var ( + ltds []spec.LinuxThrottleDevice + t *throttleDevice + err error + ) + for _, i := range throttleInput { + if rateType == bps { + t, err = validateBpsDevice(i) + } else { + t, err = validateIOpsDevice(i) + } + if err != nil { + return []spec.LinuxThrottleDevice{}, err + } + ltdStat, err := getStatFromPath(t.path) + if err != nil { + return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path) + } + ltd := spec.LinuxThrottleDevice{ + Rate: t.rate, + } + ltd.Major = int64(unix.Major(ltdStat.Rdev)) + ltd.Minor = int64(unix.Minor(ltdStat.Rdev)) + ltds = append(ltds, ltd) + } + return ltds, nil +} + +// GetAnnotations returns the all the annotations for the container +func (c *CreateConfig) GetAnnotations() map[string]string { + a := getDefaultAnnotations() + // TODO - Which annotations do we want added by default + // TODO - This should be added to the DB long term + if c.Tty { + a["io.kubernetes.cri-o.TTY"] = "true" + } + return a +} + +func getDefaultAnnotations() map[string]string { + var annotations map[string]string + annotations = make(map[string]string) + annotations[ann.Annotations] = "" + annotations[ann.ContainerID] = "" + annotations[ann.ContainerName] = "" + annotations[ann.ContainerType] = "sandbox" + annotations[ann.Created] = "" + annotations[ann.HostName] = "" + annotations[ann.IP] = "" + annotations[ann.Image] = "" + annotations[ann.ImageName] = "" + annotations[ann.ImageRef] = "" + annotations[ann.KubeName] = "" + annotations[ann.Labels] = "" + annotations[ann.LogPath] = "" + annotations[ann.Metadata] = "" + annotations[ann.Name] = "" + annotations[ann.PrivilegedRuntime] = "" + annotations[ann.ResolvPath] = "" + annotations[ann.HostnamePath] = "" + annotations[ann.SandboxID] = "" + annotations[ann.SandboxName] = "" + annotations[ann.ShmPath] = "" + annotations[ann.MountPoint] = "" + annotations[ann.TrustedSandbox] = "" + annotations[ann.TTY] = "false" + annotations[ann.Stdin] = "" + annotations[ann.StdinOnce] = "" + annotations[ann.Volumes] = "" + + return annotations +} + +//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs +func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) { + var m []spec.Mount + var options []string + for _, i := range c.Volumes { + // We need to handle SELinux options better here, specifically :Z + spliti := strings.Split(i, ":") + if len(spliti) > 2 { + options = strings.Split(spliti[2], ",") + } + if libpod.MountExists(specMounts, spliti[1]) { + continue + } + options = append(options, "rbind") + var foundrw, foundro, foundz, foundZ bool + var rootProp string + for _, opt := range options { + switch opt { + case "rw": + foundrw = true + case "ro": + foundro = true + case "z": + foundz = true + case "Z": + foundZ = true + case "private", "rprivate", "slave", "rslave", "shared", "rshared": + rootProp = opt + } + } + if !foundrw && !foundro { + options = append(options, "rw") + } + if foundz { + if err := label.Relabel(spliti[0], c.MountLabel, true); err != nil { + return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) + } + } + if foundZ { + if err := label.Relabel(spliti[0], c.MountLabel, false); err != nil { + return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) + } + } + if rootProp == "" { + options = append(options, "private") + } + + m = append(m, spec.Mount{ + Destination: spliti[1], + Type: string(TypeBind), + Source: spliti[0], + Options: options, + }) + } + + // volumes from image config + if c.ImageVolumeType != "tmpfs" { + return m, nil + } + for vol := range c.BuiltinImgVolumes { + if libpod.MountExists(specMounts, vol) { + continue + } + mount := spec.Mount{ + Destination: vol, + Type: string(TypeTmpfs), + Source: string(TypeTmpfs), + Options: []string{"rw", "noexec", "nosuid", "nodev", "tmpcopyup"}, + } + m = append(m, mount) + } + return m, nil +} + +//GetTmpfsMounts takes user provided input for Tmpfs mounts and creates Mount structs +func (c *CreateConfig) GetTmpfsMounts() []spec.Mount { + var m []spec.Mount + for _, i := range c.Tmpfs { + // Default options if nothing passed + options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"} + spliti := strings.Split(i, ":") + destPath := spliti[0] + if len(spliti) > 1 { + options = strings.Split(spliti[1], ",") + } + m = append(m, spec.Mount{ + Destination: destPath, + Type: string(TypeTmpfs), + Options: options, + Source: string(TypeTmpfs), + }) + } + return m +} + +// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions +func (c *CreateConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, error) { + var options []libpod.CtrCreateOption + var portBindings []ocicni.PortMapping + var err error + + // Uncomment after talking to mheon about unimplemented funcs + // options = append(options, libpod.WithLabels(c.labels)) + + if c.Interactive { + options = append(options, libpod.WithStdin()) + } + if c.Name != "" { + logrus.Debugf("appending name %s", c.Name) + options = append(options, libpod.WithName(c.Name)) + } + + if len(c.PortBindings) > 0 { + portBindings, err = c.CreatePortBindings() + if err != nil { + return nil, errors.Wrapf(err, "unable to create port bindings") + } + } + + if len(c.Volumes) != 0 { + // Volumes consist of multiple, comma-delineated fields + // The image spec only includes one part of that, so drop the + // others, if they are included + volumes := make([]string, 0, len(c.Volumes)) + for _, vol := range c.Volumes { + volumes = append(volumes, strings.SplitN(vol, ":", 2)[0]) + } + + options = append(options, libpod.WithUserVolumes(volumes)) + } + + if len(c.Command) != 0 { + options = append(options, libpod.WithCommand(c.Command)) + } + + // Add entrypoint unconditionally + // If it's empty it's because it was explicitly set to "" or the image + // does not have one + options = append(options, libpod.WithEntrypoint(c.Entrypoint)) + + if c.NetMode.IsContainer() { + connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer()) + if err != nil { + return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer()) + } + options = append(options, libpod.WithNetNSFrom(connectedCtr)) + } else if !c.NetMode.IsHost() && !c.NetMode.IsNone() { + postConfigureNetNS := (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() + options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}, postConfigureNetNS)) + options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS)) + } + + if c.PidMode.IsContainer() { + connectedCtr, err := c.Runtime.LookupContainer(c.PidMode.Container()) + if err != nil { + return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container()) + } + + options = append(options, libpod.WithPIDNSFrom(connectedCtr)) + } + if c.IpcMode.IsContainer() { + connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container()) + if err != nil { + return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container()) + } + + options = append(options, libpod.WithIPCNSFrom(connectedCtr)) + } + + options = append(options, libpod.WithStopSignal(c.StopSignal)) + options = append(options, libpod.WithStopTimeout(c.StopTimeout)) + if len(c.DNSSearch) > 0 { + options = append(options, libpod.WithDNSSearch(c.DNSSearch)) + } + if len(c.DNSServers) > 0 { + options = append(options, libpod.WithDNS(c.DNSServers)) + } + if len(c.DNSOpt) > 0 { + options = append(options, libpod.WithDNSOption(c.DNSOpt)) + } + if len(c.HostAdd) > 0 { + options = append(options, libpod.WithHosts(c.HostAdd)) + } + logPath := getLoggingPath(c.LogDriverOpt) + if logPath != "" { + options = append(options, libpod.WithLogPath(logPath)) + } + + options = append(options, libpod.WithPrivileged(c.Privileged)) + return options, nil +} + +// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands +func (c *CreateConfig) CreatePortBindings() ([]ocicni.PortMapping, error) { + var portBindings []ocicni.PortMapping + for containerPb, hostPb := range c.PortBindings { + var pm ocicni.PortMapping + pm.ContainerPort = int32(containerPb.Int()) + for _, i := range hostPb { + var hostPort int + var err error + pm.HostIP = i.HostIP + if i.HostPort == "" { + hostPort = containerPb.Int() + } else { + hostPort, err = strconv.Atoi(i.HostPort) + if err != nil { + return nil, errors.Wrapf(err, "unable to convert host port to integer") + } + } + + pm.HostPort = int32(hostPort) + // CNI requires us to make both udp and tcp structs + pm.Protocol = "udp" + portBindings = append(portBindings, pm) + pm.Protocol = "tcp" + portBindings = append(portBindings, pm) + } + } + return portBindings, nil +} + +// AddPrivilegedDevices iterates through host devices and adds all +// host devices to the spec +func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error { + hostDevices, err := devices.HostDevices() + if err != nil { + return err + } + g.ClearLinuxDevices() + for _, d := range hostDevices { + g.AddDevice(Device(d)) + } + g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") + return nil +} + +func getStatFromPath(path string) (unix.Stat_t, error) { + s := unix.Stat_t{} + err := unix.Stat(path, &s) + return s, err +} diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go new file mode 100644 index 000000000..920674b10 --- /dev/null +++ b/pkg/spec/parse.go @@ -0,0 +1,128 @@ +package createconfig + +import ( + "fmt" + "strconv" + "strings" + + "github.com/docker/go-units" + "github.com/opencontainers/runc/libcontainer/configs" + spec "github.com/opencontainers/runtime-spec/specs-go" +) + +// weightDevice is a structure that holds device:weight pair +type weightDevice struct { + path string + weight uint16 +} + +func (w *weightDevice) String() string { + return fmt.Sprintf("%s:%d", w.path, w.weight) +} + +// validateweightDevice validates that the specified string has a valid device-weight format +// for blkio-weight-device flag +func validateweightDevice(val string) (*weightDevice, error) { + split := strings.SplitN(val, ":", 2) + if len(split) != 2 { + return nil, fmt.Errorf("bad format: %s", val) + } + if !strings.HasPrefix(split[0], "/dev/") { + return nil, fmt.Errorf("bad format for device path: %s", val) + } + weight, err := strconv.ParseUint(split[1], 10, 0) + if err != nil { + return nil, fmt.Errorf("invalid weight for device: %s", val) + } + if weight > 0 && (weight < 10 || weight > 1000) { + return nil, fmt.Errorf("invalid weight for device: %s", val) + } + + return &weightDevice{ + path: split[0], + weight: uint16(weight), + }, nil +} + +// throttleDevice is a structure that holds device:rate_per_second pair +type throttleDevice struct { + path string + rate uint64 +} + +func (t *throttleDevice) String() string { + return fmt.Sprintf("%s:%d", t.path, t.rate) +} + +// validateBpsDevice validates that the specified string has a valid device-rate format +// for device-read-bps and device-write-bps flags +func validateBpsDevice(val string) (*throttleDevice, error) { + split := strings.SplitN(val, ":", 2) + if len(split) != 2 { + return nil, fmt.Errorf("bad format: %s", val) + } + if !strings.HasPrefix(split[0], "/dev/") { + return nil, fmt.Errorf("bad format for device path: %s", val) + } + rate, err := units.RAMInBytes(split[1]) + if err != nil { + return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :[]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) + } + if rate < 0 { + return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :[]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) + } + + return &throttleDevice{ + path: split[0], + rate: uint64(rate), + }, nil +} + +// validateIOpsDevice validates that the specified string has a valid device-rate format +// for device-write-iops and device-read-iops flags +func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint + split := strings.SplitN(val, ":", 2) + if len(split) != 2 { + return nil, fmt.Errorf("bad format: %s", val) + } + if !strings.HasPrefix(split[0], "/dev/") { + return nil, fmt.Errorf("bad format for device path: %s", val) + } + rate, err := strconv.ParseUint(split[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :. Number must be a positive integer", val) + } + if rate < 0 { + return nil, fmt.Errorf("invalid rate for device: %s. The correct format is :. Number must be a positive integer", val) + } + + return &throttleDevice{ + path: split[0], + rate: uint64(rate), + }, nil +} + +func getLoggingPath(opts []string) string { + for _, opt := range opts { + arr := strings.SplitN(opt, "=", 2) + if len(arr) == 2 { + if strings.TrimSpace(arr[0]) == "path" { + return strings.TrimSpace(arr[1]) + } + } + } + return "" +} + +// Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. +func Device(d *configs.Device) spec.LinuxDevice { + return spec.LinuxDevice{ + Type: string(d.Type), + Path: d.Path, + Major: d.Major, + Minor: d.Minor, + FileMode: fmPtr(int64(d.FileMode)), + UID: u32Ptr(int64(d.Uid)), + GID: u32Ptr(int64(d.Gid)), + } +} diff --git a/pkg/spec/ports.go b/pkg/spec/ports.go new file mode 100644 index 000000000..4d9a625bf --- /dev/null +++ b/pkg/spec/ports.go @@ -0,0 +1,107 @@ +package createconfig + +import ( + "fmt" + "net" + "strconv" + + "github.com/docker/go-connections/nat" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// ExposedPorts parses user and image ports and returns binding information +func ExposedPorts(expose, publish []string, publishAll bool, imageExposedPorts map[string]struct{}) (map[nat.Port][]nat.PortBinding, error) { + containerPorts := make(map[string]string) + + // add expose ports from the image itself + for expose := range imageExposedPorts { + _, port := nat.SplitProtoPort(expose) + containerPorts[port] = "" + } + + // add the expose ports from the user (--expose) + // can be single or a range + for _, expose := range expose { + //support two formats for expose, original format /[] or /[] + _, port := nat.SplitProtoPort(expose) + //parse the start and end port and create a sequence of ports to expose + //if expose a port, the start and end port are the same + start, end, err := nat.ParsePortRange(port) + if err != nil { + return nil, fmt.Errorf("invalid range format for --expose: %s, error: %s", expose, err) + } + for i := start; i <= end; i++ { + containerPorts[strconv.Itoa(int(i))] = "" + } + } + + // parse user input'd port bindings + pbPorts, portBindings, err := nat.ParsePortSpecs(publish) + if err != nil { + return nil, err + } + + // delete exposed container ports if being used by -p + for i := range pbPorts { + delete(containerPorts, i.Port()) + } + + // iterate container ports and make port bindings from them + if publishAll { + for e := range containerPorts { + //support two formats for expose, original format /[] or /[] + //proto, port := nat.SplitProtoPort(e) + p, err := nat.NewPort("tcp", e) + if err != nil { + return nil, err + } + rp, err := getRandomPort() + if err != nil { + return nil, err + } + logrus.Debug(fmt.Sprintf("Using random host port %d with container port %d", rp, p.Int())) + portBindings[p] = CreatePortBinding(rp, "") + } + } + + // We need to see if any host ports are not populated and if so, we need to assign a + // random port to them. + for k, pb := range portBindings { + if pb[0].HostPort == "" { + hostPort, err := getRandomPort() + if err != nil { + return nil, err + } + logrus.Debug(fmt.Sprintf("Using random host port %d with container port %s", hostPort, k.Port())) + pb[0].HostPort = strconv.Itoa(hostPort) + } + } + return portBindings, nil +} + +func getRandomPort() (int, error) { + l, err := net.Listen("tcp", ":0") + if err != nil { + return 0, errors.Wrapf(err, "unable to get free port") + } + defer l.Close() + _, randomPort, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return 0, errors.Wrapf(err, "unable to determine free port") + } + rp, err := strconv.Atoi(randomPort) + if err != nil { + return 0, errors.Wrapf(err, "unable to convert random port to int") + } + return rp, nil +} + +//CreatePortBinding takes port (int) and IP (string) and creates an array of portbinding structs +func CreatePortBinding(hostPort int, hostIP string) []nat.PortBinding { + pb := nat.PortBinding{ + HostPort: strconv.Itoa(hostPort), + } + pb.HostIP = hostIP + return []nat.PortBinding{pb} +} diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go new file mode 100644 index 000000000..959a24213 --- /dev/null +++ b/pkg/spec/spec.go @@ -0,0 +1,422 @@ +package createconfig + +import ( + "strings" + + "github.com/docker/docker/daemon/caps" + "github.com/docker/docker/pkg/mount" + "github.com/docker/docker/profiles/seccomp" + "github.com/docker/go-units" + "github.com/opencontainers/runc/libcontainer/devices" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "io/ioutil" +) + +const cpuPeriod = 100000 + +// CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec +func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint + cgroupPerm := "ro" + g := generate.New() + g.HostSpecific = true + addCgroup := true + if config.Privileged { + cgroupPerm = "rw" + g.RemoveMount("/sys") + sysMnt := spec.Mount{ + Destination: "/sys", + Type: "sysfs", + Source: "sysfs", + Options: []string{"nosuid", "noexec", "nodev", "rw"}, + } + g.AddMount(sysMnt) + } else if !config.UsernsMode.IsHost() && config.NetMode.IsHost() { + addCgroup = false + g.RemoveMount("/sys") + sysMnt := spec.Mount{ + Destination: "/sys", + Type: "bind", + Source: "/sys", + Options: []string{"nosuid", "noexec", "nodev", "ro", "rbind"}, + } + g.AddMount(sysMnt) + } + + if addCgroup { + cgroupMnt := spec.Mount{ + Destination: "/sys/fs/cgroup", + Type: "cgroup", + Source: "cgroup", + Options: []string{"nosuid", "noexec", "nodev", "relatime", cgroupPerm}, + } + g.AddMount(cgroupMnt) + } + g.SetProcessCwd(config.WorkDir) + g.SetProcessArgs(config.Command) + g.SetProcessTerminal(config.Tty) + + for key, val := range config.GetAnnotations() { + g.AddAnnotation(key, val) + } + g.SetRootReadonly(config.ReadOnlyRootfs) + g.SetHostname(config.Hostname) + if config.Hostname != "" { + g.AddProcessEnv("HOSTNAME", config.Hostname) + } + for sysctlKey, sysctlVal := range config.Sysctl { + g.AddLinuxSysctl(sysctlKey, sysctlVal) + } + g.AddProcessEnv("container", "podman") + + // RESOURCES - MEMORY + if config.Resources.Memory != 0 { + g.SetLinuxResourcesMemoryLimit(config.Resources.Memory) + } + if config.Resources.MemoryReservation != 0 { + g.SetLinuxResourcesMemoryReservation(config.Resources.MemoryReservation) + } + if config.Resources.MemorySwap != 0 { + g.SetLinuxResourcesMemorySwap(config.Resources.MemorySwap) + } + if config.Resources.KernelMemory != 0 { + g.SetLinuxResourcesMemoryKernel(config.Resources.KernelMemory) + } + if config.Resources.MemorySwappiness != -1 { + g.SetLinuxResourcesMemorySwappiness(uint64(config.Resources.MemorySwappiness)) + } + g.SetLinuxResourcesMemoryDisableOOMKiller(config.Resources.DisableOomKiller) + g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj) + + // RESOURCES - CPU + if config.Resources.CPUShares != 0 { + g.SetLinuxResourcesCPUShares(config.Resources.CPUShares) + } + if config.Resources.CPUQuota != 0 { + g.SetLinuxResourcesCPUQuota(config.Resources.CPUQuota) + } + if config.Resources.CPUPeriod != 0 { + g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod) + } + if config.Resources.CPUs != 0 { + g.SetLinuxResourcesCPUPeriod(cpuPeriod) + g.SetLinuxResourcesCPUQuota(int64(config.Resources.CPUs * cpuPeriod)) + } + if config.Resources.CPURtRuntime != 0 { + g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime) + } + if config.Resources.CPURtPeriod != 0 { + g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod) + } + if config.Resources.CPUsetCPUs != "" { + g.SetLinuxResourcesCPUCpus(config.Resources.CPUsetCPUs) + } + if config.Resources.CPUsetMems != "" { + g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems) + } + + // Devices + if config.Privileged { + // If privileged, we need to add all the host devices to the + // spec. We do not add the user provided ones because we are + // already adding them all. + if err := config.AddPrivilegedDevices(&g); err != nil { + return nil, err + } + } else { + for _, device := range config.Devices { + if err := addDevice(&g, device); err != nil { + return nil, err + } + } + } + + for _, uidmap := range config.IDMappings.UIDMap { + g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size)) + } + for _, gidmap := range config.IDMappings.GIDMap { + g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size)) + } + // SECURITY OPTS + g.SetProcessNoNewPrivileges(config.NoNewPrivs) + g.SetProcessApparmorProfile(config.ApparmorProfile) + g.SetProcessSelinuxLabel(config.ProcessLabel) + g.SetLinuxMountLabel(config.MountLabel) + blockAccessToKernelFilesystems(config, &g) + + // RESOURCES - PIDS + if config.Resources.PidsLimit != 0 { + g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit) + } + + for _, i := range config.Tmpfs { + // Default options if nothing passed + options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"} + spliti := strings.SplitN(i, ":", 2) + if len(spliti) > 1 { + if _, _, err := mount.ParseTmpfsOptions(spliti[1]); err != nil { + return nil, err + } + options = strings.Split(spliti[1], ",") + } + tmpfsMnt := spec.Mount{ + Destination: spliti[0], + Type: "tmpfs", + Source: "tmpfs", + Options: append(options, "tmpcopyup"), + } + g.AddMount(tmpfsMnt) + } + + for name, val := range config.Env { + g.AddProcessEnv(name, val) + } + + if err := addRlimits(config, &g); err != nil { + return nil, err + } + + if err := addPidNS(config, &g); err != nil { + return nil, err + } + + if err := addUserNS(config, &g); err != nil { + return nil, err + } + + if err := addNetNS(config, &g); err != nil { + return nil, err + } + + if err := addUTSNS(config, &g); err != nil { + return nil, err + } + + if err := addIpcNS(config, &g); err != nil { + return nil, err + } + configSpec := g.Spec() + + // HANDLE CAPABILITIES + // NOTE: Must happen before SECCOMP + if !config.Privileged { + if err := setupCapabilities(config, configSpec); err != nil { + return nil, err + } + } else { + g.SetupPrivileged(true) + } + + // HANDLE SECCOMP + if config.SeccompProfilePath != "unconfined" { + if config.SeccompProfilePath != "" { + seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath) + if err != nil { + return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath) + } + seccompConfig, err := seccomp.LoadProfile(string(seccompProfile), configSpec) + if err != nil { + return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) + } + configSpec.Linux.Seccomp = seccompConfig + } else { + seccompConfig, err := seccomp.GetDefaultProfile(configSpec) + if err != nil { + return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) + } + configSpec.Linux.Seccomp = seccompConfig + } + } + + // Clear default Seccomp profile from Generator for privileged containers + if config.SeccompProfilePath == "unconfined" || config.Privileged { + configSpec.Linux.Seccomp = nil + } + + // BIND MOUNTS + mounts, err := config.GetVolumeMounts(configSpec.Mounts) + if err != nil { + return nil, errors.Wrapf(err, "error getting volume mounts") + } + configSpec.Mounts = append(configSpec.Mounts, mounts...) + for _, mount := range configSpec.Mounts { + for _, opt := range mount.Options { + switch opt { + case "private", "rprivate", "slave", "rslave", "shared", "rshared": + if err := g.SetLinuxRootPropagation(opt); err != nil { + return nil, errors.Wrapf(err, "error setting root propagation for %q", mount.Destination) + } + } + } + } + + // BLOCK IO + blkio, err := config.CreateBlockIO() + if err != nil { + return nil, errors.Wrapf(err, "error creating block io") + } + if blkio != nil { + configSpec.Linux.Resources.BlockIO = blkio + } + + /* + //Annotations + Resources: &configSpec.LinuxResources{ + BlockIO: &blkio, + //HugepageLimits: + Network: &configSpec.LinuxNetwork{ + // ClassID *uint32 + // Priorites []LinuxInterfacePriority + }, + }, + //CgroupsPath: + //Namespaces: []LinuxNamespace + // DefaultAction: + // Architectures + // Syscalls: + }, + // RootfsPropagation + // MaskedPaths + // ReadonlyPaths: + // IntelRdt + }, + } + */ + return configSpec, nil +} + +func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) { + if !config.Privileged { + for _, mp := range []string{ + "/proc/kcore", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + } { + g.AddLinuxMaskedPaths(mp) + } + + for _, rp := range []string{ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + } { + g.AddLinuxReadonlyPaths(rp) + } + } +} + +func addPidNS(config *CreateConfig, g *generate.Generator) error { + pidMode := config.PidMode + if pidMode.IsHost() { + return g.RemoveLinuxNamespace(string(spec.PIDNamespace)) + } + if pidMode.IsContainer() { + logrus.Debug("using container pidmode") + } + return nil +} + +func addUserNS(config *CreateConfig, g *generate.Generator) error { + if (len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0) && !config.UsernsMode.IsHost() { + g.AddOrReplaceLinuxNamespace(spec.UserNamespace, "") + } + return nil +} + +func addNetNS(config *CreateConfig, g *generate.Generator) error { + netMode := config.NetMode + if netMode.IsHost() { + logrus.Debug("Using host netmode") + return g.RemoveLinuxNamespace(spec.NetworkNamespace) + } else if netMode.IsNone() { + logrus.Debug("Using none netmode") + return nil + } else if netMode.IsBridge() { + logrus.Debug("Using bridge netmode") + return nil + } else if netMode.IsContainer() { + logrus.Debug("Using container netmode") + } else { + return errors.Errorf("unknown network mode") + } + return nil +} + +func addUTSNS(config *CreateConfig, g *generate.Generator) error { + utsMode := config.UtsMode + if utsMode.IsHost() { + return g.RemoveLinuxNamespace(spec.UTSNamespace) + } + return nil +} + +func addIpcNS(config *CreateConfig, g *generate.Generator) error { + ipcMode := config.IpcMode + if ipcMode.IsHost() { + return g.RemoveLinuxNamespace(spec.IPCNamespace) + } + if ipcMode.IsContainer() { + logrus.Debug("Using container ipcmode") + } + + return nil +} + +func addRlimits(config *CreateConfig, g *generate.Generator) error { + var ( + ul *units.Ulimit + err error + ) + + for _, u := range config.Resources.Ulimit { + if ul, err = units.ParseUlimit(u); err != nil { + return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u) + } + + g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft)) + } + return nil +} + +func setupCapabilities(config *CreateConfig, configSpec *spec.Spec) error { + var err error + var caplist []string + caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, config.CapAdd, config.CapDrop) + if err != nil { + return err + } + + configSpec.Process.Capabilities.Bounding = caplist + configSpec.Process.Capabilities.Permitted = caplist + configSpec.Process.Capabilities.Inheritable = caplist + configSpec.Process.Capabilities.Effective = caplist + return nil +} + +func addDevice(g *generate.Generator, device string) error { + dev, err := devices.DeviceFromPath(device, "rwm") + if err != nil { + return errors.Wrapf(err, "%s is not a valid device", device) + } + linuxdev := spec.LinuxDevice{ + Path: dev.Path, + Type: string(dev.Type), + Major: dev.Major, + Minor: dev.Minor, + FileMode: &dev.FileMode, + UID: &dev.Uid, + GID: &dev.Gid, + } + g.AddDevice(linuxdev) + g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, dev.Permissions) + return nil +} diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go new file mode 100644 index 000000000..2a040a9a0 --- /dev/null +++ b/pkg/spec/spec_test.go @@ -0,0 +1,45 @@ +package createconfig + +import ( + "reflect" + "testing" + + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" +) + +func TestCreateConfig_GetVolumeMounts(t *testing.T) { + data := spec.Mount{ + Destination: "/foobar", + Type: "bind", + Source: "foobar", + Options: []string{"ro", "rbind", "private"}, + } + config := CreateConfig{ + Volumes: []string{"foobar:/foobar:ro"}, + } + specMount, err := config.GetVolumeMounts([]spec.Mount{}) + assert.NoError(t, err) + assert.True(t, reflect.DeepEqual(data, specMount[0])) +} + +func TestCreateConfig_GetAnnotations(t *testing.T) { + config := CreateConfig{} + annotations := config.GetAnnotations() + assert.True(t, reflect.DeepEqual("sandbox", annotations["io.kubernetes.cri-o.ContainerType"])) +} + +func TestCreateConfig_GetTmpfsMounts(t *testing.T) { + data := spec.Mount{ + Destination: "/homer", + Type: "tmpfs", + Source: "tmpfs", + Options: []string{"rw", "size=787448k", "mode=1777"}, + } + config := CreateConfig{ + Tmpfs: []string{"/homer:rw,size=787448k,mode=1777"}, + } + tmpfsMount := config.GetTmpfsMounts() + assert.True(t, reflect.DeepEqual(data, tmpfsMount[0])) + +} diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index 9468719fc..43ab3c995 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -67,11 +67,6 @@ func (i *LibpodAPI) GetContainer(call ioprojectatomicpodman.VarlinkCall, name st return call.ReplyGetContainer(makeListContainer(ctr.ID(), batchInfo)) } -// CreateContainer ... -func (i *LibpodAPI) CreateContainer(call ioprojectatomicpodman.VarlinkCall) error { - return call.ReplyMethodNotImplemented("CreateContainer") -} - // InspectContainer ... func (i *LibpodAPI) InspectContainer(call ioprojectatomicpodman.VarlinkCall, name string) error { runtime, err := libpodruntime.GetRuntime(i.Cli) @@ -264,8 +259,26 @@ func (i *LibpodAPI) ResizeContainerTty(call ioprojectatomicpodman.VarlinkCall) e } // StartContainer ... -func (i *LibpodAPI) StartContainer(call ioprojectatomicpodman.VarlinkCall) error { - return call.ReplyMethodNotImplemented("StartContainer") +func (i *LibpodAPI) StartContainer(call ioprojectatomicpodman.VarlinkCall, name string) error { + runtime, err := libpodruntime.GetRuntime(i.Cli) + if err != nil { + return call.ReplyRuntimeError(err.Error()) + } + ctr, err := runtime.LookupContainer(name) + if err != nil { + return call.ReplyContainerNotFound(name) + } + state, err := ctr.State() + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused { + return call.ReplyErrorOccurred("container is alrady running or paused") + } + if err := ctr.Start(getContext()); err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + return call.ReplyStartContainer(ctr.ID()) } // StopContainer ... @@ -429,3 +442,21 @@ func (i *LibpodAPI) DeleteStoppedContainers(call ioprojectatomicpodman.VarlinkCa } return call.ReplyDeleteStoppedContainers(deletedContainers) } + +// GetAttachSockets ... +func (i *LibpodAPI) GetAttachSockets(call ioprojectatomicpodman.VarlinkCall, name string) error { + runtime, err := libpodruntime.GetRuntime(i.Cli) + if err != nil { + return call.ReplyRuntimeError(err.Error()) + } + ctr, err := runtime.LookupContainer(name) + if err != nil { + return call.ReplyContainerNotFound(name) + } + s := ioprojectatomicpodman.Sockets{ + Container_id: ctr.ID(), + Io_socket: ctr.AttachSocketPath(), + Control_socket: ctr.ControlSocketPath(), + } + return call.ReplyGetAttachSockets(s) +} diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go new file mode 100644 index 000000000..77799cb8d --- /dev/null +++ b/pkg/varlinkapi/containers_create.go @@ -0,0 +1,243 @@ +package varlinkapi + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + "syscall" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/pkg/signal" + "github.com/projectatomic/libpod/cmd/podman/libpodruntime" + "github.com/projectatomic/libpod/cmd/podman/varlink" + "github.com/projectatomic/libpod/libpod" + "github.com/projectatomic/libpod/libpod/image" + "github.com/projectatomic/libpod/pkg/inspect" + cc "github.com/projectatomic/libpod/pkg/spec" + "github.com/projectatomic/libpod/pkg/util" + "github.com/sirupsen/logrus" +) + +// CreateContainer ... +func (i *LibpodAPI) CreateContainer(call ioprojectatomicpodman.VarlinkCall, config ioprojectatomicpodman.Create) error { + //mappings, err := util.ParseIDMapping(config.Uidmap, config.Gidmap, config.Subuidmap, config.Subgidmap) + //if err != nil { + // return err + //} + //storageOpts := storage.DefaultStoreOptions + //storageOpts.UIDMap = mappings.UIDMap + //storageOpts.GIDMap = mappings.GIDMap + + runtime, err := libpodruntime.GetRuntime(i.Cli) + if err != nil { + return call.ReplyRuntimeError(err.Error()) + } + defer runtime.Shutdown(false) + + rtc := runtime.GetConfig() + ctx := getContext() + + newImage, err := runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false) + if err != nil { + return err + } + data, err := newImage.Inspect(ctx) + + createConfig, err := varlinkCreateToCreateConfig(ctx, config, runtime, config.Image, data) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + useImageVolumes := createConfig.ImageVolumeType == "bind" + + runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + + options, err := createConfig.GetContainerCreateOptions() + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + // Gather up the options for NewContainer which consist of With... funcs + options = append(options, libpod.WithRootFSFromImage(createConfig.ImageID, createConfig.Image, useImageVolumes)) + options = append(options, libpod.WithSELinuxLabels(createConfig.ProcessLabel, createConfig.MountLabel)) + options = append(options, libpod.WithConmonPidFile(createConfig.ConmonPidFile)) + options = append(options, libpod.WithLabels(createConfig.Labels)) + options = append(options, libpod.WithUser(createConfig.User)) + options = append(options, libpod.WithShmDir(createConfig.ShmDir)) + options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize)) + options = append(options, libpod.WithGroups(createConfig.GroupAdd)) + options = append(options, libpod.WithIDMappings(*createConfig.IDMappings)) + ctr, err := 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 ioprojectatomicpodman.Create, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) { + var ( + inputCommand, command []string + memoryLimit, memoryReservation, memorySwap, memoryKernel int64 + blkioWeight uint16 + ) + + idmappings, err := util.ParseIDMapping(create.Uidmap, create.Gidmap, create.Subuidname, create.Subgidname) + if err != nil { + return nil, err + } + inputCommand = create.Command + entrypoint := create.Entrypoint + + // ENTRYPOINT + // User input entrypoint takes priority over image entrypoint + if len(entrypoint) == 0 { + entrypoint = data.ContainerConfig.Entrypoint + } + // if entrypoint=, we need to clear the entrypoint + if len(entrypoint) == 1 && strings.Join(create.Entrypoint, "") == "" { + entrypoint = []string{} + } + // Build the command + // If we have an entry point, it goes first + if len(entrypoint) > 0 { + command = entrypoint + } + if len(inputCommand) > 0 { + // User command overrides data CMD + command = append(command, inputCommand...) + } else if len(data.ContainerConfig.Cmd) > 0 && len(create.Entrypoint) > 0 { + // If not user command, add CMD + command = append(command, data.ContainerConfig.Cmd...) + } + + if create.Resources.Blkio_weight != 0 { + blkioWeight = uint16(create.Resources.Blkio_weight) + } + + stopSignal := syscall.SIGTERM + if create.Stop_signal > 0 { + stopSignal, err = signal.ParseSignal(fmt.Sprintf("%d", create.Stop_signal)) + if err != nil { + return nil, err + } + } + + user := create.User + if user == "" { + user = data.ContainerConfig.User + } + + // EXPOSED PORTS + portBindings, err := cc.ExposedPorts(create.Exposed_ports, create.Publish, create.Publish_all, data.ContainerConfig.ExposedPorts) + if err != nil { + return nil, err + } + + // NETWORK MODE + networkMode := create.Net_mode + if networkMode == "" { + networkMode = "bridge" + } + + // WORKING DIR + workDir := create.Work_dir + if workDir == "" { + workDir = "/" + } + + imageID := data.ID + config := &cc.CreateConfig{ + Runtime: runtime, + BuiltinImgVolumes: data.ContainerConfig.Volumes, + ConmonPidFile: create.Conmon_pidfile, + ImageVolumeType: create.Image_volume_type, + CapAdd: create.Cap_add, + CapDrop: create.Cap_drop, + CgroupParent: create.Cgroup_parent, + Command: command, + Detach: create.Detach, + Devices: create.Devices, + DNSOpt: create.Dns_opt, + DNSSearch: create.Dns_search, + DNSServers: create.Dns_servers, + Entrypoint: create.Entrypoint, + Env: create.Env, + GroupAdd: create.Group_add, + Hostname: create.Hostname, + HostAdd: create.Host_add, + IDMappings: idmappings, + Image: imageName, + ImageID: imageID, + Interactive: create.Interactive, + Labels: create.Labels, + LogDriver: create.Log_driver, + LogDriverOpt: create.Log_driver_opt, + Name: create.Name, + Network: networkMode, + IpcMode: container.IpcMode(create.Ipc_mode), + NetMode: container.NetworkMode(networkMode), + UtsMode: container.UTSMode(create.Uts_mode), + PidMode: container.PidMode(create.Pid_mode), + Pod: create.Pod, + Privileged: create.Privileged, + Publish: create.Publish, + PublishAll: create.Publish_all, + PortBindings: portBindings, + Quiet: create.Quiet, + ReadOnlyRootfs: create.Readonly_rootfs, + Resources: cc.CreateResourceConfig{ + BlkioWeight: blkioWeight, + BlkioWeightDevice: create.Resources.Blkio_weight_device, + CPUShares: uint64(create.Resources.Cpu_shares), + CPUPeriod: uint64(create.Resources.Cpu_period), + CPUsetCPUs: create.Resources.Cpuset_cpus, + CPUsetMems: create.Resources.Cpuset_mems, + CPUQuota: create.Resources.Cpu_quota, + CPURtPeriod: uint64(create.Resources.Cpu_rt_period), + CPURtRuntime: create.Resources.Cpu_rt_runtime, + CPUs: create.Resources.Cpus, + DeviceReadBps: create.Resources.Device_read_bps, + DeviceReadIOps: create.Resources.Device_write_bps, + DeviceWriteBps: create.Resources.Device_read_iops, + DeviceWriteIOps: create.Resources.Device_write_iops, + DisableOomKiller: create.Resources.Disable_oomkiller, + ShmSize: create.Resources.Shm_size, + Memory: memoryLimit, + MemoryReservation: memoryReservation, + MemorySwap: memorySwap, + MemorySwappiness: int(create.Resources.Memory_swappiness), + KernelMemory: memoryKernel, + OomScoreAdj: int(create.Resources.Oom_score_adj), + PidsLimit: create.Resources.Pids_limit, + Ulimit: create.Resources.Ulimit, + }, + Rm: create.Rm, + ShmDir: create.Shm_dir, + StopSignal: stopSignal, + StopTimeout: uint(create.Stop_timeout), + Sysctl: create.Sys_ctl, + Tmpfs: create.Tmpfs, + Tty: create.Tty, + User: user, + UsernsMode: container.UsernsMode(create.Userns_mode), + Volumes: create.Volumes, + WorkDir: workDir, + } + + return config, nil +} -- cgit v1.2.3-54-g00ecf