From 6ba6ecf59b9204d36388de07b866f157a4d13957 Mon Sep 17 00:00:00 2001 From: baude Date: Fri, 2 Feb 2018 11:02:09 -0600 Subject: Migrate Create|Commit to ginkgo Migrate create and commit bats tests to the ginkgo test suite. In doing so, some structures had to be moved to pkg/podmanstructs/podmanstructs.go so we could do better verification of test results. Signed-off-by: baude Closes: #286 Approved by: rhatdan --- cmd/podman/create.go | 5 +- cmd/podman/images.go | 13 +-- cmd/podman/inspect.go | 105 ++-------------------- cmd/podman/run_test.go | 6 +- libpod/container_api.go | 3 +- libpod/container_inspect.go | 10 +-- libpod/driver/driver.go | 15 ++-- libpod/image_inspect.go | 8 +- libpod/inspect_data.go | 104 --------------------- libpod/runtime_img.go | 7 +- pkg/inspect/inspect.go | 204 ++++++++++++++++++++++++++++++++++++++++++ test/e2e/commit_test.go | 112 +++++++++++++++++++++++ test/e2e/create_test.go | 57 ++++++++++++ test/e2e/libpod_suite_test.go | 45 +++++++++- test/podman_commit.bats | 97 -------------------- test/podman_create.bats | 29 ------ 16 files changed, 456 insertions(+), 364 deletions(-) delete mode 100644 libpod/inspect_data.go create mode 100644 pkg/inspect/inspect.go create mode 100644 test/e2e/commit_test.go create mode 100644 test/e2e/create_test.go delete mode 100644 test/podman_commit.bats delete mode 100644 test/podman_create.bats diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 045703074..ac6bc2969 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -17,6 +17,7 @@ import ( "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -381,7 +382,7 @@ func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[na // imageData pulls down the image if not stored locally and extracts the // default container runtime data out of it. imageData returns the data // to the caller. Example Data: Entrypoint, Env, WorkingDir, Labels ... -func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, string, *libpod.ImageData, error) { +func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, string, *inspect.ImageData, error) { var ( err error imageName, imageID string @@ -420,7 +421,7 @@ func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, s // Parses CLI options related to container creation into a config which can be // parsed into an OCI runtime spec -func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, data *libpod.ImageData) (*createConfig, error) { +func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*createConfig, error) { var command []string var memoryLimit, memoryReservation, memorySwap, memoryKernel int64 var blkioWeight uint16 diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 1f1174950..540a5f4f3 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -13,6 +13,7 @@ import ( "github.com/projectatomic/libpod/cmd/podman/formats" "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod/common" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/urfave/cli" ) @@ -273,7 +274,7 @@ func generateImagesOutput(runtime *libpod.Runtime, images []*storage.Image, opts func generateImagesFilter(params *libpod.ImageFilterParams, filterType string) libpod.ImageFilter { switch filterType { case "label": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.Label == "" { return true } @@ -290,21 +291,21 @@ func generateImagesFilter(params *libpod.ImageFilterParams, filterType string) l return false } case "before-image": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.BeforeImage.IsZero() { return true } return info.Created.Before(params.BeforeImage) } case "since-image": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.SinceImage.IsZero() { return true } return info.Created.After(params.SinceImage) } case "dangling": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.Dangling == "" { return true } @@ -317,14 +318,14 @@ func generateImagesFilter(params *libpod.ImageFilterParams, filterType string) l return false } case "reference": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.ReferencePattern == "" { return true } return libpod.MatchesReference(params.ImageName, params.ReferencePattern) } case "image-input": - return func(image *storage.Image, info *libpod.ImageData) bool { + return func(image *storage.Image, info *inspect.ImageData) bool { if params == nil || params.ImageInput == "" { return true } diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 01de6587d..2e70eaa0a 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -2,12 +2,11 @@ package main import ( "encoding/json" - - "github.com/docker/go-connections/nat" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/projectatomic/libpod/cmd/podman/formats" "github.com/projectatomic/libpod/libpod" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -143,7 +142,7 @@ func inspectCmd(c *cli.Context) error { return nil } -func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *libpod.ContainerInspectData) (*ContainerData, error) { +func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerInspectData) (*inspect.ContainerData, error) { config := ctr.Config() spec := config.Spec @@ -163,9 +162,9 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *libpod.ContainerIn logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err) } - data := &ContainerData{ + data := &inspect.ContainerData{ CtrInspectData: ctrInspectData, - HostConfig: &HostConfig{ + HostConfig: &inspect.HostConfig{ ConsoleSize: spec.Process.ConsoleSize, OomScoreAdj: spec.Process.OOMScoreAdj, CPUShares: shares, @@ -211,7 +210,7 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *libpod.ContainerIn Ulimits: createArtifact.Resources.Ulimit, SecurityOpt: createArtifact.SecurityOpts, }, - Config: &CtrConfig{ + Config: &inspect.CtrConfig{ Hostname: spec.Hostname, User: spec.Process.User, Env: spec.Process.Env, @@ -282,97 +281,3 @@ func getCgroup(spec *specs.Spec) string { } return cgroup } - -// ContainerData holds the podman inspect data for a container -type ContainerData struct { - CtrInspectData *libpod.ContainerInspectData `json:"CtrInspectData"` - HostConfig *HostConfig `json:"HostConfig"` - Config *CtrConfig `json:"Config"` -} - -// LogConfig holds the log information for a container -type LogConfig struct { - Type string `json:"Type"` // TODO - Config map[string]string `json:"Config"` //idk type, TODO -} - -// HostConfig represents the host configuration for the container -type HostConfig struct { - ContainerIDFile string `json:"ContainerIDFile"` - LogConfig *LogConfig `json:"LogConfig"` //TODO - NetworkMode string `json:"NetworkMode"` - PortBindings nat.PortMap `json:"PortBindings"` //TODO - AutoRemove bool `json:"AutoRemove"` - CapAdd []string `json:"CapAdd"` - CapDrop []string `json:"CapDrop"` - DNS []string `json:"DNS"` - DNSOptions []string `json:"DNSOptions"` - DNSSearch []string `json:"DNSSearch"` - ExtraHosts []string `json:"ExtraHosts"` - GroupAdd []uint32 `json:"GroupAdd"` - IpcMode string `json:"IpcMode"` - Cgroup string `json:"Cgroup"` - OomScoreAdj *int `json:"OomScoreAdj"` - PidMode string `json:"PidMode"` - Privileged bool `json:"Privileged"` - PublishAllPorts bool `json:"PublishAllPorts"` //TODO - ReadonlyRootfs bool `json:"ReadonlyRootfs"` - SecurityOpt []string `json:"SecurityOpt"` - UTSMode string `json:"UTSMode"` - UsernsMode string `json:"UsernsMode"` - ShmSize int64 `json:"ShmSize"` - Runtime string `json:"Runtime"` - ConsoleSize *specs.Box `json:"ConsoleSize"` - Isolation string `json:"Isolation"` //TODO - CPUShares *uint64 `json:"CPUSShares"` - Memory int64 `json:"Memory"` - NanoCPUs int `json:"NanoCPUs"` //check type, TODO - CgroupParent string `json:"CgroupParent"` - BlkioWeight *uint16 `json:"BlkioWeight"` - BlkioWeightDevice []specs.LinuxWeightDevice `json:"BlkioWeightDevice"` - BlkioDeviceReadBps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadBps"` - BlkioDeviceWriteBps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteBps"` - BlkioDeviceReadIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadIOps"` - BlkioDeviceWriteIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteIOps"` - CPUPeriod *uint64 `json:"CPUPeriod"` - CPUQuota *int64 `json:"CPUQuota"` - CPURealtimePeriod *uint64 `json:"CPURealtimePeriod"` - CPURealtimeRuntime *int64 `json:"CPURealtimeRuntime"` - CPUSetCPUs string `json:"CPUSetCPUs"` - CPUSetMems string `json:"CPUSetMems"` - Devices []specs.LinuxDevice `json:"Devices"` - DiskQuota int `json:"DiskQuota"` //check type, TODO - KernelMemory *int64 `json:"KernelMemory"` - MemoryReservation *int64 `json:"MemoryReservation"` - MemorySwap *int64 `json:"MemorySwap"` - MemorySwappiness *uint64 `json:"MemorySwappiness"` - OomKillDisable *bool `json:"OomKillDisable"` - PidsLimit *int64 `json:"PidsLimit"` - Ulimits []string `json:"Ulimits"` - CPUCount int `json:"CPUCount"` //check type, TODO - CPUPercent int `json:"CPUPercent"` //check type, TODO - IOMaximumIOps int `json:"IOMaximumIOps"` //check type, TODO - IOMaximumBandwidth int `json:"IOMaximumBandwidth"` //check type, TODO -} - -// CtrConfig holds information about the container configuration -type CtrConfig struct { - Hostname string `json:"Hostname"` - DomainName string `json:"Domainname"` //TODO - User specs.User `json:"User"` - AttachStdin bool `json:"AttachStdin"` //TODO - AttachStdout bool `json:"AttachStdout"` //TODO - AttachStderr bool `json:"AttachStderr"` //TODO - Tty bool `json:"Tty"` - OpenStdin bool `json:"OpenStdin"` - StdinOnce bool `json:"StdinOnce"` //TODO - Env []string `json:"Env"` - Cmd []string `json:"Cmd"` - Image string `json:"Image"` - Volumes map[string]struct{} `json:"Volumes"` - WorkingDir string `json:"WorkingDir"` - Entrypoint string `json:"Entrypoint"` - Labels map[string]string `json:"Labels"` - Annotations map[string]string `json:"Annotations"` - StopSignal uint `json:"StopSignal"` -} diff --git a/cmd/podman/run_test.go b/cmd/podman/run_test.go index b82df86db..55c535337 100644 --- a/cmd/podman/run_test.go +++ b/cmd/podman/run_test.go @@ -6,7 +6,7 @@ import ( units "github.com/docker/go-units" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/projectatomic/libpod/libpod" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/stretchr/testify/assert" "github.com/urfave/cli" ) @@ -22,7 +22,7 @@ var ( ) // generates a mocked ImageData structure based on alpine -func generateAlpineImageData() *libpod.ImageData { +func generateAlpineImageData() *inspect.ImageData { config := &ociv1.ImageConfig{ User: "", ExposedPorts: nil, @@ -35,7 +35,7 @@ func generateAlpineImageData() *libpod.ImageData { StopSignal: "", } - data := &libpod.ImageData{ + data := &inspect.ImageData{ ID: "e21c333399e0aeedfd70e8827c9fba3f8e9b170ef8a48a29945eb7702bf6aa5f", RepoTags: []string{"docker.io/library/alpine:latest"}, RepoDigests: []string{"docker.io/library/alpine@sha256:5cb04fce748f576d7b72a37850641de8bd725365519673c643ef2d14819b42c6"}, diff --git a/libpod/container_api.go b/libpod/container_api.go index c0ccdc212..05b3e89e6 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -17,6 +17,7 @@ import ( "github.com/projectatomic/libpod/libpod/driver" crioAnnotations "github.com/projectatomic/libpod/pkg/annotations" "github.com/projectatomic/libpod/pkg/chrootuser" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/remotecommand" @@ -600,7 +601,7 @@ func (c *Container) RemoveArtifact(name string) error { } // Inspect a container for low-level information -func (c *Container) Inspect(size bool) (*ContainerInspectData, error) { +func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) { if !c.locked { c.lock.Lock() defer c.lock.Unlock() diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 78dd00c16..b07dafa00 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -2,11 +2,11 @@ package libpod import ( "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/projectatomic/libpod/libpod/driver" + "github.com/projectatomic/libpod/pkg/inspect" "github.com/sirupsen/logrus" ) -func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) (*ContainerInspectData, error) { +func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data) (*inspect.ContainerInspectData, error) { config := c.config runtimeInfo := c.state spec := c.config.Spec @@ -20,12 +20,12 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) args = args[1:] } - data := &ContainerInspectData{ + data := &inspect.ContainerInspectData{ ID: config.ID, Created: config.CreatedTime, Path: path, Args: args, - State: &ContainerInspectState{ + State: &inspect.ContainerInspectState{ OciVersion: spec.Version, Status: runtimeInfo.State.String(), Running: runtimeInfo.State == ContainerStateRunning, @@ -53,7 +53,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) ExecIDs: []string{}, //TODO GraphDriver: driverData, Mounts: spec.Mounts, - NetworkSettings: &NetworkSettings{ + NetworkSettings: &inspect.NetworkSettings{ Bridge: "", // TODO SandboxID: "", // TODO - is this even relevant? HairpinMode: false, // TODO diff --git a/libpod/driver/driver.go b/libpod/driver/driver.go index 8475810a8..d84ce8d3c 100644 --- a/libpod/driver/driver.go +++ b/libpod/driver/driver.go @@ -1,12 +1,9 @@ package driver -import cstorage "github.com/containers/storage" - -// Data handles the data for a storage driver -type Data struct { - Name string `json:"Name"` - Data map[string]string `json:"Data"` -} +import ( + cstorage "github.com/containers/storage" + "github.com/projectatomic/libpod/pkg/inspect" +) // GetDriverName returns the name of the driver for the given store func GetDriverName(store cstorage.Store) (string, error) { @@ -27,7 +24,7 @@ func GetDriverMetadata(store cstorage.Store, layerID string) (map[string]string, } // GetDriverData returns the Data struct with information of the driver used by the store -func GetDriverData(store cstorage.Store, layerID string) (*Data, error) { +func GetDriverData(store cstorage.Store, layerID string) (*inspect.Data, error) { name, err := GetDriverName(store) if err != nil { return nil, err @@ -36,7 +33,7 @@ func GetDriverData(store cstorage.Store, layerID string) (*Data, error) { if err != nil { return nil, err } - return &Data{ + return &inspect.Data{ Name: name, Data: metaData, }, nil diff --git a/libpod/image_inspect.go b/libpod/image_inspect.go index 3d904e64b..cc4b8307a 100644 --- a/libpod/image_inspect.go +++ b/libpod/image_inspect.go @@ -9,10 +9,10 @@ import ( digest "github.com/opencontainers/go-digest" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/projectatomic/libpod/libpod/driver" + "github.com/projectatomic/libpod/pkg/inspect" ) -func getImageData(img storage.Image, imgRef types.Image, size int64, driver *driver.Data) (*ImageData, error) { +func getImageData(img storage.Image, imgRef types.Image, size int64, driver *inspect.Data) (*inspect.ImageData, error) { imgSize, err := imgRef.Size() if err != nil { return nil, errors.Wrapf(err, "error reading size of image %q", img.ID) @@ -41,7 +41,7 @@ func getImageData(img storage.Image, imgRef types.Image, size int64, driver *dri repoDigests = append(repoDigests, strings.SplitN(name, ":", 2)[0]+"@"+imgDigest.String()) } - data := &ImageData{ + data := &inspect.ImageData{ ID: img.ID, RepoTags: img.Names, RepoDigests: repoDigests, @@ -57,7 +57,7 @@ func getImageData(img storage.Image, imgRef types.Image, size int64, driver *dri Annotations: annotations, Digest: imgDigest, Labels: info.Labels, - RootFS: &RootFS{ + RootFS: &inspect.RootFS{ Type: ociv1Img.RootFS.Type, Layers: ociv1Img.RootFS.DiffIDs, }, diff --git a/libpod/inspect_data.go b/libpod/inspect_data.go deleted file mode 100644 index 5f9e3166d..000000000 --- a/libpod/inspect_data.go +++ /dev/null @@ -1,104 +0,0 @@ -package libpod - -import ( - "time" - - "github.com/cri-o/ocicni/pkg/ocicni" - digest "github.com/opencontainers/go-digest" - "github.com/opencontainers/image-spec/specs-go/v1" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/projectatomic/libpod/libpod/driver" -) - -// ContainerInspectData handles the data used when inspecting a container -type ContainerInspectData struct { - ID string `json:"ID"` - Created time.Time `json:"Created"` - Path string `json:"Path"` - Args []string `json:"Args"` - State *ContainerInspectState `json:"State"` - ImageID string `json:"Image"` - ImageName string `json:"ImageName"` - ResolvConfPath string `json:"ResolvConfPath"` - HostnamePath string `json:"HostnamePath"` //TODO - HostsPath string `json:"HostsPath"` //TODO - StaticDir string `json:"StaticDir"` - LogPath string `json:"LogPath"` - Name string `json:"Name"` - RestartCount int32 `json:"RestartCount"` //TODO - Driver string `json:"Driver"` - MountLabel string `json:"MountLabel"` - ProcessLabel string `json:"ProcessLabel"` - AppArmorProfile string `json:"AppArmorProfile"` - ExecIDs []string `json:"ExecIDs"` //TODO - GraphDriver *driver.Data `json:"GraphDriver"` - SizeRw int64 `json:"SizeRw,omitempty"` - SizeRootFs int64 `json:"SizeRootFs,omitempty"` - Mounts []specs.Mount `json:"Mounts"` - NetworkSettings *NetworkSettings `json:"NetworkSettings"` //TODO -} - -// ContainerInspectState represents the state of a container. -type ContainerInspectState struct { - OciVersion string `json:"OciVersion"` - Status string `json:"Status"` - Running bool `json:"Running"` - Paused bool `json:"Paused"` - Restarting bool `json:"Restarting"` // TODO - OOMKilled bool `json:"OOMKilled"` - Dead bool `json:"Dead"` - Pid int `json:"Pid"` - ExitCode int32 `json:"ExitCode"` - Error string `json:"Error"` // TODO - StartedAt time.Time `json:"StartedAt"` - FinishedAt time.Time `json:"FinishedAt"` -} - -// NetworkSettings holds information about the newtwork settings of the container -type NetworkSettings struct { - Bridge string `json:"Bridge"` - SandboxID string `json:"SandboxID"` - HairpinMode bool `json:"HairpinMode"` - LinkLocalIPv6Address string `json:"LinkLocalIPv6Address"` - LinkLocalIPv6PrefixLen int `json:"LinkLocalIPv6PrefixLen"` - Ports []ocicni.PortMapping `json:"Ports"` - SandboxKey string `json:"SandboxKey"` - SecondaryIPAddresses []string `json:"SecondaryIPAddresses"` - SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses"` - EndpointID string `json:"EndpointID"` - Gateway string `json:"Gateway"` - GlobalIPv6Addresses []string `json:"GlobalIPv6Addresses"` - GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"` - IPAddress string `json:"IPAddress"` - IPPrefixLen int `json:"IPPrefixLen"` - IPv6Gateway string `json:"IPv6Gateway"` - MacAddress string `json:"MacAddress"` -} - -// ImageData holds the inspect information of an image -type ImageData struct { - ID string `json:"ID"` - Digest digest.Digest `json:"Digest"` - RepoTags []string `json:"RepoTags"` - RepoDigests []string `json:"RepoDigests"` - Parent string `json:"Parent"` - Comment string `json:"Comment"` - Created *time.Time `json:"Created"` - Config *v1.ImageConfig `json:"Config"` - Version string `json:"Version"` - Author string `json:"Author"` - Architecture string `json:"Architecture"` - Os string `json:"Os"` - Size int64 `json:"Size"` - VirtualSize int64 `json:"VirtualSize"` - GraphDriver *driver.Data `json:"GraphDriver"` - RootFS *RootFS `json:"RootFS"` - Labels map[string]string `json:"Labels"` - Annotations map[string]string `json:"Annotations"` -} - -// RootFS holds the root fs information of an image -type RootFS struct { - Type string `json:"Type"` - Layers []digest.Digest `json:"Layers"` -} diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index a572afcbb..76687351d 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -28,6 +28,7 @@ import ( "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod/common" "github.com/projectatomic/libpod/libpod/driver" + "github.com/projectatomic/libpod/pkg/inspect" ) // Runtime API @@ -492,7 +493,7 @@ func getRegistries() ([]string, error) { // ImageFilter is a function to determine whether an image is included in // command output. Images to be outputted are tested using the function. A true // return will include the image, a false return will exclude it. -type ImageFilter func(*storage.Image, *ImageData) bool +type ImageFilter func(*storage.Image, *inspect.ImageData) bool func (ips imageDecomposeStruct) returnFQName() string { return fmt.Sprintf("%s%s/%s:%s", ips.transport, ips.registry, ips.imageName, ips.tag) @@ -1072,7 +1073,7 @@ func (r *Runtime) ImportImage(path string, options CopyOptions) error { } // GetImageInspectInfo returns the inspect information of an image -func (r *Runtime) GetImageInspectInfo(image storage.Image) (*ImageData, error) { +func (r *Runtime) GetImageInspectInfo(image storage.Image) (*inspect.ImageData, error) { r.lock.RLock() defer r.lock.RUnlock() @@ -1082,7 +1083,7 @@ func (r *Runtime) GetImageInspectInfo(image storage.Image) (*ImageData, error) { return r.getImageInspectInfo(image) } -func (r *Runtime) getImageInspectInfo(image storage.Image) (*ImageData, error) { +func (r *Runtime) getImageInspectInfo(image storage.Image) (*inspect.ImageData, error) { imgRef, err := r.getImageRef("@" + image.ID) if err != nil { return nil, errors.Wrapf(err, "error reading image %q", image.ID) diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go new file mode 100644 index 000000000..9e7137560 --- /dev/null +++ b/pkg/inspect/inspect.go @@ -0,0 +1,204 @@ +package inspect + +import ( + "time" + + "github.com/cri-o/ocicni/pkg/ocicni" + "github.com/docker/go-connections/nat" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go/v1" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +// ContainerData holds the podman inspect data for a container +type ContainerData struct { + CtrInspectData *ContainerInspectData `json:"CtrInspectData"` + HostConfig *HostConfig `json:"HostConfig"` + Config *CtrConfig `json:"Config"` +} + +// HostConfig represents the host configuration for the container +type HostConfig struct { + ContainerIDFile string `json:"ContainerIDFile"` + LogConfig *LogConfig `json:"LogConfig"` //TODO + NetworkMode string `json:"NetworkMode"` + PortBindings nat.PortMap `json:"PortBindings"` //TODO + AutoRemove bool `json:"AutoRemove"` + CapAdd []string `json:"CapAdd"` + CapDrop []string `json:"CapDrop"` + DNS []string `json:"DNS"` + DNSOptions []string `json:"DNSOptions"` + DNSSearch []string `json:"DNSSearch"` + ExtraHosts []string `json:"ExtraHosts"` + GroupAdd []uint32 `json:"GroupAdd"` + IpcMode string `json:"IpcMode"` + Cgroup string `json:"Cgroup"` + OomScoreAdj *int `json:"OomScoreAdj"` + PidMode string `json:"PidMode"` + Privileged bool `json:"Privileged"` + PublishAllPorts bool `json:"PublishAllPorts"` //TODO + ReadonlyRootfs bool `json:"ReadonlyRootfs"` + SecurityOpt []string `json:"SecurityOpt"` + UTSMode string `json:"UTSMode"` + UsernsMode string `json:"UsernsMode"` + ShmSize int64 `json:"ShmSize"` + Runtime string `json:"Runtime"` + ConsoleSize *specs.Box `json:"ConsoleSize"` + Isolation string `json:"Isolation"` //TODO + CPUShares *uint64 `json:"CPUSShares"` + Memory int64 `json:"Memory"` + NanoCPUs int `json:"NanoCPUs"` //check type, TODO + CgroupParent string `json:"CgroupParent"` + BlkioWeight *uint16 `json:"BlkioWeight"` + BlkioWeightDevice []specs.LinuxWeightDevice `json:"BlkioWeightDevice"` + BlkioDeviceReadBps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadBps"` + BlkioDeviceWriteBps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteBps"` + BlkioDeviceReadIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadIOps"` + BlkioDeviceWriteIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteIOps"` + CPUPeriod *uint64 `json:"CPUPeriod"` + CPUQuota *int64 `json:"CPUQuota"` + CPURealtimePeriod *uint64 `json:"CPURealtimePeriod"` + CPURealtimeRuntime *int64 `json:"CPURealtimeRuntime"` + CPUSetCPUs string `json:"CPUSetCPUs"` + CPUSetMems string `json:"CPUSetMems"` + Devices []specs.LinuxDevice `json:"Devices"` + DiskQuota int `json:"DiskQuota"` //check type, TODO + KernelMemory *int64 `json:"KernelMemory"` + MemoryReservation *int64 `json:"MemoryReservation"` + MemorySwap *int64 `json:"MemorySwap"` + MemorySwappiness *uint64 `json:"MemorySwappiness"` + OomKillDisable *bool `json:"OomKillDisable"` + PidsLimit *int64 `json:"PidsLimit"` + Ulimits []string `json:"Ulimits"` + CPUCount int `json:"CPUCount"` //check type, TODO + CPUPercent int `json:"CPUPercent"` //check type, TODO + IOMaximumIOps int `json:"IOMaximumIOps"` //check type, TODO + IOMaximumBandwidth int `json:"IOMaximumBandwidth"` //check type, TODO +} + +// CtrConfig holds information about the container configuration +type CtrConfig struct { + Hostname string `json:"Hostname"` + DomainName string `json:"Domainname"` //TODO + User specs.User `json:"User"` + AttachStdin bool `json:"AttachStdin"` //TODO + AttachStdout bool `json:"AttachStdout"` //TODO + AttachStderr bool `json:"AttachStderr"` //TODO + Tty bool `json:"Tty"` + OpenStdin bool `json:"OpenStdin"` + StdinOnce bool `json:"StdinOnce"` //TODO + Env []string `json:"Env"` + Cmd []string `json:"Cmd"` + Image string `json:"Image"` + Volumes map[string]struct{} `json:"Volumes"` + WorkingDir string `json:"WorkingDir"` + Entrypoint string `json:"Entrypoint"` + Labels map[string]string `json:"Labels"` + Annotations map[string]string `json:"Annotations"` + StopSignal uint `json:"StopSignal"` +} + +// LogConfig holds the log information for a container +type LogConfig struct { + Type string `json:"Type"` // TODO + Config map[string]string `json:"Config"` //idk type, TODO +} + +// ImageData holds the inspect information of an image +type ImageData struct { + ID string `json:"ID"` + Digest digest.Digest `json:"Digest"` + RepoTags []string `json:"RepoTags"` + RepoDigests []string `json:"RepoDigests"` + Parent string `json:"Parent"` + Comment string `json:"Comment"` + Created *time.Time `json:"Created"` + Config *v1.ImageConfig `json:"Config"` + Version string `json:"Version"` + Author string `json:"Author"` + Architecture string `json:"Architecture"` + Os string `json:"Os"` + Size int64 `json:"Size"` + VirtualSize int64 `json:"VirtualSize"` + GraphDriver *Data `json:"GraphDriver"` + RootFS *RootFS `json:"RootFS"` + Labels map[string]string `json:"Labels"` + Annotations map[string]string `json:"Annotations"` +} + +// RootFS holds the root fs information of an image +type RootFS struct { + Type string `json:"Type"` + Layers []digest.Digest `json:"Layers"` +} + +// Data handles the data for a storage driver +type Data struct { + Name string `json:"Name"` + Data map[string]string `json:"Data"` +} + +// ContainerInspectData handles the data used when inspecting a container +type ContainerInspectData struct { + ID string `json:"ID"` + Created time.Time `json:"Created"` + Path string `json:"Path"` + Args []string `json:"Args"` + State *ContainerInspectState `json:"State"` + ImageID string `json:"Image"` + ImageName string `json:"ImageName"` + ResolvConfPath string `json:"ResolvConfPath"` + HostnamePath string `json:"HostnamePath"` //TODO + HostsPath string `json:"HostsPath"` //TODO + StaticDir string `json:"StaticDir"` + LogPath string `json:"LogPath"` + Name string `json:"Name"` + RestartCount int32 `json:"RestartCount"` //TODO + Driver string `json:"Driver"` + MountLabel string `json:"MountLabel"` + ProcessLabel string `json:"ProcessLabel"` + AppArmorProfile string `json:"AppArmorProfile"` + ExecIDs []string `json:"ExecIDs"` //TODO + GraphDriver *Data `json:"GraphDriver"` + SizeRw int64 `json:"SizeRw,omitempty"` + SizeRootFs int64 `json:"SizeRootFs,omitempty"` + Mounts []specs.Mount `json:"Mounts"` + NetworkSettings *NetworkSettings `json:"NetworkSettings"` //TODO +} + +// ContainerInspectState represents the state of a container. +type ContainerInspectState struct { + OciVersion string `json:"OciVersion"` + Status string `json:"Status"` + Running bool `json:"Running"` + Paused bool `json:"Paused"` + Restarting bool `json:"Restarting"` // TODO + OOMKilled bool `json:"OOMKilled"` + Dead bool `json:"Dead"` + Pid int `json:"Pid"` + ExitCode int32 `json:"ExitCode"` + Error string `json:"Error"` // TODO + StartedAt time.Time `json:"StartedAt"` + FinishedAt time.Time `json:"FinishedAt"` +} + +// NetworkSettings holds information about the newtwork settings of the container +type NetworkSettings struct { + Bridge string `json:"Bridge"` + SandboxID string `json:"SandboxID"` + HairpinMode bool `json:"HairpinMode"` + LinkLocalIPv6Address string `json:"LinkLocalIPv6Address"` + LinkLocalIPv6PrefixLen int `json:"LinkLocalIPv6PrefixLen"` + Ports []ocicni.PortMapping `json:"Ports"` + SandboxKey string `json:"SandboxKey"` + SecondaryIPAddresses []string `json:"SecondaryIPAddresses"` + SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses"` + EndpointID string `json:"EndpointID"` + Gateway string `json:"Gateway"` + GlobalIPv6Addresses []string `json:"GlobalIPv6Addresses"` + GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"` + IPAddress string `json:"IPAddress"` + IPPrefixLen int `json:"IPPrefixLen"` + IPv6Gateway string `json:"IPv6Gateway"` + MacAddress string `json:"MacAddress"` +} diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go new file mode 100644 index 000000000..6955b33d1 --- /dev/null +++ b/test/e2e/commit_test.go @@ -0,0 +1,112 @@ +package integration + +import ( + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman commit", func() { + var ( + tempdir string + err error + podmanTest PodmanTest + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanCreate(tempdir) + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.Cleanup() + + }) + + It("podman commit container", func() { + _, ec, _ := podmanTest.RunLsContainer("test1") + Expect(ec).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"}) + check.WaitWithDefaultTimeout() + data := check.InspectImageJSON() + Expect(StringInSlice("foobar.com/test1-image:latest", data.RepoTags)).To(BeTrue()) + }) + + It("podman commit container with message", func() { + _, ec, _ := podmanTest.RunLsContainer("test1") + Expect(ec).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "--message", "testing-commit", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"}) + check.WaitWithDefaultTimeout() + data := check.InspectImageJSON() + Expect(data.Comment).To(Equal("testing-commit")) + }) + + It("podman commit container with author", func() { + _, ec, _ := podmanTest.RunLsContainer("test1") + Expect(ec).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "--author", "snoopy", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"}) + check.WaitWithDefaultTimeout() + data := check.InspectImageJSON() + Expect(data.Author).To(Equal("snoopy")) + }) + + It("podman commit container with change flag", func() { + test := podmanTest.Podman([]string{"run", "--name", "test1", "-d", fedoraMinimal, "ls"}) + test.WaitWithDefaultTimeout() + Expect(test.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "--change", "LABEL=image=blue", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"}) + check.WaitWithDefaultTimeout() + data := check.InspectImageJSON() + foundBlue := false + for _, i := range data.Labels { + if i == "blue" { + foundBlue = true + break + } + } + Expect(foundBlue).To(Equal(true)) + }) + + It("podman commit container with pause flag", func() { + _, ec, _ := podmanTest.RunLsContainer("test1") + Expect(ec).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "--pause=false", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"}) + check.WaitWithDefaultTimeout() + Expect(check.ExitCode()).To(Equal(0)) + }) +}) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go new file mode 100644 index 000000000..c116cea7d --- /dev/null +++ b/test/e2e/create_test.go @@ -0,0 +1,57 @@ +package integration + +import ( + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman create", func() { + var ( + tempdir string + err error + podmanTest PodmanTest + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanCreate(tempdir) + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.Cleanup() + + }) + + It("podman create container based on a local image", func() { + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + cid := session.OutputToString() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + check := podmanTest.Podman([]string{"inspect", "-l"}) + check.WaitWithDefaultTimeout() + data := check.InspectContainerToJSON() + Expect(data.CtrInspectData.ID).To(ContainSubstring(cid)) + }) + + It("podman create container based on a remote image", func() { + session := podmanTest.Podman([]string{"create", BB_GLIBC, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + }) + + It("podman create using short options", func() { + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + }) +}) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index be9be93d8..27848517f 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -21,6 +21,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "github.com/pkg/errors" + "github.com/projectatomic/libpod/pkg/inspect" ) // - CRIO_ROOT=/var/tmp/checkout PODMAN_BINARY=/usr/bin/podman CONMON_BINARY=/usr/libexec/crio/conmon PAPR=1 sh .papr.sh @@ -218,12 +219,29 @@ func (s *PodmanSession) IsJSONOutputValid() bool { var i interface{} if err := json.Unmarshal(s.Out.Contents(), &i); err != nil { fmt.Println(err) - fmt.Println(s.OutputToString()) return false } return true } +// InspectContainerToJSON takes the session output of an inspect +// container and returns json +func (s *PodmanSession) InspectContainerToJSON() inspect.ContainerData { + var i inspect.ContainerData + err := json.Unmarshal(s.Out.Contents(), &i) + Expect(err).To(BeNil()) + return i +} + +// InspectImageJSON takes the session output of an inspect +// image and returns json +func (s *PodmanSession) InspectImageJSON() inspect.ImageData { + var i inspect.ImageData + err := json.Unmarshal(s.Out.Contents(), &i) + Expect(err).To(BeNil()) + return i +} + func (s *PodmanSession) WaitWithDefaultTimeout() { s.Wait(defaultWaitTimeout) } @@ -370,3 +388,28 @@ func (p *PodmanTest) NumberOfContainersRunning() int { } return len(containers) } + +//NumberOfContainersreturns an int of how many +// containers are currently defined. +func (p *PodmanTest) NumberOfContainers() int { + var containers []string + ps := p.Podman([]string{"ps", "-aq"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + for _, i := range ps.OutputToStringArray() { + if i != "" { + containers = append(containers, i) + } + } + return len(containers) +} + +// StringInSlice determines if a string is in a string slice, returns bool +func StringInSlice(s string, sl []string) bool { + for _, i := range sl { + if i == s { + return true + } + } + return false +} diff --git a/test/podman_commit.bats b/test/podman_commit.bats deleted file mode 100644 index 45c2b010e..000000000 --- a/test/podman_commit.bats +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -IMAGE="redis:alpine" - -function teardown() { - cleanup_test -} - -function setup() { - copy_images -} - -@test "podman commit default" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d --name my_ctr ${FEDORA_MINIMAL} sleep 6000 - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} images | grep image-committed" - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} stop my_ctr -} - -@test "podman commit with message flag" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d --name my_ctr ${FEDORA_MINIMAL} sleep 6000 - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit --message testing-commit my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} inspect image-committed | grep testing-commit" - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} stop my_ctr -} - -@test "podman commit with author flag" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d --name my_ctr ${FEDORA_MINIMAL} sleep 6000 - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit --author author-name my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} inspect image-committed | grep author-name" - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} stop my_ctr -} - -@test "podman commit with change flag" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d --name my_ctr ${FEDORA_MINIMAL} sleep 6000 - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit --change LABEL=image=blue my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} inspect image-committed | grep blue" - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} stop my_ctr -} - -@test "podman commit with pause flag" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -d --name my_ctr ${FEDORA_MINIMAL} sleep 6000 - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit --pause=false my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} images | grep image-committed" - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} stop my_ctr -} - -@test "podman commit non-running container" { - ${PODMAN_BINARY} ${PODMAN_OPTIONS} create --name my_ctr ${FEDORA_MINIMAL} ls - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} commit my_ctr image-committed - echo "$output" - [ "$status" -eq 0 ] - run bash -c "${PODMAN_BINARY} ${PODMAN_OPTIONS} images | grep image-committed" - echo "$output" - [ "$status" -eq 0 ] - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} rmi image-committed - echo "$output" - [ "$status" -eq 0 ] - ${PODMAN_BINARY} ${PODMAN_OPTIONS} rm my_ctr -} diff --git a/test/podman_create.bats b/test/podman_create.bats deleted file mode 100644 index d7a9cd72e..000000000 --- a/test/podman_create.bats +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -function setup() { - copy_images -} - -function teardown() { - cleanup_test -} - -@test "create a container based on local image" { - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} create $BB ls - echo "$output" - [ "$status" -eq 0 ] -} - -@test "create a container based on a remote image" { - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} create ${BB_GLIBC} ls - echo "$output" - [ "$status" -eq 0 ] -} - -@test "ensure short options" { - run ${PODMAN_BINARY} ${PODMAN_OPTIONS} create -dt ${BB_GLIBC} ls - echo "$output" - [ "$status" -eq 0 ] -} -- cgit v1.2.3-54-g00ecf