diff options
137 files changed, 1052 insertions, 18165 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 5f99b0490..0fa51be63 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -270,24 +270,6 @@ swagger_task: always: *binary_artifacts -endpoint_task: - name: "Test Endpoint" - alias: endpoint - only_if: *not_docs - depends_on: - - build - container: *smallcontainer - env: - <<: *stdenvars - TEST_FLAVOR: endpoint - TEST_ENVIRON: container - CTR_FQIN: ${FEDORA_CONTAINER_FQIN} - clone_script: *full_clone # build-cache not available to container tasks - setup_script: *setup - main_script: *main - always: *runner_stats - - # Check that all included go modules from other sources match # what is expected in `vendor/modules.txt` vs `go.mod`. vendor_task: @@ -328,11 +310,7 @@ alt_build_task: - env: ALT_NAME: 'Build Without CGO' - env: - ALT_NAME: 'Build varlink-API' - - env: ALT_NAME: 'Test build RPM' - - env: - ALT_NAME: 'Build varlink-binaries' setup_script: *setup main_script: *main always: *binary_artifacts @@ -633,7 +611,6 @@ success_task: - build - validate - bindings - - endpoint - swagger - vendor - alt_build diff --git a/.gitignore b/.gitignore index 9e444442a..208a71f37 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,6 @@ /bin/ /brew /build/ -/cmd/podman/varlink/iopodman.go -/cmd/podman/varlink/ioprojectatomicpodman.go /conmon/ contrib/spec/podman.spec *.coverprofile @@ -21,7 +19,6 @@ coverprofile /_output/ /pause/pause.o pkg/api/swagger.yaml -/pkg/varlink/iopodman.go podman-remote*.zip podman*.tar.gz __pycache__ diff --git a/.golangci.yml b/.golangci.yml index b3466d8f9..da22b7602 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,9 +8,6 @@ run: - dependencies - test - pkg/spec - - pkg/varlink - - pkg/varlinkapi - - docs/varlink - vendor skip-files: - iopodman.go diff --git a/API.md b/API.md deleted file mode 100644 index 831367d8e..000000000 --- a/API.md +++ /dev/null @@ -1,2211 +0,0 @@ -# io.podman -Podman Service Interface and API description. The master version of this document can be found -in the [API.md](https://github.com/containers/podman/blob/master/API.md) file in the upstream libpod repository. -## Index - -[func Attach(name: string, detachKeys: string, start: bool) ](#Attach) - -[func AttachControl(name: string) ](#AttachControl) - -[func BuildImage(build: BuildInfo) MoreResponse](#BuildImage) - -[func BuildImageHierarchyMap(name: string) string](#BuildImageHierarchyMap) - -[func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) MoreResponse](#Commit) - -[func ContainerArtifacts(name: string, artifactName: string) string](#ContainerArtifacts) - -[func ContainerCheckpoint(name: string, keep: bool, leaveRunning: bool, tcpEstablished: bool) string](#ContainerCheckpoint) - -[func ContainerConfig(name: string) string](#ContainerConfig) - -[func ContainerExists(name: string) int](#ContainerExists) - -[func ContainerInspectData(name: string, size: bool) string](#ContainerInspectData) - -[func ContainerRestore(name: string, keep: bool, tcpEstablished: bool) string](#ContainerRestore) - -[func ContainerRunlabel(runlabel: Runlabel) ](#ContainerRunlabel) - -[func ContainerStateData(name: string) string](#ContainerStateData) - -[func CreateContainer(create: Create) string](#CreateContainer) - -[func CreateFromCC(in: []string) string](#CreateFromCC) - -[func CreatePod(create: PodCreate) string](#CreatePod) - -[func DeleteStoppedContainers() []string](#DeleteStoppedContainers) - -[func DeleteUnusedImages() []string](#DeleteUnusedImages) - -[func Diff(name: string) DiffInfo](#Diff) - -[func EvictContainer(name: string, removeVolumes: bool) string](#EvictContainer) - -[func ExecContainer(opts: ExecOpts) ](#ExecContainer) - -[func ExportContainer(name: string, path: string) string](#ExportContainer) - -[func ExportImage(name: string, destination: string, compress: bool, tags: []string) string](#ExportImage) - -[func GenerateKube(name: string, service: bool) KubePodService](#GenerateKube) - -[func GetAttachSockets(name: string) Sockets](#GetAttachSockets) - -[func GetContainer(id: string) Container](#GetContainer) - -[func GetContainerLogs(name: string) []string](#GetContainerLogs) - -[func GetContainerStats(name: string) ContainerStats](#GetContainerStats) - -[func GetContainerStatsWithHistory(previousStats: ContainerStats) ContainerStats](#GetContainerStatsWithHistory) - -[func GetContainersByContext(all: bool, latest: bool, args: []string) []string](#GetContainersByContext) - -[func GetContainersByStatus(status: []string) Container](#GetContainersByStatus) - -[func GetContainersLogs(names: []string, follow: bool, latest: bool, since: string, tail: int, timestamps: bool) LogLine](#GetContainersLogs) - -[func GetEvents(filter: []string, since: string, until: string) Event](#GetEvents) - -[func GetImage(id: string) Image](#GetImage) - -[func GetInfo() PodmanInfo](#GetInfo) - -[func GetLayersMapWithImageInfo() string](#GetLayersMapWithImageInfo) - -[func GetPod(name: string) ListPodData](#GetPod) - -[func GetPodStats(name: string) string, ContainerStats](#GetPodStats) - -[func GetPodsByContext(all: bool, latest: bool, args: []string) []string](#GetPodsByContext) - -[func GetPodsByStatus(statuses: []string) []string](#GetPodsByStatus) - -[func GetVersion() string, string, string, string, string, int](#GetVersion) - -[func GetVolumes(args: []string, all: bool) Volume](#GetVolumes) - -[func HealthCheckRun(nameOrID: string) string](#HealthCheckRun) - -[func HistoryImage(name: string) ImageHistory](#HistoryImage) - -[func ImageExists(name: string) int](#ImageExists) - -[func ImageSave(options: ImageSaveOptions) MoreResponse](#ImageSave) - -[func ImageTree(name: string, whatRequires: bool) string](#ImageTree) - -[func ImagesPrune(all: bool, filter: []string) []string](#ImagesPrune) - -[func ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) string](#ImportImage) - -[func InitContainer(name: string) string](#InitContainer) - -[func InspectContainer(name: string) string](#InspectContainer) - -[func InspectImage(name: string) string](#InspectImage) - -[func InspectPod(name: string) string](#InspectPod) - -[func InspectVolume(name: string) string](#InspectVolume) - -[func KillContainer(name: string, signal: int) string](#KillContainer) - -[func KillPod(name: string, signal: int) string](#KillPod) - -[func ListContainerChanges(name: string) ContainerChanges](#ListContainerChanges) - -[func ListContainerMounts() map[string]](#ListContainerMounts) - -[func ListContainerProcesses(name: string, opts: []string) []string](#ListContainerProcesses) - -[func ListContainers() Container](#ListContainers) - -[func ListImages() Image](#ListImages) - -[func ListImagesWithFilters(filters: []string) Image](#ListImagesWithFilters) - -[func ListPods() ListPodData](#ListPods) - -[func LoadImage(name: string, inputFile: string, quiet: bool, deleteFile: bool) MoreResponse](#LoadImage) - -[func MountContainer(name: string) string](#MountContainer) - -[func PauseContainer(name: string) string](#PauseContainer) - -[func PausePod(name: string) string](#PausePod) - -[func PodStateData(name: string) string](#PodStateData) - -[func Ps(opts: PsOpts) PsContainer](#Ps) - -[func PullImage(name: string, creds: AuthConfig) MoreResponse](#PullImage) - -[func PushImage(name: string, tag: string, compress: bool, format: string, removeSignatures: bool, signBy: string) MoreResponse](#PushImage) - -[func ReceiveFile(path: string, delete: bool) int](#ReceiveFile) - -[func RemoveContainer(name: string, force: bool, removeVolumes: bool) string](#RemoveContainer) - -[func RemoveImage(name: string, force: bool) string](#RemoveImage) - -[func RemoveImageWithResponse(name: string, force: bool) RemoveImageResponse](#RemoveImageWithResponse) - -[func RemovePod(name: string, force: bool) string](#RemovePod) - -[func Reset() ](#Reset) - -[func RestartContainer(name: string, timeout: int) string](#RestartContainer) - -[func RestartPod(name: string) string](#RestartPod) - -[func SearchImages(query: string, limit: ?int, filter: ImageSearchFilter) ImageSearchResult](#SearchImages) - -[func SendFile(type: string, length: int) string](#SendFile) - -[func Spec(name: string) string](#Spec) - -[func StartContainer(name: string) string](#StartContainer) - -[func StartPod(name: string) string](#StartPod) - -[func StopContainer(name: string, timeout: int) string](#StopContainer) - -[func StopPod(name: string, timeout: int) string](#StopPod) - -[func TagImage(name: string, tagged: string) string](#TagImage) - -[func Top(nameOrID: string, descriptors: []string) []string](#Top) - -[func TopPod(pod: string, latest: bool, descriptors: []string) []string](#TopPod) - -[func UnmountContainer(name: string, force: bool) ](#UnmountContainer) - -[func UnpauseContainer(name: string) string](#UnpauseContainer) - -[func UnpausePod(name: string) string](#UnpausePod) - -[func UntagImage(name: string, tag: string) string](#UntagImage) - -[func VolumeCreate(options: VolumeCreateOpts) string](#VolumeCreate) - -[func VolumeRemove(options: VolumeRemoveOpts) []string, map[string]](#VolumeRemove) - -[func VolumesPrune() []string, []string](#VolumesPrune) - -[func WaitContainer(name: string, interval: int) int](#WaitContainer) - -[type AuthConfig](#AuthConfig) - -[type BuildInfo](#BuildInfo) - -[type BuildOptions](#BuildOptions) - -[type Container](#Container) - -[type ContainerChanges](#ContainerChanges) - -[type ContainerMount](#ContainerMount) - -[type ContainerNameSpace](#ContainerNameSpace) - -[type ContainerPortMappings](#ContainerPortMappings) - -[type ContainerStats](#ContainerStats) - -[type Create](#Create) - -[type DiffInfo](#DiffInfo) - -[type Event](#Event) - -[type ExecOpts](#ExecOpts) - -[type Image](#Image) - -[type ImageHistory](#ImageHistory) - -[type ImageSaveOptions](#ImageSaveOptions) - -[type ImageSearchFilter](#ImageSearchFilter) - -[type ImageSearchResult](#ImageSearchResult) - -[type InfoDistribution](#InfoDistribution) - -[type InfoGraphStatus](#InfoGraphStatus) - -[type InfoHost](#InfoHost) - -[type InfoPodmanBinary](#InfoPodmanBinary) - -[type InfoRegistry](#InfoRegistry) - -[type InfoStore](#InfoStore) - -[type KubePodService](#KubePodService) - -[type ListPodContainerInfo](#ListPodContainerInfo) - -[type ListPodData](#ListPodData) - -[type LogLine](#LogLine) - -[type MoreResponse](#MoreResponse) - -[type NotImplemented](#NotImplemented) - -[type PodContainerErrorData](#PodContainerErrorData) - -[type PodCreate](#PodCreate) - -[type PodmanInfo](#PodmanInfo) - -[type PsContainer](#PsContainer) - -[type PsOpts](#PsOpts) - -[type RemoveImageResponse](#RemoveImageResponse) - -[type Runlabel](#Runlabel) - -[type Sockets](#Sockets) - -[type StringResponse](#StringResponse) - -[type Volume](#Volume) - -[type VolumeCreateOpts](#VolumeCreateOpts) - -[type VolumeRemoveOpts](#VolumeRemoveOpts) - -[error ContainerNotFound](#ContainerNotFound) - -[error ErrCtrStopped](#ErrCtrStopped) - -[error ErrRequiresCgroupsV2ForRootless](#ErrRequiresCgroupsV2ForRootless) - -[error ErrorOccurred](#ErrorOccurred) - -[error ImageNotFound](#ImageNotFound) - -[error InvalidState](#InvalidState) - -[error NoContainerRunning](#NoContainerRunning) - -[error NoContainersInPod](#NoContainersInPod) - -[error PodContainerError](#PodContainerError) - -[error PodNotFound](#PodNotFound) - -[error RuntimeError](#RuntimeError) - -[error VolumeNotFound](#VolumeNotFound) - -[error WantsMoreRequired](#WantsMoreRequired) - -## Methods -### <a name="Attach"></a>func Attach -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Attach(name: [string](https://godoc.org/builtin#string), detachKeys: [string](https://godoc.org/builtin#string), start: [bool](https://godoc.org/builtin#bool)) </div> -Attach takes the name or ID of a container and sets up the ability to remotely attach to its console. The start -bool is whether you wish to start the container in question first. -### <a name="AttachControl"></a>func AttachControl -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method AttachControl(name: [string](https://godoc.org/builtin#string)) </div> - -### <a name="BuildImage"></a>func BuildImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method BuildImage(build: [BuildInfo](#BuildInfo)) [MoreResponse](#MoreResponse)</div> -BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the -contextDir tarball path, the 'dockerfiles' path, and 'output' option in the BuildInfo structure. The 'output' -options is the name of the of the resulting build. It will return a [MoreResponse](#MoreResponse) structure -that contains the build logs and resulting image ID. -#### Example -~~~ -$ sudo varlink call -m unix:///run/podman/io.podman/io.podman.BuildImage '{"build":{"contextDir":"/tmp/t/context.tar","dockerfiles":["Dockerfile"], "output":"foobar"}}' -{ - "image": { - "id": "", - "logs": [ - "STEP 1: FROM alpine\n" - ] - } -} -{ - "image": { - "id": "", - "logs": [ - "STEP 2: COMMIT foobar\n" - ] - } -} -{ - "image": { - "id": "", - "logs": [ - "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9\n" - ] - } -} -{ - "image": { - "id": "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9", - "logs": [] - } -} -~~~ -### <a name="BuildImageHierarchyMap"></a>func BuildImageHierarchyMap -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method BuildImageHierarchyMap(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -BuildImageHierarchyMap is for the development of Podman and should not be used. -### <a name="Commit"></a>func Commit -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Commit(name: [string](https://godoc.org/builtin#string), image_name: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), author: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), pause: [bool](https://godoc.org/builtin#bool), manifestType: [string](https://godoc.org/builtin#string)) [MoreResponse](#MoreResponse)</div> -Commit, creates an image from an existing container. It requires the name or -ID of the container as well as the resulting image name. Optionally, you can define an author and message -to be added to the resulting image. You can also define changes to the resulting image for the following -attributes: _CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, ONBUILD, STOPSIGNAL, USER, VOLUME, and WORKDIR_. To pause the -container while it is being committed, pass a _true_ bool for the pause argument. If the container cannot -be found by the ID or name provided, a (ContainerNotFound)[#ContainerNotFound] error will be returned; otherwise, -the resulting image's ID will be returned as a string inside a MoreResponse. -### <a name="ContainerArtifacts"></a>func ContainerArtifacts -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerArtifacts(name: [string](https://godoc.org/builtin#string), artifactName: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -ContainerArtifacts returns a container's artifacts in string form. This call is for -development of Podman only and generally should not be used. -### <a name="ContainerCheckpoint"></a>func ContainerCheckpoint -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerCheckpoint(name: [string](https://godoc.org/builtin#string), keep: [bool](https://godoc.org/builtin#bool), leaveRunning: [bool](https://godoc.org/builtin#bool), tcpEstablished: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -ContainerCheckPoint performs a checkpopint on a container by its name or full/partial container -ID. On successful checkpoint, the id of the checkpointed container is returned. -### <a name="ContainerConfig"></a>func ContainerConfig -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerConfig(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -ContainerConfig returns a container's config in string form. This call is for -development of Podman only and generally should not be used. -### <a name="ContainerExists"></a>func ContainerExists -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerExists(name: [string](https://godoc.org/builtin#string)) [int](https://godoc.org/builtin#int)</div> -ContainerExists takes a full or partial container ID or name and returns an int as to -whether the container exists in local storage. A result of 0 means the container does -exists; whereas a result of 1 means it could not be found. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ContainerExists '{"name": "flamboyant_payne"}'{ - "exists": 0 -} -~~~ -### <a name="ContainerInspectData"></a>func ContainerInspectData -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerInspectData(name: [string](https://godoc.org/builtin#string), size: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -ContainerInspectData returns a container's inspect data in string form. This call is for -development of Podman only and generally should not be used. -### <a name="ContainerRestore"></a>func ContainerRestore -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerRestore(name: [string](https://godoc.org/builtin#string), keep: [bool](https://godoc.org/builtin#bool), tcpEstablished: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -ContainerRestore restores a container that has been checkpointed. The container to be restored can -be identified by its name or full/partial container ID. A successful restore will result in the return -of the container's ID. -### <a name="ContainerRunlabel"></a>func ContainerRunlabel -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerRunlabel(runlabel: [Runlabel](#Runlabel)) </div> -ContainerRunlabel runs executes a command as described by a given container image label. -### <a name="ContainerStateData"></a>func ContainerStateData -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ContainerStateData(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -ContainerStateData returns a container's state config in string form. This call is for -development of Podman only and generally should not be used. -### <a name="CreateContainer"></a>func CreateContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method CreateContainer(create: [Create](#Create)) [string](https://godoc.org/builtin#string)</div> -CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. -### <a name="CreateFromCC"></a>func CreateFromCC -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method CreateFromCC(in: [[]string](#[]string)) [string](https://godoc.org/builtin#string)</div> -This call is for the development of Podman only and should not be used. -### <a name="CreatePod"></a>func CreatePod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method CreatePod(create: [PodCreate](#PodCreate)) [string](https://godoc.org/builtin#string)</div> -CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input. -On success, the ID of the newly created pod will be returned. -#### Example -~~~ -$ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"name": "test"}}' -{ - "pod": "b05dee7bd4ccfee688099fe1588a7a898d6ddd6897de9251d4671c9b0feacb2a" -} -# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"infra": true, "share": ["ipc", "net", "uts"]}}' -{ - "pod": "d7697449a8035f613c1a8891286502aca68fff7d5d49a85279b3bda229af3b28" -} -~~~ -### <a name="DeleteStoppedContainers"></a>func DeleteStoppedContainers -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method DeleteStoppedContainers() [[]string](#[]string)</div> -DeleteStoppedContainers will delete all containers that are not running. It will return a list the deleted -container IDs. See also [RemoveContainer](RemoveContainer). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteStoppedContainers -{ - "containers": [ - "451410b931d00def8aa9b4f8084e4d4a39e5e04ea61f358cf53a5cf95afcdcee", - "8b60f754a3e01389494a9581ade97d35c2765b6e2f19acd2d3040c82a32d1bc0", - "cf2e99d4d3cad6073df199ed32bbe64b124f3e1aba6d78821aa8460e70d30084", - "db901a329587312366e5ecff583d08f0875b4b79294322df67d90fc6eed08fc1" - ] -} -~~~ -### <a name="DeleteUnusedImages"></a>func DeleteUnusedImages -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method DeleteUnusedImages() [[]string](#[]string)</div> -DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned -in a string array. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteUnusedImages -{ - "images": [ - "166ea6588079559c724c15223f52927f514f73dd5c5cf2ae2d143e3b2e6e9b52", - "da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e", - "3ef70f7291f47dfe2b82931a993e16f5a44a0e7a68034c3e0e086d77f5829adc", - "59788edf1f3e78cd0ebe6ce1446e9d10788225db3dedcfd1a59f764bad2b2690" - ] -} -~~~ -### <a name="Diff"></a>func Diff -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Diff(name: [string](https://godoc.org/builtin#string)) [DiffInfo](#DiffInfo)</div> -Diff returns a diff between libpod objects -### <a name="EvictContainer"></a>func EvictContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method EvictContainer(name: [string](https://godoc.org/builtin#string), removeVolumes: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -EvictContainer requires the name or ID of a container as well as a boolean that -indicates to remove builtin volumes. Upon successful eviction of the container, -its ID is returned. If the container cannot be found by name or ID, -a [ContainerNotFound](#ContainerNotFound) error will be returned. -See also [RemoveContainer](RemoveContainer). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.EvictContainer '{"name": "62f4fd98cb57"}' -{ - "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -} -~~~ -### <a name="ExecContainer"></a>func ExecContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ExecContainer(opts: [ExecOpts](#ExecOpts)) </div> -ExecContainer executes a command in the given container. -### <a name="ExportContainer"></a>func ExportContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ExportContainer(name: [string](https://godoc.org/builtin#string), path: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -ExportContainer creates an image from a container. It takes the name or ID of a container and a -path representing the target tarfile. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -error will be returned. -The return value is the written tarfile. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ExportContainer '{"name": "flamboyant_payne", "path": "/tmp/payne.tar" }' -{ - "tarfile": "/tmp/payne.tar" -} -~~~ -### <a name="ExportImage"></a>func ExportImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ExportImage(name: [string](https://godoc.org/builtin#string), destination: [string](https://godoc.org/builtin#string), compress: [bool](https://godoc.org/builtin#bool), tags: [[]string](#[]string)) [string](https://godoc.org/builtin#string)</div> -ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also -a boolean option to force compression. It also takes in a string array of tags to be able to save multiple -tags of the same image to a tarball (each tag should be of the form <image>:<tag>). 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). -### <a name="GenerateKube"></a>func GenerateKube -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GenerateKube(name: [string](https://godoc.org/builtin#string), service: [bool](https://godoc.org/builtin#bool)) [KubePodService](#KubePodService)</div> -GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod -and its containers. The description is in YAML. See also [ReplayKube](ReplayKube). -### <a name="GetAttachSockets"></a>func GetAttachSockets -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetAttachSockets(name: [string](https://godoc.org/builtin#string)) [Sockets](#Sockets)</div> -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.podman/io.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" - } -} -~~~ -### <a name="GetContainer"></a>func GetContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainer(id: [string](https://godoc.org/builtin#string)) [Container](#Container)</div> -GetContainer returns information about a single container. If a container -with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound) -error will be returned. See also [ListContainers](ListContainers) and -[InspectContainer](#InspectContainer). -### <a name="GetContainerLogs"></a>func GetContainerLogs -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainerLogs(name: [string](https://godoc.org/builtin#string)) [[]string](#[]string)</div> -GetContainerLogs takes a name or ID of a container and returns the logs of that container. -If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned. -The container logs are returned as an array of strings. GetContainerLogs will honor the streaming -capability of varlink if the client invokes it. -### <a name="GetContainerStats"></a>func GetContainerStats -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainerStats(name: [string](https://godoc.org/builtin#string)) [ContainerStats](#ContainerStats)</div> -GetContainerStats takes the name or ID of a container and returns a single ContainerStats structure which -contains attributes like memory and cpu usage. If the container cannot be found, a -[ContainerNotFound](#ContainerNotFound) error will be returned. If the container is not running, a [NoContainerRunning](#NoContainerRunning) -error will be returned -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name": "c33e4164f384"}' -{ - "container": { - "block_input": 0, - "block_output": 0, - "cpu": 2.571123918839990154678e-08, - "cpu_nano": 49037378, - "id": "c33e4164f384aa9d979072a63319d66b74fd7a128be71fa68ede24f33ec6cfee", - "mem_limit": 33080606720, - "mem_perc": 2.166828456524753747370e-03, - "mem_usage": 716800, - "name": "competent_wozniak", - "net_input": 768, - "net_output": 5910, - "pids": 1, - "system_nano": 10000000 - } -} -~~~ -### <a name="GetContainerStatsWithHistory"></a>func GetContainerStatsWithHistory -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainerStatsWithHistory(previousStats: [ContainerStats](#ContainerStats)) [ContainerStats](#ContainerStats)</div> -GetContainerStatsWithHistory takes a previous set of container statistics and uses libpod functions -to calculate the containers statistics based on current and previous measurements. -### <a name="GetContainersByContext"></a>func GetContainersByContext -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainersByContext(all: [bool](https://godoc.org/builtin#bool), latest: [bool](https://godoc.org/builtin#bool), args: [[]string](#[]string)) [[]string](#[]string)</div> -GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of -container names. The definition of latest container means the latest by creation date. In a multi- -user environment, results might differ from what you expect. -### <a name="GetContainersByStatus"></a>func GetContainersByStatus -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainersByStatus(status: [[]string](#[]string)) [Container](#Container)</div> - -### <a name="GetContainersLogs"></a>func GetContainersLogs -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetContainersLogs(names: [[]string](#[]string), follow: [bool](https://godoc.org/builtin#bool), latest: [bool](https://godoc.org/builtin#bool), since: [string](https://godoc.org/builtin#string), tail: [int](https://godoc.org/builtin#int), timestamps: [bool](https://godoc.org/builtin#bool)) [LogLine](#LogLine)</div> - -### <a name="GetEvents"></a>func GetEvents -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetEvents(filter: [[]string](#[]string), since: [string](https://godoc.org/builtin#string), until: [string](https://godoc.org/builtin#string)) [Event](#Event)</div> -GetEvents returns known libpod events filtered by the options provided. -### <a name="GetImage"></a>func GetImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetImage(id: [string](https://godoc.org/builtin#string)) [Image](#Image)</div> -GetImage returns information about a single image in storage. -If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned. -### <a name="GetInfo"></a>func GetInfo -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetInfo() [PodmanInfo](#PodmanInfo)</div> -GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats, -build information of Podman, and system-wide registries. -### <a name="GetLayersMapWithImageInfo"></a>func GetLayersMapWithImageInfo -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetLayersMapWithImageInfo() [string](https://godoc.org/builtin#string)</div> -GetLayersMapWithImageInfo is for the development of Podman and should not be used. -### <a name="GetPod"></a>func GetPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetPod(name: [string](https://godoc.org/builtin#string)) [ListPodData](#ListPodData)</div> -GetPod takes a name or ID of a pod and returns single [ListPodData](#ListPodData) -structure. A [PodNotFound](#PodNotFound) error will be returned if the pod cannot be found. -See also [ListPods](ListPods). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.GetPod '{"name": "foobar"}' -{ - "pod": { - "cgroup": "machine.slice", - "containersinfo": [ - { - "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45", - "name": "1840835294cf-infra", - "status": "running" - }, - { - "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6", - "name": "upbeat_murdock", - "status": "running" - } - ], - "createdat": "2018-12-07 13:10:15.014139258 -0600 CST", - "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f", - "name": "foobar", - "numberofcontainers": "2", - "status": "Running" - } -} -~~~ -### <a name="GetPodStats"></a>func GetPodStats -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetPodStats(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string), [ContainerStats](#ContainerStats)</div> -GetPodStats takes the name or ID of a pod and returns a pod name and slice of ContainerStats structure which -contains attributes like memory and cpu usage. If the pod cannot be found, a [PodNotFound](#PodNotFound) -error will be returned. If the pod has no running containers associated with it, a [NoContainerRunning](#NoContainerRunning) -error will be returned. -#### Example -~~~ -$ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b508b6f12b11d8fe02e"}' -{ - "containers": [ - { - "block_input": 0, - "block_output": 0, - "cpu": 2.833470544016107524276e-08, - "cpu_nano": 54363072, - "id": "a64b51f805121fe2c5a3dc5112eb61d6ed139e3d1c99110360d08b58d48e4a93", - "mem_limit": 12276146176, - "mem_perc": 7.974359265237864966003e-03, - "mem_usage": 978944, - "name": "quirky_heisenberg", - "net_input": 866, - "net_output": 7388, - "pids": 1, - "system_nano": 20000000 - } - ], - "pod": "7f62b508b6f12b11d8fe02e0db4de6b9e43a7d7699b33a4fc0d574f6e82b4ebd" -} -~~~ -### <a name="GetPodsByContext"></a>func GetPodsByContext -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetPodsByContext(all: [bool](https://godoc.org/builtin#bool), latest: [bool](https://godoc.org/builtin#bool), args: [[]string](#[]string)) [[]string](#[]string)</div> -GetPodsByContext allows you to get a list pod ids depending on all, latest, or a list of -pod names. The definition of latest pod means the latest by creation date. In a multi- -user environment, results might differ from what you expect. -### <a name="GetPodsByStatus"></a>func GetPodsByStatus -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetPodsByStatus(statuses: [[]string](#[]string)) [[]string](#[]string)</div> -GetPodsByStatus searches for pods whose status is included in statuses -### <a name="GetVersion"></a>func GetVersion -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetVersion() [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [int](https://godoc.org/builtin#int)</div> -GetVersion returns version and build information of the podman service -### <a name="GetVolumes"></a>func GetVolumes -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method GetVolumes(args: [[]string](#[]string), all: [bool](https://godoc.org/builtin#bool)) [Volume](#Volume)</div> -GetVolumes gets slice of the volumes on a remote host -### <a name="HealthCheckRun"></a>func HealthCheckRun -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method HealthCheckRun(nameOrID: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -HealthCheckRun executes defined container's healthcheck command -and returns the container's health status. -### <a name="HistoryImage"></a>func HistoryImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method HistoryImage(name: [string](https://godoc.org/builtin#string)) [ImageHistory](#ImageHistory)</div> -HistoryImage takes the name or ID of an image and returns information about its history and layers. The returned -history is in the form of an array of ImageHistory structures. If the image cannot be found, an -[ImageNotFound](#ImageNotFound) error is returned. -### <a name="ImageExists"></a>func ImageExists -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ImageExists(name: [string](https://godoc.org/builtin#string)) [int](https://godoc.org/builtin#int)</div> -ImageExists talks a full or partial image ID or name and returns an int as to whether -the image exists in local storage. An int result of 0 means the image does exist in -local storage; whereas 1 indicates the image does not exists in local storage. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ImageExists '{"name": "imageddoesntexist"}' -{ - "exists": 1 -} -~~~ -### <a name="ImageSave"></a>func ImageSave -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ImageSave(options: [ImageSaveOptions](#ImageSaveOptions)) [MoreResponse](#MoreResponse)</div> -ImageSave allows you to save an image from the local image storage to a tarball -### <a name="ImageTree"></a>func ImageTree -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ImageTree(name: [string](https://godoc.org/builtin#string), whatRequires: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -ImageTree returns the image tree for the provided image name or ID -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ImageTree '{"name": "alpine"}' -{ - "tree": "Image ID: e7d92cdc71fe\nTags: [docker.io/library/alpine:latest]\nSize: 5.861MB\nImage Layers\n└── ID: 5216338b40a7 Size: 5.857MB Top Layer of: [docker.io/library/alpine:latest]\n" -} -~~~ -### <a name="ImagesPrune"></a>func ImagesPrune -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ImagesPrune(all: [bool](https://godoc.org/builtin#bool), filter: [[]string](#[]string)) [[]string](#[]string)</div> -ImagesPrune removes all unused images from the local store. Upon successful pruning, -the IDs of the removed images are returned. -### <a name="ImportImage"></a>func ImportImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ImportImage(source: [string](https://godoc.org/builtin#string), reference: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), delete: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -ImportImage imports an image from a source (like tarball) into local storage. The image can have additional -descriptions added to it using the message and changes options. See also [ExportImage](ExportImage). -### <a name="InitContainer"></a>func InitContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method InitContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -InitContainer initializes the given container. It accepts a container name or -ID, and will initialize the container matching that ID if possible, and error -if not. Containers can only be initialized when they are in the Created or -Exited states. Initialization prepares a container to be started, but does not -start the container. It is intended to be used to debug a container's state -prior to starting it. -### <a name="InspectContainer"></a>func InspectContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method InspectContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -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) -error will be returned if the container cannot be found. See also [InspectImage](#InspectImage). -### <a name="InspectImage"></a>func InspectImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method InspectImage(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -InspectImage takes the name or ID of an image and returns a string representation of data associated with the -mage. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will -be returned if the image cannot be found. -### <a name="InspectPod"></a>func InspectPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method InspectPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -InspectPod takes the name or ID of an image and returns a string representation of data associated with the -pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will -be returned if the pod cannot be found. -### <a name="InspectVolume"></a>func InspectVolume -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method InspectVolume(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -InspectVolume inspects a single volume. Returns inspect JSON in the form of a -string. -### <a name="KillContainer"></a>func KillContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method KillContainer(name: [string](https://godoc.org/builtin#string), signal: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -KillContainer takes the name or ID of a container as well as a signal to be applied to the container. Once the -container has been killed, the container's ID is returned. If the container cannot be found, a -[ContainerNotFound](#ContainerNotFound) error is returned. See also [StopContainer](StopContainer). -### <a name="KillPod"></a>func KillPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method KillPod(name: [string](https://godoc.org/builtin#string), signal: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -KillPod takes the name or ID of a pod as well as a signal to be applied to the pod. If the pod cannot be found, a -[PodNotFound](#PodNotFound) error is returned. -Containers in a pod are killed independently. If there is an error killing one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was killed with no errors, the pod ID is returned. -See also [StopPod](StopPod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.KillPod '{"name": "foobar", "signal": 15}' -{ - "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -} -~~~ -### <a name="ListContainerChanges"></a>func ListContainerChanges -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListContainerChanges(name: [string](https://godoc.org/builtin#string)) [ContainerChanges](#ContainerChanges)</div> -ListContainerChanges takes a name or ID of a container and returns changes between the container and -its base image. It returns a struct of changed, deleted, and added path names. -### <a name="ListContainerMounts"></a>func ListContainerMounts -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListContainerMounts() [map[string]](#map[string])</div> -ListContainerMounts gathers all the mounted container mount points and returns them as an array -of strings -#### Example -~~~ -$ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts -{ - "mounts": { - "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged", - "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged" - } -} -~~~ -### <a name="ListContainerProcesses"></a>func ListContainerProcesses -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListContainerProcesses(name: [string](https://godoc.org/builtin#string), opts: [[]string](#[]string)) [[]string](#[]string)</div> -ListContainerProcesses takes a name or ID of a container and returns the processes -running inside the container as array of strings. It will accept an array of string -arguments that represent ps options. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -error will be returned. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerProcesses '{"name": "135d71b9495f", "opts": []}' -{ - "container": [ - " UID PID PPID C STIME TTY TIME CMD", - " 0 21220 21210 0 09:05 pts/0 00:00:00 /bin/sh", - " 0 21232 21220 0 09:05 pts/0 00:00:00 top", - " 0 21284 21220 0 09:05 pts/0 00:00:00 vi /etc/hosts" - ] -} -~~~ -### <a name="ListContainers"></a>func ListContainers -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListContainers() [Container](#Container)</div> -ListContainers returns information about all containers. -See also [GetContainer](#GetContainer). -### <a name="ListImages"></a>func ListImages -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListImages() [Image](#Image)</div> -ListImages returns information about the images that are currently in storage. -See also [InspectImage](#InspectImage). -### <a name="ListImagesWithFilters"></a>func ListImagesWithFilters -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListImagesWithFilters(filters: [[]string](#[]string)) [Image](#Image)</div> -ListImagesWithFilters returns information about the images that are currently in storage -after one or more filters has been applied. -See also [InspectImage](#InspectImage). -### <a name="ListPods"></a>func ListPods -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ListPods() [ListPodData](#ListPodData)</div> -ListPods returns a list of pods in no particular order. They are -returned as an array of ListPodData structs. See also [GetPod](#GetPod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.ListPods -{ - "pods": [ - { - "cgroup": "machine.slice", - "containersinfo": [ - { - "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45", - "name": "1840835294cf-infra", - "status": "running" - }, - { - "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6", - "name": "upbeat_murdock", - "status": "running" - } - ], - "createdat": "2018-12-07 13:10:15.014139258 -0600 CST", - "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f", - "name": "foobar", - "numberofcontainers": "2", - "status": "Running" - }, - { - "cgroup": "machine.slice", - "containersinfo": [ - { - "id": "1ca4b7bbba14a75ba00072d4b705c77f3df87db0109afaa44d50cb37c04a477e", - "name": "784306f655c6-infra", - "status": "running" - } - ], - "createdat": "2018-12-07 13:09:57.105112457 -0600 CST", - "id": "784306f655c6200aea321dd430ba685e9b2cc1f7d7528a72f3ff74ffb29485a2", - "name": "nostalgic_pike", - "numberofcontainers": "1", - "status": "Running" - } - ] -} -~~~ -### <a name="LoadImage"></a>func LoadImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method LoadImage(name: [string](https://godoc.org/builtin#string), inputFile: [string](https://godoc.org/builtin#string), quiet: [bool](https://godoc.org/builtin#bool), deleteFile: [bool](https://godoc.org/builtin#bool)) [MoreResponse](#MoreResponse)</div> -LoadImage allows you to load an image into local storage from a tarball. -### <a name="MountContainer"></a>func MountContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method MountContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -MountContainer mounts a container by name or full/partial ID. Upon a successful mount, the destination -mount is returned as a string. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.MountContainer '{"name": "jolly_shannon"}'{ - "path": "/var/lib/containers/storage/overlay/419eeb04e783ea159149ced67d9fcfc15211084d65e894792a96bedfae0470ca/merged" -} -~~~ -### <a name="PauseContainer"></a>func PauseContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method PauseContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -PauseContainer takes the name or ID of container and pauses it. If the container cannot be found, -a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. -See also [UnpauseContainer](#UnpauseContainer). -### <a name="PausePod"></a>func PausePod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method PausePod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -PausePod takes the name or ID of a pod and pauses the running containers associated with it. If the pod cannot be found, -a [PodNotFound](#PodNotFound) error will be returned. -Containers in a pod are paused independently. If there is an error pausing one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was paused with no errors, the pod ID is returned. -See also [UnpausePod](#UnpausePod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.PausePod '{"name": "foobar"}' -{ - "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -} -~~~ -### <a name="PodStateData"></a>func PodStateData -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method PodStateData(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -PodStateData returns inspectr level information of a given pod in string form. This call is for -development of Podman only and generally should not be used. -### <a name="Ps"></a>func Ps -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Ps(opts: [PsOpts](#PsOpts)) [PsContainer](#PsContainer)</div> - -### <a name="PullImage"></a>func PullImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method PullImage(name: [string](https://godoc.org/builtin#string), creds: [AuthConfig](#AuthConfig)) [MoreResponse](#MoreResponse)</div> -PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs -are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send -status as it occurs. -### <a name="PushImage"></a>func PushImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), compress: [bool](https://godoc.org/builtin#bool), format: [string](https://godoc.org/builtin#string), removeSignatures: [bool](https://godoc.org/builtin#bool), signBy: [string](https://godoc.org/builtin#string)) [MoreResponse](#MoreResponse)</div> -PushImage takes two input arguments: the name or ID of an image, the fully-qualified destination name of the image, -It will return an [ImageNotFound](#ImageNotFound) error if -the image cannot be found in local storage; otherwise it will return a [MoreResponse](#MoreResponse) -### <a name="ReceiveFile"></a>func ReceiveFile -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method ReceiveFile(path: [string](https://godoc.org/builtin#string), delete: [bool](https://godoc.org/builtin#bool)) [int](https://godoc.org/builtin#int)</div> -ReceiveFile allows the host to send a remote client a file -### <a name="RemoveContainer"></a>func RemoveContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RemoveContainer(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool), removeVolumes: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -RemoveContainer requires the name or ID of a container as well as a boolean that -indicates whether a container should be forcefully removed (e.g., by stopping it), and a boolean -indicating whether to remove builtin volumes. Upon successful removal of the -container, its ID is returned. If the -container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned. -See also [EvictContainer](EvictContainer). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.RemoveContainer '{"name": "62f4fd98cb57"}' -{ - "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -} -~~~ -### <a name="RemoveImage"></a>func RemoveImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RemoveImage(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -RemoveImage takes the name or ID of an image as well as a boolean that determines if containers using that image -should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The -ID of the removed image is returned when complete. See also [DeleteUnusedImages](DeleteUnusedImages). -#### Example -~~~ -varlink call -m unix:/run/podman/io.podman/io.podman.RemoveImage '{"name": "registry.fedoraproject.org/fedora", "force": true}' -{ - "image": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e" -} -~~~ -### <a name="RemoveImageWithResponse"></a>func RemoveImageWithResponse -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RemoveImageWithResponse(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [RemoveImageResponse](#RemoveImageResponse)</div> -RemoveImageWithResponse takes the name or ID of an image as well as a boolean that determines if containers using that image -should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The response is -in the form of a RemoveImageResponse . -### <a name="RemovePod"></a>func RemovePod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RemovePod(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> -RemovePod takes the name or ID of a pod as well a boolean representing whether a running -container in the pod can be stopped and removed. If a pod has containers associated with it, and force is not true, -an error will occur. -If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. -Containers in a pod are removed independently. If there is an error removing any container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was removed with no errors, the pod ID is returned. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4fd98cb57", "force": "true"}' -{ - "pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -} -~~~ -### <a name="Reset"></a>func Reset -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Reset() </div> -Reset resets Podman back to its initial state. -Removes all Pods, Containers, Images and Volumes -### <a name="RestartContainer"></a>func RestartContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RestartContainer(name: [string](https://godoc.org/builtin#string), timeout: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -RestartContainer will restart a running container given a container name or ID and timeout value. The timeout -value is the time before a forcible stop is used to stop the container. If the container cannot be found by -name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise, the ID of the -container will be returned. -### <a name="RestartPod"></a>func RestartPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method RestartPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -RestartPod will restart containers in a pod given a pod name or ID. Containers in -the pod that are running will be stopped, then all stopped containers will be run. -If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. -Containers in a pod are restarted independently. If there is an error restarting one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was restarted with no errors, the pod ID is returned. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.RestartPod '{"name": "135d71b9495f"}' -{ - "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -} -~~~ -### <a name="SearchImages"></a>func SearchImages -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method SearchImages(query: [string](https://godoc.org/builtin#string), limit: [?int](#?int), filter: [ImageSearchFilter](#ImageSearchFilter)) [ImageSearchResult](#ImageSearchResult)</div> -SearchImages searches available registries for images that contain the -contents of "query" in their name. If "limit" is given, limits the amount of -search results per registry. -### <a name="SendFile"></a>func SendFile -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -Sendfile allows a remote client to send a file to the host -### <a name="Spec"></a>func Spec -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Spec(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -Spec returns the oci spec for a container. This call is for development of Podman only and generally should not be used. -### <a name="StartContainer"></a>func StartContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method StartContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -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). -### <a name="StartPod"></a>func StartPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method StartPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -StartPod starts containers in a pod. It takes the name or ID of pod. If the pod cannot be found, a [PodNotFound](#PodNotFound) -error will be returned. Containers in a pod are started independently. If there is an error starting one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was started with no errors, the pod ID is returned. -See also [CreatePod](#CreatePod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.StartPod '{"name": "135d71b9495f"}' -{ - "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6", -} -~~~ -### <a name="StopContainer"></a>func StopContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method StopContainer(name: [string](https://godoc.org/builtin#string), timeout: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -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 forcible stop to the container is applied. It -returns the container ID once stopped. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -error will be returned instead. See also [KillContainer](KillContainer). -#### Error -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.StopContainer '{"name": "135d71b9495f", "timeout": 5}' -{ - "container": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -} -~~~ -### <a name="StopPod"></a>func StopPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method StopPod(name: [string](https://godoc.org/builtin#string), timeout: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> -StopPod stops containers in a pod. It takes the name or ID of a pod and a timeout. -If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead. -Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was stopped with no errors, the pod ID is returned. -See also [KillPod](KillPod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71b9495f"}' -{ - "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -} -~~~ -### <a name="TagImage"></a>func TagImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method TagImage(name: [string](https://godoc.org/builtin#string), tagged: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot -be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success. -### <a name="Top"></a>func Top -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method Top(nameOrID: [string](https://godoc.org/builtin#string), descriptors: [[]string](#[]string)) [[]string](#[]string)</div> - -### <a name="TopPod"></a>func TopPod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method TopPod(pod: [string](https://godoc.org/builtin#string), latest: [bool](https://godoc.org/builtin#bool), descriptors: [[]string](#[]string)) [[]string](#[]string)</div> - -### <a name="UnmountContainer"></a>func UnmountContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method UnmountContainer(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) </div> -UnmountContainer umounts a container by its name or full/partial container ID. -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.UnmountContainer '{"name": "jolly_shannon", "force": false}' -{} -~~~ -### <a name="UnpauseContainer"></a>func UnpauseContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method UnpauseContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -UnpauseContainer takes the name or ID of container and unpauses a paused container. If the container cannot be -found, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. -See also [PauseContainer](#PauseContainer). -### <a name="UnpausePod"></a>func UnpausePod -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method UnpausePod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -UnpausePod takes the name or ID of a pod and unpauses the paused containers associated with it. If the pod cannot be -found, a [PodNotFound](#PodNotFound) error will be returned. -Containers in a pod are unpaused independently. If there is an error unpausing one container, the ID of those containers -will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -If the pod was unpaused with no errors, the pod ID is returned. -See also [PausePod](#PausePod). -#### Example -~~~ -$ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foobar"}' -{ - "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -} -~~~ -### <a name="UntagImage"></a>func UntagImage -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method UntagImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> -UntagImage takes the name or ID of an image in local storage as well as the -tag name to be removed. If the image cannot be found, an -[ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of -the image is returned on success. -### <a name="VolumeCreate"></a>func VolumeCreate -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method VolumeCreate(options: [VolumeCreateOpts](#VolumeCreateOpts)) [string](https://godoc.org/builtin#string)</div> -VolumeCreate creates a volume on a remote host -### <a name="VolumeRemove"></a>func VolumeRemove -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method VolumeRemove(options: [VolumeRemoveOpts](#VolumeRemoveOpts)) [[]string](#[]string), [map[string]](#map[string])</div> -VolumeRemove removes a volume on a remote host -### <a name="VolumesPrune"></a>func VolumesPrune -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method VolumesPrune() [[]string](#[]string), [[]string](#[]string)</div> -VolumesPrune removes unused volumes on the host -### <a name="WaitContainer"></a>func WaitContainer -<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> - -method WaitContainer(name: [string](https://godoc.org/builtin#string), interval: [int](https://godoc.org/builtin#int)) [int](https://godoc.org/builtin#int)</div> -WaitContainer takes the name or ID of a container and waits the given interval in milliseconds 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 -### <a name="AuthConfig"></a>type AuthConfig - - - -username [string](https://godoc.org/builtin#string) - -password [string](https://godoc.org/builtin#string) -### <a name="BuildInfo"></a>type BuildInfo - -BuildInfo is used to describe user input for building images - -architecture [string](https://godoc.org/builtin#string) - -addCapabilities [[]string](#[]string) - -additionalTags [[]string](#[]string) - -annotations [[]string](#[]string) - -buildArgs [map[string]](#map[string]) - -buildOptions [BuildOptions](#BuildOptions) - -cniConfigDir [string](https://godoc.org/builtin#string) - -cniPluginDir [string](https://godoc.org/builtin#string) - -compression [string](https://godoc.org/builtin#string) - -contextDir [string](https://godoc.org/builtin#string) - -defaultsMountFilePath [string](https://godoc.org/builtin#string) - -devices [[]string](#[]string) - -dockerfiles [[]string](#[]string) - -dropCapabilities [[]string](#[]string) - -err [string](https://godoc.org/builtin#string) - -forceRmIntermediateCtrs [bool](https://godoc.org/builtin#bool) - -iidfile [string](https://godoc.org/builtin#string) - -label [[]string](#[]string) - -layers [bool](https://godoc.org/builtin#bool) - -nocache [bool](https://godoc.org/builtin#bool) - -os [string](https://godoc.org/builtin#string) - -out [string](https://godoc.org/builtin#string) - -output [string](https://godoc.org/builtin#string) - -outputFormat [string](https://godoc.org/builtin#string) - -pullPolicy [string](https://godoc.org/builtin#string) - -quiet [bool](https://godoc.org/builtin#bool) - -remoteIntermediateCtrs [bool](https://godoc.org/builtin#bool) - -reportWriter [string](https://godoc.org/builtin#string) - -runtimeArgs [[]string](#[]string) - -signBy [string](https://godoc.org/builtin#string) - -squash [bool](https://godoc.org/builtin#bool) - -target [string](https://godoc.org/builtin#string) - -transientMounts [[]string](#[]string) -### <a name="BuildOptions"></a>type BuildOptions - -BuildOptions are are used to describe describe physical attributes of the build - -addHosts [[]string](#[]string) - -cgroupParent [string](https://godoc.org/builtin#string) - -cpuPeriod [int](https://godoc.org/builtin#int) - -cpuQuota [int](https://godoc.org/builtin#int) - -cpuShares [int](https://godoc.org/builtin#int) - -cpusetCpus [string](https://godoc.org/builtin#string) - -cpusetMems [string](https://godoc.org/builtin#string) - -memory [int](https://godoc.org/builtin#int) - -memorySwap [int](https://godoc.org/builtin#int) - -shmSize [string](https://godoc.org/builtin#string) - -ulimit [[]string](#[]string) - -volume [[]string](#[]string) -### <a name="Container"></a>type Container - - - -id [string](https://godoc.org/builtin#string) - -image [string](https://godoc.org/builtin#string) - -imageid [string](https://godoc.org/builtin#string) - -command [[]string](#[]string) - -createdat [string](https://godoc.org/builtin#string) - -runningfor [string](https://godoc.org/builtin#string) - -status [string](https://godoc.org/builtin#string) - -ports [ContainerPortMappings](#ContainerPortMappings) - -rootfssize [int](https://godoc.org/builtin#int) - -rwsize [int](https://godoc.org/builtin#int) - -names [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -mounts [ContainerMount](#ContainerMount) - -containerrunning [bool](https://godoc.org/builtin#bool) - -namespaces [ContainerNameSpace](#ContainerNameSpace) -### <a name="ContainerChanges"></a>type ContainerChanges - -ContainerChanges describes the return struct for ListContainerChanges - -changed [[]string](#[]string) - -added [[]string](#[]string) - -deleted [[]string](#[]string) -### <a name="ContainerMount"></a>type ContainerMount - -ContainerMount describes the struct for mounts in a container - -destination [string](https://godoc.org/builtin#string) - -type [string](https://godoc.org/builtin#string) - -source [string](https://godoc.org/builtin#string) - -options [[]string](#[]string) -### <a name="ContainerNameSpace"></a>type ContainerNameSpace - -ContainerNamespace describes the namespace structure for an existing container - -user [string](https://godoc.org/builtin#string) - -uts [string](https://godoc.org/builtin#string) - -pidns [string](https://godoc.org/builtin#string) - -pid [string](https://godoc.org/builtin#string) - -cgroup [string](https://godoc.org/builtin#string) - -net [string](https://godoc.org/builtin#string) - -mnt [string](https://godoc.org/builtin#string) - -ipc [string](https://godoc.org/builtin#string) -### <a name="ContainerPortMappings"></a>type ContainerPortMappings - -ContainerPortMappings describes the struct for portmappings in an existing container - -host_port [string](https://godoc.org/builtin#string) - -host_ip [string](https://godoc.org/builtin#string) - -protocol [string](https://godoc.org/builtin#string) - -container_port [string](https://godoc.org/builtin#string) -### <a name="ContainerStats"></a>type ContainerStats - -ContainerStats is the return struct for the stats of a container - -id [string](https://godoc.org/builtin#string) - -name [string](https://godoc.org/builtin#string) - -cpu [float](https://golang.org/src/builtin/builtin.go#L58) - -cpu_nano [int](https://godoc.org/builtin#int) - -system_nano [int](https://godoc.org/builtin#int) - -mem_usage [int](https://godoc.org/builtin#int) - -mem_limit [int](https://godoc.org/builtin#int) - -mem_perc [float](https://golang.org/src/builtin/builtin.go#L58) - -net_input [int](https://godoc.org/builtin#int) - -net_output [int](https://godoc.org/builtin#int) - -block_output [int](https://godoc.org/builtin#int) - -block_input [int](https://godoc.org/builtin#int) - -pids [int](https://godoc.org/builtin#int) -### <a name="Create"></a>type Create - -Create is an input structure for creating containers. -args[0] is the image name or id -args[1-] are the new commands if changed - -args [[]string](#[]string) - -addHost [?[]string](#?[]string) - -annotation [?[]string](#?[]string) - -attach [?[]string](#?[]string) - -blkioWeight [?string](#?string) - -blkioWeightDevice [?[]string](#?[]string) - -capAdd [?[]string](#?[]string) - -capDrop [?[]string](#?[]string) - -cgroupParent [?string](#?string) - -cidFile [?string](#?string) - -conmonPidfile [?string](#?string) - -command [?[]string](#?[]string) - -cpuPeriod [?int](#?int) - -cpuQuota [?int](#?int) - -cpuRtPeriod [?int](#?int) - -cpuRtRuntime [?int](#?int) - -cpuShares [?int](#?int) - -cpus [?float](#?float) - -cpuSetCpus [?string](#?string) - -cpuSetMems [?string](#?string) - -detach [?bool](#?bool) - -detachKeys [?string](#?string) - -device [?[]string](#?[]string) - -deviceReadBps [?[]string](#?[]string) - -deviceReadIops [?[]string](#?[]string) - -deviceWriteBps [?[]string](#?[]string) - -deviceWriteIops [?[]string](#?[]string) - -dns [?[]string](#?[]string) - -dnsOpt [?[]string](#?[]string) - -dnsSearch [?[]string](#?[]string) - -dnsServers [?[]string](#?[]string) - -entrypoint [?string](#?string) - -env [?[]string](#?[]string) - -envFile [?[]string](#?[]string) - -expose [?[]string](#?[]string) - -gidmap [?[]string](#?[]string) - -groupadd [?[]string](#?[]string) - -healthcheckCommand [?string](#?string) - -healthcheckInterval [?string](#?string) - -healthcheckRetries [?int](#?int) - -healthcheckStartPeriod [?string](#?string) - -healthcheckTimeout [?string](#?string) - -hostname [?string](#?string) - -imageVolume [?string](#?string) - -init [?bool](#?bool) - -initPath [?string](#?string) - -interactive [?bool](#?bool) - -ip [?string](#?string) - -ipc [?string](#?string) - -kernelMemory [?string](#?string) - -label [?[]string](#?[]string) - -labelFile [?[]string](#?[]string) - -logDriver [?string](#?string) - -logOpt [?[]string](#?[]string) - -macAddress [?string](#?string) - -memory [?string](#?string) - -memoryReservation [?string](#?string) - -memorySwap [?string](#?string) - -memorySwappiness [?int](#?int) - -name [?string](#?string) - -network [?string](#?string) - -noHosts [?bool](#?bool) - -oomKillDisable [?bool](#?bool) - -oomScoreAdj [?int](#?int) - -overrideArch [?string](#?string) - -overrideOS [?string](#?string) - -pid [?string](#?string) - -pidsLimit [?int](#?int) - -pod [?string](#?string) - -privileged [?bool](#?bool) - -publish [?[]string](#?[]string) - -publishAll [?bool](#?bool) - -pull [?string](#?string) - -quiet [?bool](#?bool) - -readonly [?bool](#?bool) - -readonlytmpfs [?bool](#?bool) - -restart [?string](#?string) - -rm [?bool](#?bool) - -rootfs [?bool](#?bool) - -securityOpt [?[]string](#?[]string) - -shmSize [?string](#?string) - -stopSignal [?string](#?string) - -stopTimeout [?int](#?int) - -storageOpt [?[]string](#?[]string) - -subuidname [?string](#?string) - -subgidname [?string](#?string) - -sysctl [?[]string](#?[]string) - -systemd [?string](#?string) - -tmpfs [?[]string](#?[]string) - -tty [?bool](#?bool) - -uidmap [?[]string](#?[]string) - -ulimit [?[]string](#?[]string) - -user [?string](#?string) - -userns [?string](#?string) - -uts [?string](#?string) - -mount [?[]string](#?[]string) - -volume [?[]string](#?[]string) - -volumesFrom [?[]string](#?[]string) - -workDir [?string](#?string) -### <a name="DiffInfo"></a>type DiffInfo - - - -path [string](https://godoc.org/builtin#string) - -changeType [string](https://godoc.org/builtin#string) -### <a name="Event"></a>type Event - -Event describes a libpod struct - -id [string](https://godoc.org/builtin#string) - -image [string](https://godoc.org/builtin#string) - -name [string](https://godoc.org/builtin#string) - -status [string](https://godoc.org/builtin#string) - -time [string](https://godoc.org/builtin#string) - -type [string](https://godoc.org/builtin#string) -### <a name="ExecOpts"></a>type ExecOpts - - - -name [string](https://godoc.org/builtin#string) - -tty [bool](https://godoc.org/builtin#bool) - -privileged [bool](https://godoc.org/builtin#bool) - -cmd [[]string](#[]string) - -user [?string](#?string) - -workdir [?string](#?string) - -env [?[]string](#?[]string) - -detachKeys [?string](#?string) -### <a name="Image"></a>type Image - - - -id [string](https://godoc.org/builtin#string) - -digest [string](https://godoc.org/builtin#string) - -digests [[]string](#[]string) - -parentId [string](https://godoc.org/builtin#string) - -repoTags [[]string](#[]string) - -repoDigests [[]string](#[]string) - -created [string](https://godoc.org/builtin#string) - -size [int](https://godoc.org/builtin#int) - -virtualSize [int](https://godoc.org/builtin#int) - -containers [int](https://godoc.org/builtin#int) - -labels [map[string]](#map[string]) - -isParent [bool](https://godoc.org/builtin#bool) - -topLayer [string](https://godoc.org/builtin#string) - -readOnly [bool](https://godoc.org/builtin#bool) - -history [[]string](#[]string) -### <a name="ImageHistory"></a>type ImageHistory - -ImageHistory describes the returned structure from ImageHistory. - -id [string](https://godoc.org/builtin#string) - -created [string](https://godoc.org/builtin#string) - -createdBy [string](https://godoc.org/builtin#string) - -tags [[]string](#[]string) - -size [int](https://godoc.org/builtin#int) - -comment [string](https://godoc.org/builtin#string) -### <a name="ImageSaveOptions"></a>type ImageSaveOptions - - - -name [string](https://godoc.org/builtin#string) - -format [string](https://godoc.org/builtin#string) - -output [string](https://godoc.org/builtin#string) - -outputType [string](https://godoc.org/builtin#string) - -moreTags [[]string](#[]string) - -quiet [bool](https://godoc.org/builtin#bool) - -compress [bool](https://godoc.org/builtin#bool) -### <a name="ImageSearchFilter"></a>type ImageSearchFilter - - - -is_official [?bool](#?bool) - -is_automated [?bool](#?bool) - -star_count [int](https://godoc.org/builtin#int) -### <a name="ImageSearchResult"></a>type ImageSearchResult - -Represents a single search result from SearchImages - -description [string](https://godoc.org/builtin#string) - -is_official [bool](https://godoc.org/builtin#bool) - -is_automated [bool](https://godoc.org/builtin#bool) - -registry [string](https://godoc.org/builtin#string) - -name [string](https://godoc.org/builtin#string) - -star_count [int](https://godoc.org/builtin#int) -### <a name="InfoDistribution"></a>type InfoDistribution - -InfoDistribution describes the host's distribution - -distribution [string](https://godoc.org/builtin#string) - -version [string](https://godoc.org/builtin#string) -### <a name="InfoGraphStatus"></a>type InfoGraphStatus - -InfoGraphStatus describes the detailed status of the storage driver - -backing_filesystem [string](https://godoc.org/builtin#string) - -native_overlay_diff [string](https://godoc.org/builtin#string) - -supports_d_type [string](https://godoc.org/builtin#string) -### <a name="InfoHost"></a>type InfoHost - -InfoHost describes the host stats portion of PodmanInfo - -buildah_version [string](https://godoc.org/builtin#string) - -distribution [InfoDistribution](#InfoDistribution) - -mem_free [int](https://godoc.org/builtin#int) - -mem_total [int](https://godoc.org/builtin#int) - -swap_free [int](https://godoc.org/builtin#int) - -swap_total [int](https://godoc.org/builtin#int) - -arch [string](https://godoc.org/builtin#string) - -cpus [int](https://godoc.org/builtin#int) - -hostname [string](https://godoc.org/builtin#string) - -kernel [string](https://godoc.org/builtin#string) - -os [string](https://godoc.org/builtin#string) - -uptime [string](https://godoc.org/builtin#string) - -eventlogger [string](https://godoc.org/builtin#string) -### <a name="InfoPodmanBinary"></a>type InfoPodmanBinary - -InfoPodman provides details on the Podman binary - -compiler [string](https://godoc.org/builtin#string) - -go_version [string](https://godoc.org/builtin#string) - -podman_version [string](https://godoc.org/builtin#string) - -git_commit [string](https://godoc.org/builtin#string) -### <a name="InfoRegistry"></a>type InfoRegistry - -InfoRegistry describes the host's registry information - -search [[]string](#[]string) - -insecure [[]string](#[]string) - -blocked [[]string](#[]string) -### <a name="InfoStore"></a>type InfoStore - -InfoStore describes the host's storage information - -containers [int](https://godoc.org/builtin#int) - -images [int](https://godoc.org/builtin#int) - -graph_driver_name [string](https://godoc.org/builtin#string) - -graph_driver_options [string](https://godoc.org/builtin#string) - -graph_root [string](https://godoc.org/builtin#string) - -graph_status [InfoGraphStatus](#InfoGraphStatus) - -run_root [string](https://godoc.org/builtin#string) -### <a name="KubePodService"></a>type KubePodService - - - -pod [string](https://godoc.org/builtin#string) - -service [string](https://godoc.org/builtin#string) -### <a name="ListPodContainerInfo"></a>type ListPodContainerInfo - -ListPodContainerInfo is a returned struct for describing containers -in a pod. - -name [string](https://godoc.org/builtin#string) - -id [string](https://godoc.org/builtin#string) - -status [string](https://godoc.org/builtin#string) -### <a name="ListPodData"></a>type ListPodData - -ListPodData is the returned struct for an individual pod - -id [string](https://godoc.org/builtin#string) - -name [string](https://godoc.org/builtin#string) - -createdat [string](https://godoc.org/builtin#string) - -cgroup [string](https://godoc.org/builtin#string) - -status [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -numberofcontainers [string](https://godoc.org/builtin#string) - -containersinfo [ListPodContainerInfo](#ListPodContainerInfo) -### <a name="LogLine"></a>type LogLine - - - -device [string](https://godoc.org/builtin#string) - -parseLogType [string](https://godoc.org/builtin#string) - -time [string](https://godoc.org/builtin#string) - -msg [string](https://godoc.org/builtin#string) - -cid [string](https://godoc.org/builtin#string) -### <a name="MoreResponse"></a>type MoreResponse - -MoreResponse is a struct for when responses from varlink requires longer output - -logs [[]string](#[]string) - -id [string](https://godoc.org/builtin#string) -### <a name="NotImplemented"></a>type NotImplemented - - - -comment [string](https://godoc.org/builtin#string) -### <a name="PodContainerErrorData"></a>type PodContainerErrorData - - - -containerid [string](https://godoc.org/builtin#string) - -reason [string](https://godoc.org/builtin#string) -### <a name="PodCreate"></a>type PodCreate - -PodCreate is an input structure for creating pods. -It emulates options to podman pod create. The infraCommand and -infraImage options are currently NotSupported. - -name [string](https://godoc.org/builtin#string) - -cgroupParent [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -share [[]string](#[]string) - -infra [bool](https://godoc.org/builtin#bool) - -infraCommand [string](https://godoc.org/builtin#string) - -infraImage [string](https://godoc.org/builtin#string) - -publish [[]string](#[]string) -### <a name="PodmanInfo"></a>type PodmanInfo - -PodmanInfo describes the Podman host and build - -host [InfoHost](#InfoHost) - -registries [InfoRegistry](#InfoRegistry) - -store [InfoStore](#InfoStore) - -podman [InfoPodmanBinary](#InfoPodmanBinary) -### <a name="PsContainer"></a>type PsContainer - - - -id [string](https://godoc.org/builtin#string) - -image [string](https://godoc.org/builtin#string) - -command [string](https://godoc.org/builtin#string) - -created [string](https://godoc.org/builtin#string) - -ports [string](https://godoc.org/builtin#string) - -names [string](https://godoc.org/builtin#string) - -isInfra [bool](https://godoc.org/builtin#bool) - -status [string](https://godoc.org/builtin#string) - -state [string](https://godoc.org/builtin#string) - -pidNum [int](https://godoc.org/builtin#int) - -rootFsSize [int](https://godoc.org/builtin#int) - -rwSize [int](https://godoc.org/builtin#int) - -pod [string](https://godoc.org/builtin#string) - -createdAt [string](https://godoc.org/builtin#string) - -exitedAt [string](https://godoc.org/builtin#string) - -startedAt [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -nsPid [string](https://godoc.org/builtin#string) - -cgroup [string](https://godoc.org/builtin#string) - -ipc [string](https://godoc.org/builtin#string) - -mnt [string](https://godoc.org/builtin#string) - -net [string](https://godoc.org/builtin#string) - -pidNs [string](https://godoc.org/builtin#string) - -user [string](https://godoc.org/builtin#string) - -uts [string](https://godoc.org/builtin#string) - -mounts [string](https://godoc.org/builtin#string) -### <a name="PsOpts"></a>type PsOpts - - - -all [bool](https://godoc.org/builtin#bool) - -filters [?[]string](#?[]string) - -last [?int](#?int) - -latest [?bool](#?bool) - -noTrunc [?bool](#?bool) - -pod [?bool](#?bool) - -quiet [?bool](#?bool) - -size [?bool](#?bool) - -sort [?string](#?string) - -sync [?bool](#?bool) -### <a name="RemoveImageResponse"></a>type RemoveImageResponse - - - -untagged [[]string](#[]string) - -deleted [string](https://godoc.org/builtin#string) -### <a name="Runlabel"></a>type Runlabel - -Runlabel describes the required input for container runlabel - -image [string](https://godoc.org/builtin#string) - -authfile [string](https://godoc.org/builtin#string) - -display [bool](https://godoc.org/builtin#bool) - -name [string](https://godoc.org/builtin#string) - -pull [bool](https://godoc.org/builtin#bool) - -label [string](https://godoc.org/builtin#string) - -extraArgs [[]string](#[]string) - -opts [map[string]](#map[string]) -### <a name="Sockets"></a>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) -### <a name="StringResponse"></a>type StringResponse - - - -message [string](https://godoc.org/builtin#string) -### <a name="Volume"></a>type Volume - - - -name [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -mountPoint [string](https://godoc.org/builtin#string) - -driver [string](https://godoc.org/builtin#string) - -options [map[string]](#map[string]) -### <a name="VolumeCreateOpts"></a>type VolumeCreateOpts - - - -volumeName [string](https://godoc.org/builtin#string) - -driver [string](https://godoc.org/builtin#string) - -labels [map[string]](#map[string]) - -options [map[string]](#map[string]) -### <a name="VolumeRemoveOpts"></a>type VolumeRemoveOpts - - - -volumes [[]string](#[]string) - -all [bool](https://godoc.org/builtin#bool) - -force [bool](https://godoc.org/builtin#bool) -## Errors -### <a name="ContainerNotFound"></a>type ContainerNotFound - -ContainerNotFound means the container could not be found by the provided name or ID in local storage. -### <a name="ErrCtrStopped"></a>type ErrCtrStopped - -Container is already stopped -### <a name="ErrRequiresCgroupsV2ForRootless"></a>type ErrRequiresCgroupsV2ForRootless - -This function requires CGroupsV2 to run in rootless mode. -### <a name="ErrorOccurred"></a>type ErrorOccurred - -ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message -is includes as part of the error's text. -### <a name="ImageNotFound"></a>type ImageNotFound - -ImageNotFound means the image could not be found by the provided name or ID in local storage. -### <a name="InvalidState"></a>type InvalidState - -InvalidState indicates that a container or pod was in an improper state for the requested operation -### <a name="NoContainerRunning"></a>type NoContainerRunning - -NoContainerRunning means none of the containers requested are running in a command that requires a running container. -### <a name="NoContainersInPod"></a>type NoContainersInPod - -NoContainersInPod means a pod has no containers on which to perform the operation. It contains -the pod ID. -### <a name="PodContainerError"></a>type PodContainerError - -PodContainerError means a container associated with a pod failed to perform an operation. It contains -a container ID of the container that failed. -### <a name="PodNotFound"></a>type PodNotFound - -PodNotFound means the pod could not be found by the provided name or ID in local storage. -### <a name="RuntimeError"></a>type RuntimeError - -RuntimeErrors generally means a runtime could not be found or gotten. -### <a name="VolumeNotFound"></a>type VolumeNotFound - -VolumeNotFound means the volume could not be found by the name or ID in local storage. -### <a name="WantsMoreRequired"></a>type WantsMoreRequired - -The Podman endpoint requires that you use a streaming connection. @@ -40,9 +40,6 @@ SOURCES = $(shell find . -path './.*' -prune -o -name "*.go") BUILDFLAGS := -mod=vendor $(BUILDFLAGS) BUILDTAGS_CROSS ?= containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay -ifneq (,$(findstring varlink,$(BUILDTAGS))) - PODMAN_VARLINK_DEPENDENCIES = pkg/varlink/iopodman.go -endif CONTAINER_RUNTIME := $(shell command -v podman 2> /dev/null || echo docker) OCI_RUNTIME ?= "" @@ -149,10 +146,6 @@ ifeq ("$(wildcard $(GOPKGDIR))","") mkdir -p "$(GOPKGBASEDIR)" ln -sfn "$(CURDIR)" "$(GOPKGDIR)" endif - -ifneq (,$(findstring varlink,$(BUILDTAGS))) - ln -sfn "$(CURDIR)/vendor/github.com/varlink" "$(FIRST_GOPATH)/src/github.com/varlink" -endif touch $@ .PHONY: lint @@ -165,7 +158,7 @@ endif $(PRE_COMMIT) run -a .PHONY: golangci-lint -golangci-lint: .gopathok varlink_generate .install.golangci-lint +golangci-lint: .gopathok .install.golangci-lint hack/golangci-lint.sh run .PHONY: gofmt @@ -189,7 +182,7 @@ test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go) .PHONY: bin/podman -bin/podman: .gopathok $(SOURCES) go.mod go.sum $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman +bin/podman: .gopathok $(SOURCES) go.mod go.sum ## Build with podman # Make sure to warn in case we're building without the systemd buildtag. ifeq (,$(findstring systemd,$(BUILDTAGS))) @echo "Podman is being compiled without the systemd build tag. Install libsystemd on \ @@ -201,7 +194,7 @@ endif podman: bin/podman .PHONY: bin/podman-remote -bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote environment +bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum ## Build with podman on remote environment $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o $@ ./cmd/podman .PHONY: bin/podman-remote-static @@ -218,7 +211,7 @@ podman.msi: podman-remote podman-remote-windows install-podman-remote-windows-do |wixl-heat --var var.ManSourceDir --component-group ManFiles --directory-ref INSTALLDIR --prefix $(DOCFILE)/ >$(DOCFILE)/pages.wsx wixl -D VERSION=$(RELEASE_NUMBER) -D ManSourceDir=$(DOCFILE) -o podman-v$(RELEASE_NUMBER).msi contrib/msi/podman.wxs $(DOCFILE)/pages.wsx -podman-remote-%: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build podman for a specific GOOS +podman-remote-%: .gopathok ## Build podman for a specific GOOS $(eval BINSFX := $(shell test "$*" != "windows" || echo ".exe")) CGO_ENABLED=0 GOOS=$* $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o bin/$@$(BINSFX) ./cmd/podman @@ -267,7 +260,6 @@ clean: ## Clean artifacts test/checkseccomp/checkseccomp \ test/goecho/goecho \ test/testdata/redis-image \ - pkg/varlink/iopodman.go \ libpod/container_ffjson.go \ libpod/pod_ffjson.go \ libpod/container_easyjson.go \ @@ -276,13 +268,13 @@ clean: ## Clean artifacts make -C docs clean .PHONY: localunit -localunit: test/goecho/goecho varlink_generate +localunit: test/goecho/goecho hack/check_root.sh make localunit rm -rf ${COVERAGE_PATH} && mkdir -p ${COVERAGE_PATH} $(GOBIN)/ginkgo \ -r \ $(TESTFLAGS) \ - --skipPackage test/e2e,pkg/apparmor,test/endpoint,pkg/bindings,hack \ + --skipPackage test/e2e,pkg/apparmor,pkg/bindings,hack \ --cover \ --covermode atomic \ --coverprofile coverprofile \ @@ -304,18 +296,11 @@ ginkgo: ginkgo-remote: $(GOBIN)/ginkgo -v $(TESTFLAGS) -tags "$(REMOTETAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. -.PHONY: endpoint -ifneq (,$(findstring varlink,$(BUILDTAGS))) -endpoint: - $(GOBIN)/ginkgo -v $(TESTFLAGS) -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -debug test/endpoint/. -endpoint: -endif - .PHONY: localintegration -localintegration: varlink_generate test-binaries ginkgo +localintegration: test-binaries ginkgo .PHONY: remoteintegration -remoteintegration: varlink_generate test-binaries ginkgo-remote +remoteintegration: test-binaries ginkgo-remote .PHONY: localsystem localsystem: @@ -370,7 +355,7 @@ system.test-binary: .install.ginkgo $(GO) test -c ./test/system .PHONY: binaries -binaries: varlink_generate podman podman-remote ## Build podman +binaries: podman podman-remote ## Build podman .PHONY: install.catatonit install.catatonit: @@ -534,23 +519,8 @@ install.docker: docker-docs install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} ${DESTDIR}${TMPFILESDIR} install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-docker.conf -t ${DESTDIR}${TMPFILESDIR} -.PHONY: install.varlink -ifneq (,$(findstring varlink,$(BUILDTAGS))) -install.varlink: - install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} - install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.socket ${DESTDIR}${SYSTEMDDIR}/io.podman.socket - install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.socket ${DESTDIR}${USERSYSTEMDDIR}/io.podman.socket - install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.service ${DESTDIR}${SYSTEMDDIR}/io.podman.service - # User units are ordered differently, we can't make the *system* multi-user.target depend on a user unit. - # For user units the default.target that's the default is fine. - sed -e 's,^WantedBy=.*,WantedBy=default.target,' < contrib/varlink/io.podman.service > ${DESTDIR}${USERSYSTEMDDIR}/io.podman.service -else -install.varlink: -endif - - .PHONY: install.systemd -install.systemd: install.varlink +install.systemd: install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} # User services install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.service ${DESTDIR}${USERSYSTEMDDIR}/podman-auto-update.service @@ -631,20 +601,6 @@ endef fi # $BUILD_TAGS variable is used in hack/golangci-lint.sh -.PHONY: varlink_generate -ifneq (or $(findstring varlink,$(BUILDTAGS)),$(findstring varlink,$(BUILD_TAGS))) -varlink_generate: .gopathok pkg/varlink/iopodman.go ## Generate varlink -else -varlink_generate: -endif - -.PHONY: varlink_api_generate -ifneq (,$(findstring varlink,$(BUILDTAGS))) -varlink_api_generate: .gopathok API.md -else -varlink_api_generate: -endif - .PHONY: install.libseccomp.sudo install.libseccomp.sudo: rm -rf ../../seccomp/libseccomp @@ -652,15 +608,6 @@ install.libseccomp.sudo: cd ../../seccomp/libseccomp && git checkout --detach $(LIBSECCOMP_COMMIT) && ./autogen.sh && ./configure --prefix=/usr && make all && make install -pkg/varlink/iopodman.go: .gopathok pkg/varlink/io.podman.varlink -ifneq (,$(findstring Linux,$(shell uname -s))) - # Only generate the varlink code on Linux (see issue #4814). - $(GO) generate ./pkg/varlink/... -endif - -API.md: pkg/varlink/io.podman.varlink - $(GO) generate ./docs/... - .PHONY: validate.completions validate.completions: SHELL:=/usr/bin/env bash # Set shell to bash for this target validate.completions: @@ -5,7 +5,7 @@ Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers. Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes. -* [Latest Version: 2.1.1](https://github.com/containers/podman/releases/latest) +* [Latest Version: 2.2.0](https://github.com/containers/podman/releases/latest) * Latest Remote client for Windows * Latest Remote client for MacOs * Latest Static Remote client for Linux @@ -176,10 +176,10 @@ you to manage and maintain those images and containers in a production environme familiar container cli commands. For more details, see the [Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools). -## Podman Legacy API (Varlink) -Podman offers a [Varlink-based API](https://github.com/containers/podman/blob/master/docs/tutorials/varlink_remote_client.md) -for remote management of containers. However, this API has been deprecated by the REST API. -Varlink support is in maintenance mode, and will be removed in a future release. +## Podman Former API (Varlink) +Podman formerly offered a [Varlink-based API](https://github.com/containers/podman/blob/master/docs/tutorials/varlink_remote_client.md) +for remote management of containers. However, this API was replaced by the REST API. +Varlink support has been removed as of the 3.0 release. For more details, you can see [this blog](https://podman.io/blogs/2020/01/17/podman-new-api.html). ## Static Binary Builds diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 6dc43dbc6..41611d1aa 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -211,12 +211,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup mounts = append(mounts, mount) } - // volumes - volumes := make([]string, 0, len(cc.Config.Volumes)) - for v := range cc.Config.Volumes { - volumes = append(volumes, v) - } - // dns dns := make([]net.IP, 0, len(cc.HostConfig.DNS)) for _, d := range cc.HostConfig.DNS { @@ -373,7 +367,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup UserNS: string(cc.HostConfig.UsernsMode), UTS: string(cc.HostConfig.UTSMode), Mount: mounts, - Volume: volumes, VolumesFrom: cc.HostConfig.VolumesFrom, Workdir: cc.Config.WorkingDir, Net: &netInfo, @@ -388,6 +381,10 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup } } + // volumes + if volumes := cc.HostConfig.Binds; len(volumes) > 0 { + cliOpts.Volume = volumes + } if len(cc.HostConfig.BlkioWeightDevice) > 0 { devices := make([]string, 0, len(cc.HostConfig.BlkioWeightDevice)) for _, d := range cc.HostConfig.BlkioWeightDevice { diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index 6f84cf9b8..5d08e6163 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -144,7 +144,7 @@ func checkFlags(c *cobra.Command) error { func jsonOut(responses []entities.ListContainer) error { r := make([]entities.ListContainer, 0) for _, con := range responses { - con.CreatedAt = units.HumanDuration(time.Since(time.Unix(con.Created, 0))) + " ago" + con.CreatedAt = units.HumanDuration(time.Since(con.Created)) + " ago" con.Status = psReporter{con}.Status() r = append(r, con) } @@ -404,12 +404,12 @@ func (l psReporter) Ports() string { // CreatedAt returns the container creation time in string format. podman // and docker both return a timestamped value for createdat func (l psReporter) CreatedAt() string { - return time.Unix(l.Created, 0).String() + return l.Created.String() } // CreateHuman allows us to output the created time in human readable format func (l psReporter) CreatedHuman() string { - return units.HumanDuration(time.Since(time.Unix(l.Created, 0))) + " ago" + return units.HumanDuration(time.Since(l.Created)) + " ago" } // Cgroup exposes .Namespaces.Cgroup diff --git a/cmd/podman/registry/registry.go b/cmd/podman/registry/registry.go index 9c0b290e7..481ed810f 100644 --- a/cmd/podman/registry/registry.go +++ b/cmd/podman/registry/registry.go @@ -18,9 +18,6 @@ const DefaultRootAPIPath = "/run/podman/podman.sock" // DefaultRootAPIAddress is the default address of the REST socket with unix: prefix const DefaultRootAPIAddress = "unix:" + DefaultRootAPIPath -// DefaultVarlinkAddress is the default address of the varlink socket -const DefaultVarlinkAddress = "unix:/run/podman/io.podman" - type CliCommand struct { Mode []entities.EngineMode Command *cobra.Command diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index 78062d135..42482b5d9 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -38,7 +38,6 @@ Enable a listening service for API access to Podman commands. srvArgs = struct { Timeout int64 - Varlink bool }{} ) @@ -55,9 +54,6 @@ func init() { flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") _ = srvCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) - flags.BoolVar(&srvArgs.Varlink, "varlink", false, "Use legacy varlink service instead of REST. Unit of --time changes from seconds to milliseconds.") - - _ = flags.MarkDeprecated("varlink", "valink API is deprecated.") flags.SetNormalizeFunc(aliasTimeoutFlag) } @@ -97,11 +93,6 @@ func service(cmd *cobra.Command, args []string) error { Command: cmd, } - if srvArgs.Varlink { - opts.Timeout = time.Duration(srvArgs.Timeout) * time.Millisecond - return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts) - } - opts.Timeout = time.Duration(srvArgs.Timeout) * time.Second return restService(opts, cmd.Flags(), registry.PodmanConfig()) } @@ -111,8 +102,7 @@ func resolveAPIURI(_url []string) (string, error) { // 1) User input wins always // 2) systemd socket activation // 3) rootless honors XDG_RUNTIME_DIR - // 4) if varlink -- adapter.DefaultVarlinkAddress - // 5) lastly adapter.DefaultAPIAddress + // 4) lastly adapter.DefaultAPIAddress if len(_url) == 0 { if v, found := os.LookupEnv("PODMAN_SOCKET"); found { @@ -134,16 +124,11 @@ func resolveAPIURI(_url []string) (string, error) { } socketName := "podman.sock" - if srvArgs.Varlink { - socketName = "io.podman" - } socketPath := filepath.Join(xdg, "podman", socketName) if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil { return "", err } return "unix:" + socketPath, nil - case srvArgs.Varlink: - return registry.DefaultVarlinkAddress, nil default: if err := os.MkdirAll(filepath.Dir(registry.DefaultRootAPIPath), 0700); err != nil { return "", err diff --git a/cmd/podman/system/varlink.go b/cmd/podman/system/varlink.go deleted file mode 100644 index 363ac9cca..000000000 --- a/cmd/podman/system/varlink.go +++ /dev/null @@ -1,61 +0,0 @@ -// +build linux,!remote - -package system - -import ( - "time" - - "github.com/containers/common/pkg/completion" - "github.com/containers/podman/v2/cmd/podman/registry" - "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/spf13/cobra" -) - -var ( - varlinkDescription = `Run varlink interface. Podman varlink listens on the specified unix domain socket for incoming connects. - - Tools speaking varlink protocol can remotely manage pods, containers and images. -` - varlinkCmd = &cobra.Command{ - Use: "varlink [options] [URI]", - Args: cobra.MinimumNArgs(1), - Short: "Run varlink interface", - Long: varlinkDescription, - RunE: varlinkE, - ValidArgsFunction: completion.AutocompleteDefault, - Deprecated: "Please see 'podman system service' for RESTful APIs", - Hidden: true, - Example: `podman varlink unix:/run/podman/io.podman - podman varlink --time 5000 unix:/run/podman/io.podman`, - } - varlinkArgs = struct { - Timeout int64 - }{} -) - -func init() { - registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, - Command: varlinkCmd, - }) - flags := varlinkCmd.Flags() - - timeFlagName := "time" - flags.Int64VarP(&varlinkArgs.Timeout, timeFlagName, "t", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout") - _ = varlinkCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) - - flags.SetNormalizeFunc(aliasTimeoutFlag) -} - -func varlinkE(cmd *cobra.Command, args []string) error { - uri := registry.DefaultVarlinkAddress - if len(args) > 0 { - uri = args[0] - } - opts := entities.ServiceOptions{ - URI: uri, - Timeout: time.Duration(varlinkArgs.Timeout) * time.Second, - Command: cmd, - } - return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts) -} diff --git a/commands-demo.md b/commands-demo.md index cea7a63a3..967fe5beb 100644 --- a/commands-demo.md +++ b/commands-demo.md @@ -94,7 +94,6 @@ | [podman-umount(1)](https://podman.readthedocs.io/en/latest/markdown/podman-umount.1.html) | Unmount a working container's root filesystem | | [podman-unpause(1)](https://podman.readthedocs.io/en/latest/markdown/podman-unpause.1.html) | Unpause one or more containers | [![...](/docs/source/markdown/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | | [podman-unshare(1)](https://podman.readthedocs.io/en/latest/markdown/podman-unshare.1.html) | Run a command inside of a modified user namespace | -| [podman-varlink(1)](https://podman.readthedocs.io/en/latest/markdown/podman-varlink.1.html) | Runs the varlink backend interface | | [podman-version(1)](https://podman.readthedocs.io/en/latest/markdown/podman-version.1.html) | Display the Podman version information | | [podman-volume(1)](https://podman.readthedocs.io/en/latest/volume.html) | Manage Volumes | | [podman-volume-create(1)](https://podman.readthedocs.io/en/latest/markdown/podman-volume-create.1.html) | Create a new volume | diff --git a/contrib/build_rpm.sh b/contrib/build_rpm.sh index 6a82b131f..3039c1bf9 100755 --- a/contrib/build_rpm.sh +++ b/contrib/build_rpm.sh @@ -49,7 +49,6 @@ if [[ $pkg_manager == *dnf ]]; then fi PKGS+=(python3-devel \ - python3-varlink \ ) fi diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 04e8a3c1c..01e75d9a6 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -71,8 +71,8 @@ SCRIPT_BASE=${SCRIPT_BASE:-./contrib/cirrus} # Downloaded, but not installed packages. PACKAGE_DOWNLOAD_DIR=/var/cache/download -# Log remote-client system test varlink output here -PODMAN_SERVER_LOG=$CIRRUS_WORKING_DIR/varlink.log +# Log remote-client system test server output here +PODMAN_SERVER_LOG=$CIRRUS_WORKING_DIR/server.log # Defaults when not running under CI export CI="${CI:-false}" diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index bf2b1a52b..fa921f3e4 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -176,14 +176,6 @@ function _run_altbuild() { *Without*) make build-no-cgo ;; - *varlink-API) - export SUGGESTION='remove API.md, then "make varlink_api_generate" and commit changes.' - make varlink_api_generate BUILDTAGS="varlink" - ./hack/tree_status.sh - ;; - *varlink-binaries) - make clean BUILDTAGS="varlink" binaries - ;; *RPM*) make -f ./.copr/Makefile rpmbuild --rebuild ./podman-*.src.rpm diff --git a/contrib/dependencies.txt b/contrib/dependencies.txt index f61912fde..2b36c947b 100644 --- a/contrib/dependencies.txt +++ b/contrib/dependencies.txt @@ -24,7 +24,6 @@ python3-pip python3-psutil python3-pytoml python3-pyyaml -python3-varlink rsync slirp4netns unzip diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 7886a483b..3be44a3a3 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -166,7 +166,6 @@ Provides: bundled(golang(github.com/tchap/go-patricia)) = v2.2.6 Provides: bundled(golang(github.com/ulikunitz/xz)) = v0.5.4 # "-" are not accepted in version strings, so comment out below line #Provides: bundled(golang(github.com/urfave/cli)) = fix-short-opts-parsing -Provides: bundled(golang(github.com/varlink/go)) = master Provides: bundled(golang(github.com/vbatts/tar-split)) = v0.10.2 Provides: bundled(golang(github.com/vishvananda/netlink)) = master Provides: bundled(golang(github.com/vishvananda/netns)) = master diff --git a/contrib/spec/python-podman.spec.in b/contrib/spec/python-podman.spec.in index e21fb141e..1fc817d1f 100644 --- a/contrib/spec/python-podman.spec.in +++ b/contrib/spec/python-podman.spec.in @@ -36,20 +36,13 @@ BuildArch: noarch BuildRequires: git BuildRequires: python3-devel BuildRequires: python3-setuptools -BuildRequires: python3-varlink Requires: python3-humanize Requires: python3-pytoml Requires: python3-setuptools -Requires: python3-varlink Requires: python3-psutil Requires: podman -%if 0%{?fedora} -# 2018-07-20 RHEL8 doesn't have varlink RPM yet -Requires: python3-varlink -%endif - Provides: %{name} = %{version}-%{release} %description diff --git a/contrib/varlink/io.podman.service b/contrib/varlink/io.podman.service deleted file mode 100644 index 5be5329f4..000000000 --- a/contrib/varlink/io.podman.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=Podman Remote API Service -Requires=io.podman.socket -After=io.podman.socket -Documentation=man:podman-varlink(1) - -[Service] -Type=simple -ExecStart=/usr/bin/podman varlink unix:%t/podman/io.podman --timeout=60000 -TimeoutStopSec=30 -KillMode=process - -[Install] -WantedBy=multi-user.target -Also=io.podman.socket diff --git a/contrib/varlink/io.podman.socket b/contrib/varlink/io.podman.socket deleted file mode 100644 index f6a3ddc49..000000000 --- a/contrib/varlink/io.podman.socket +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Podman Remote API Socket -Documentation=man:podman-varlink(1) - -[Socket] -ListenStream=%t/podman/io.podman -SocketMode=0600 - -[Install] -WantedBy=sockets.target diff --git a/dependencies/analyses/README.md b/dependencies/analyses/README.md index 7309b1fa8..41d2ea418 100644 --- a/dependencies/analyses/README.md +++ b/dependencies/analyses/README.md @@ -29,7 +29,6 @@ WORK=/tmp/go-build794287815 2.7M github.com/containers/podman/vendor/github.com/gogo/protobuf/proto 2.5M github.com/containers/podman/vendor/k8s.io/apimachinery/pkg/apis/meta/v1 2.3M github.com/containers/podman/vendor/github.com/vishvananda/netlink -2.1M github.com/containers/podman/cmd/podman/varlink ``` The output of the `go-archive-analysis.sh` script is a sorted table with the size in bytes followed by the package. diff --git a/dependencies/dependencies.go b/dependencies/dependencies.go index 404ec2e60..b03ab149b 100644 --- a/dependencies/dependencies.go +++ b/dependencies/dependencies.go @@ -2,5 +2,4 @@ package dependencies import ( _ "github.com/onsi/ginkgo/ginkgo" - _ "github.com/varlink/go/cmd/varlink-go-interface-generator" // Note: this file is used to trick `go mod` into vendoring the command below. ) diff --git a/docs/generate.go b/docs/generate.go deleted file mode 100644 index 2adca8fc1..000000000 --- a/docs/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package docs - -//go:generate go run varlink/apidoc.go ../pkg/varlink/io.podman.varlink ../API.md diff --git a/docs/podman-derivative-api b/docs/podman-derivative-api index 1b6153df5..2e085c248 100644 --- a/docs/podman-derivative-api +++ b/docs/podman-derivative-api @@ -52,10 +52,6 @@ Potential skew between multiple libpod versions operating on the same storage ca .RE -.SH Varlink -.PP -Some code exists for this; splits the difference. Future uncertain. - .SH Making the choice .PP A good question to ask first is: Do you want users to be able to use \fB\fCpodman\fR to manipulate the containers created by your project? diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 4570bf3ff..c71f4fae9 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -317,6 +317,10 @@ Pass through HTTP Proxy environment variables. Write the image ID to the file. +#### **--ignorefile** + +Path to an alternative .dockerignore file. + #### **--ipc**=*how* Sets the configuration for IPC namespaces when handling `RUN` instructions. @@ -844,9 +848,10 @@ $ podman build -f dev/Containerfile https://10.10.10.1/podman/context.tar.gz ### `.dockerignore` -If the file .dockerignore exists in the context directory, `podman build` reads -its contents. Podman uses the content to exclude files and directories from -the context directory, when executing COPY and ADD directives in the +If the file .dockerignore exists in the context directory, `buildah copy` reads +its contents. Use the `--ignorefile` flag to override .dockerignore path location. +Podman uses the content to exclude files and directories from the context +directory, when executing COPY and ADD directives in the Containerfile/Dockerfile Users can specify a series of Unix shell globals in a .dockerignore file to diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index f280087c2..ab390447e 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -1021,18 +1021,21 @@ The _options_ is a comma delimited list and can be: The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The volume will be mounted into the container at this directory. -Volumes may specify a source as well, as either a directory on the host or the -name of a named volume. If no source is given, the volume will be created as an -anonymous named volume with a randomly generated name, and will be removed when +Volumes may specify a source as well, as either a directory on the host +or the name of a named volume. If no source is given, the volume will be created as an +anonymously named volume with a randomly generated name, and will be removed when the container is removed via the `--rm` flag or `podman rm --volumes`. If a volume source is specified, it must be a path on the host or the name of a named volume. Host paths are allowed to be absolute or relative; relative paths -are resolved relative to the directory Podman is run in. Any source that does -not begin with a `.` or `/` will be treated as the name of a named volume. -If a volume with that name does not exist, it will be created. Volumes created -with names are not anonymous. They are not removed by the `--rm` option and the -`podman rm --volumes` command. +are resolved relative to the directory Podman is run in. If the source does not +exist, Podman will return an error. Users must pre-create the source files or +directories. + +Any source that does not begin with a `.` or `/` will be treated as the name of +a named volume. If a volume with that name does not exist, it will be created. +Volumes created with names are not anonymous, and they are not removed by the `--rm` +option and the `podman rm --volumes` command. You can specify multiple **-v** options to mount one or more volumes into a container. @@ -1069,7 +1072,7 @@ upper. Modifications to the mount point are destroyed when the container finishes executing, similar to a tmpfs mount point being unmounted. Subsequent executions of the container will see the original source directory -content, any changes from previous container executions no longer exists. +content, any changes from previous container executions no longer exist. One use case of the overlay mount is sharing the package cache from the host into the container to allow speeding up builds. diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index d65d5d26f..13b586e17 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1054,11 +1054,11 @@ Set the UTS namespace mode for the container. The following values are supported - **ns:[path]**: run the container in the given existing UTS namespace. - **container:[container]**: join the UTS namespace of the specified container. -#### **--volume**, **-v**[=[[_source-volume_|_host-dir_:]_container-dir_[:_options_]]] +#### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] -Create a bind mount. If you specify _/host-dir_:_/container-dir_, Podman -bind mounts _host-dir_ in the host to _container-dir_ in the Podman -container. Similarly, _source-volume_:_/container-dir_ will mount the volume +Create a bind mount. If you specify _/HOST-DIR_:_/CONTAINER-DIR_, Podman +bind mounts _host-dir_ in the host to _CONTAINER-DIR_ in the Podman +container. Similarly, _SOURCE-VOLUME_:_/CONTAINER-DIR_ will mount the volume in the host to the container. If no such named volume exists, Podman will create one. @@ -1073,24 +1073,30 @@ The _options_ is a comma delimited list and can be: <sup>[[1]](#Footnote1)</sup> * [**no**]**suid** * [**O**] -The _container-dir_ must be an absolute path. +The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The volume +will be mounted into the container at this directory. -Volumes may specify a source as well, as either a directory on the host or the -name of a named volume. If no source is given, the volume will be created as an -anonymous named volume with a randomly generated name, and will be removed when -the container is removed via the **--rm** flag or **podman rm --volumes**. +Volumes may specify a source as well, as either a directory on the host +or the name of a named volume. If no source is given, the volume will be created as an +anonymously named volume with a randomly generated name, and will be removed when +the container is removed via the `--rm` flag or `podman rm --volumes`. If a volume source is specified, it must be a path on the host or the name of a named volume. Host paths are allowed to be absolute or relative; relative paths -are resolved relative to the directory Podman is run in. Any source that does -not begin with a **.** or **/** will be treated as the name of a named volume. -If a volume with that name does not exist, it will be created. Volumes created -with names are not anonymous and are not removed by **--rm** and -**podman rm --volumes**. +are resolved relative to the directory Podman is run in. If the source does not +exist, Podman will return an error. Users must pre-create the source files or +directories. + +Any source that does not begin with a `.` or `/` will be treated as the name of +a named volume. If a volume with that name does not exist, it will be created. +Volumes created with names are not anonymous, and they are not removed by the `--rm` +option and the `podman rm --volumes` command. You can specify multiple **-v** options to mount one or more volumes into a container. + `Write Protected Volume Mounts` + You can add **:ro** or **:rw** option to mount a volume in read-only or read-write mode, respectively. By default, the volumes are mounted read-write. @@ -1119,7 +1125,7 @@ upper. Modifications to the mount point are destroyed when the container finishes executing, similar to a tmpfs mount point being unmounted. Subsequent executions of the container will see the original source directory -content, any changes from previous container executions no longer exists. +content, any changes from previous container executions no longer exist. One use case of the overlay mount is sharing the package cache from the host into the container to allow speeding up builds. diff --git a/docs/tutorials/podman-derivative-api.md b/docs/tutorials/podman-derivative-api.md index 8a1f40fc0..e38c2b13d 100644 --- a/docs/tutorials/podman-derivative-api.md +++ b/docs/tutorials/podman-derivative-api.md @@ -46,11 +46,6 @@ Disadvantages: - Binary size - Potential skew between multiple libpod versions operating on the same storage can cause problems -Varlink ---- - -The Varlink API is presently deprecated. We do not recommend adopting it for new projects. - Making the choice --- diff --git a/docs/tutorials/varlink_remote_client.md b/docs/tutorials/varlink_remote_client.md deleted file mode 100644 index 54c648a48..000000000 --- a/docs/tutorials/varlink_remote_client.md +++ /dev/null @@ -1,89 +0,0 @@ -# Podman varlink remote-client tutorial [DEPRECATED] - -## What is the varlink client - -This API has been deprecated by the [REST API](https://docs.podman.io/en/latest/_static/api.html). -For usage on Windows and Mac, please reference the [Podman Mac/Windows tutorial](https://github.com/containers/podman/blob/master/docs/tutorials/mac_win_client.md) -Varlink support is in maintenance mode, and will be removed in a future release. -For more details, you can see [this blog](https://podman.io/blogs/2020/01/17/podman-new-api.html). - -The purpose of the Podman remote-client is to allow users to interact with a Podman "backend" -while on a separate client. The command line interface of the remote client is exactly the -same as the regular Podman commands with the exception of some flags being removed as they -do not apply to the remote-client. - -## What you need -To use the remote-client, you will need a binary for your client and a Podman "backend"; hereafter -referred to as the Podman node. In this context, a Podman node is a Linux system with Podman -installed on it and the varlink service activated. You will also need to be able to ssh into this -system as a user with privileges to the varlink socket (more on this later). - -## Building the remote client -At this time, the Podman remote-client is not being packaged for any distribution. It must be built from -source. To set up your build environment, see [Installation notes](https://github.com/containers/podman/blob/master/install.md) and follow the -section [Building from scratch](https://github.com/containers/podman/blob/master/install.md#building-from-scratch). Once you can successfully -build the regular Podman binary, you can now build the remote-client. -``` -$ make podman-remote -``` -Like building the regular Podman, the resulting binary will be in the *bin* directory. This is the binary -you will run on the remote node later in the instructions. - -## Setting up the remote and Podman nodes - -To use the remote-client, you must perform some setup on both the remote and Podman nodes. In this case, -the remote node refers to where the remote-client is being run; and the Podman node refers to where -Podman and its storage reside. - - -### Podman node setup - -Varlink bridge support is provided by the varlink cli command and installed using: -``` -$ sudo dnf install varlink-cli -``` - -The Podman node must have Podman (not the remote-client) installed as normal. If your system uses systemd, -then simply start the Podman varlink socket. -``` -$ sudo systemctl start io.podman.socket -``` - -If your system cannot use systemd, then you can manually establish the varlink socket with the Podman -command: -``` -$ sudo podman --log-level debug varlink --timeout 0 unix://run/podman/io.podman -``` - -### Required permissions -For now, the remote-client requires that you be able to run a privileged Podman and have privileged ssh -access to the remote system. This limitation is being worked on. - -### Remote node setup - -#### Initiate an ssh session to the Podman node -To use the remote client, an ssh connection to the Podman server must be established. - -Using the varlink bridge, an ssh tunnel must be initiated to connect to the server. Podman must then be informed of the location of the sshd server on the targeted server - -``` -$ export PODMAN_VARLINK_BRIDGE=$'ssh -T -p22 root@remotehost -- "varlink -A \'podman varlink \$VARLINK_ADDRESS\' bridge"' -$ bin/podman-remote images -REPOSITORY TAG IMAGE ID CREATED SIZE -docker.io/library/ubuntu latest 47b19964fb50 2 weeks ago 90.7 MB -docker.io/library/alpine latest caf27325b298 3 weeks ago 5.8 MB -quay.io/cevich/gcloud_centos latest 641dad61989a 5 weeks ago 489 MB -k8s.gcr.io/pause 3.1 da86e6ba6ca1 14 months ago 747 kB -``` - -The PODMAN_VARLINK_BRIDGE variable may be added to your log in settings. It does not change per connection. - -If coming from a Windows machine, the PODMAN_VARLINK_BRIDGE is formatted as: -``` -set PODMAN_VARLINK_BRIDGE=C:\Windows\System32\OpenSSH\ssh.exe -T -p22 root@remotehost -- varlink -A "podman varlink $VARLINK_ADDRESS" bridge -``` - -The arguments before the `--` are presented to ssh while the arguments after are for the varlink cli. The varlink arguments should be copied verbatim. - - `-p` is the port on the remote host for the ssh tunnel. `22` is the default. - - `root` is the currently supported user, while `remotehost` is the name or IP address of the host providing the Podman service. - - `-i` may be added to select an identity file. diff --git a/docs/varlink/apidoc.go b/docs/varlink/apidoc.go deleted file mode 100644 index 87304de15..000000000 --- a/docs/varlink/apidoc.go +++ /dev/null @@ -1,279 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "sort" - "strings" - - "github.com/varlink/go/varlink/idl" -) - -func readFileToString(path string) (string, error) { - content, err := ioutil.ReadFile(path) - if err != nil { - return "", err - } - return string(content), nil -} - -func exit(err error) { - fmt.Println(err.Error()) - os.Exit(1) -} - -func typeToString(input *idl.Type) string { - switch input.Kind { - case idl.TypeString: - return "string" - case idl.TypeBool: - return "bool" - case idl.TypeFloat: - return "float" - case idl.TypeArray: - result := input.ElementType.Alias - if result == "" { - return fmt.Sprintf("[]%s", typeToString(input.ElementType)) - } - return result - case idl.TypeAlias: - return input.Alias - case idl.TypeMap: - return "map[string]" - case idl.TypeInt: - return "int" - case idl.TypeMaybe: - return fmt.Sprintf("?%s", typeToString(input.ElementType)) - } - return "" -} - -func typeToLink(input string) string { - switch input { - case "string": - return "https://godoc.org/builtin#string" - case "int": - return "https://godoc.org/builtin#int" - case "bool": - return "https://godoc.org/builtin#bool" - case "float": - return "https://golang.org/src/builtin/builtin.go#L58" - default: - return fmt.Sprintf("#%s", input) - } -} - -type funcArgs struct { - paramName string - paramKind string -} -type funcDescriber struct { - Name string - inputParams []funcArgs - returnParams []funcArgs - doc string -} - -type funcSorter []funcDescriber - -func (a funcSorter) Len() int { return len(a) } -func (a funcSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a funcSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } - -type typeAttrs struct { - Name string - AttrType string -} -type typeDescriber struct { - Name string - doc string - Attrs []typeAttrs -} - -type typeSorter []typeDescriber - -func (a typeSorter) Len() int { return len(a) } -func (a typeSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a typeSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } - -type err struct { - Name string - doc string -} - -type errorSorter []err - -func (a errorSorter) Len() int { return len(a) } -func (a errorSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a errorSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } - -// collects defined types in the idl -func getTypes(tidl *idl.IDL) []typeDescriber { - var types []typeDescriber - for _, x := range tidl.Aliases { - i := typeDescriber{ - Name: x.Name, - doc: x.Doc, - } - ta := []typeAttrs{} - for _, y := range x.Type.Fields { - result := typeToString(y.Type) - ta = append(ta, typeAttrs{Name: y.Name, AttrType: result}) - } - i.Attrs = ta - types = append(types, i) - } - return types -} - -// collects defined methods in the idl -func getMethods(midl *idl.IDL) []funcDescriber { - var methods []funcDescriber - for _, t := range midl.Methods { - m := funcDescriber{ - Name: t.Name, - doc: t.Doc, - } - fa := []funcArgs{} - fo := []funcArgs{} - - for _, i := range t.In.Fields { - fa = append(fa, funcArgs{paramName: i.Name, paramKind: typeToString(i.Type)}) - - } - for _, f := range t.Out.Fields { - fo = append(fo, funcArgs{paramName: f.Name, paramKind: typeToString(f.Type)}) - } - m.inputParams = fa - m.returnParams = fo - methods = append(methods, m) - } - return methods -} - -// collects defined errors in the idl -func getErrors(midl *idl.IDL) []err { - var errors []err - for _, e := range midl.Errors { - myError := err{ - Name: e.Name, - doc: e.Doc, - } - errors = append(errors, myError) - } - return errors -} - -// generates the index for the top of the markdown page -func generateIndex(methods []funcDescriber, types []typeDescriber, errors []err, b bytes.Buffer) bytes.Buffer { - // Sort the methods, types, and errors by alphabetical order - sort.Sort(funcSorter(methods)) - sort.Sort(typeSorter(types)) - sort.Sort(errorSorter(errors)) - - for _, method := range methods { - var inArgs []string - var outArgs []string - for _, inArg := range method.inputParams { - inArgs = append(inArgs, fmt.Sprintf("%s: %s", inArg.paramName, inArg.paramKind)) - - } - for _, outArg := range method.returnParams { - outArgs = append(outArgs, outArg.paramKind) - - } - b.WriteString(fmt.Sprintf("\n[func %s(%s) %s](#%s)\n", method.Name, strings.Join(inArgs, ", "), strings.Join(outArgs, ", "), method.Name)) - } - b.WriteString("\n") - for _, t := range types { - b.WriteString(fmt.Sprintf("[type %s](#%s)\n\n", t.Name, t.Name)) - } - for _, e := range errors { - b.WriteString(fmt.Sprintf("[error %s](#%s)\n\n", e.Name, e.Name)) - } - return b -} - -// performs the output for defined methods -func generateFuncDescriptions(methods []funcDescriber, b bytes.Buffer) bytes.Buffer { - for _, method := range methods { - b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>func %s\n", method.Name, method.Name)) - var inArgs []string - var outArgs []string - for _, inArg := range method.inputParams { - inArgs = append(inArgs, fmt.Sprintf("%s: [%s](%s)", inArg.paramName, inArg.paramKind, typeToLink(inArg.paramKind))) - } - for _, outArg := range method.returnParams { - outArgs = append(outArgs, fmt.Sprintf("[%s](%s)", outArg.paramKind, typeToLink(outArg.paramKind))) - } - b.WriteString(fmt.Sprintf("<div style=\"background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;\">\n\nmethod %s(%s) %s</div>", method.Name, strings.Join(inArgs, ", "), strings.Join(outArgs, ", "))) - b.WriteString("\n") - b.WriteString(method.doc) - b.WriteString("\n") - } - return b -} - -// performs the output for defined types/structs -func generateTypeDescriptions(types []typeDescriber, b bytes.Buffer) bytes.Buffer { - for _, t := range types { - b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>type %s\n", t.Name, t.Name)) - b.WriteString(fmt.Sprintf("\n%s\n", t.doc)) - for _, i := range t.Attrs { - b.WriteString(fmt.Sprintf("\n%s [%s](%s)\n", i.Name, i.AttrType, typeToLink(i.AttrType))) - } - } - return b -} - -// performs the output for defined errors -func generateErrorDescriptions(errors []err, b bytes.Buffer) bytes.Buffer { - for _, e := range errors { - b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>type %s\n", e.Name, e.Name)) - b.WriteString(fmt.Sprintf("\n%s\n", e.doc)) - } - return b -} - -func main() { - args := os.Args - if len(args) < 2 { - exit(fmt.Errorf("you must provide an input and output path")) - } - varlinkFile := args[1] - mdFile := args[2] - - varlinkInput, err := readFileToString(varlinkFile) - if err != nil { - exit(err) - } - varlinkInput = strings.TrimRight(varlinkInput, "\n") - - // Run the idl parser - midl, err := idl.New(varlinkInput) - if err != nil { - exit(err) - } - // Collect up the info from the idl - methods := getMethods(midl) - types := getTypes(midl) - errors := getErrors(midl) - - out := bytes.Buffer{} - out.WriteString(fmt.Sprintf("# %s\n", midl.Name)) - out.WriteString(fmt.Sprintf("%s\n", midl.Doc)) - out.WriteString("## Index\n") - out = generateIndex(methods, types, errors, out) - out.WriteString("## Methods\n") - out = generateFuncDescriptions(methods, out) - out.WriteString("## Types\n") - out = generateTypeDescriptions(types, out) - out.WriteString("## Errors\n") - out = generateErrorDescriptions(errors, out) - if err := ioutil.WriteFile(mdFile, out.Bytes(), 0755); err != nil { - fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err) - os.Exit(1) - } -} @@ -10,7 +10,7 @@ require ( github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/containernetworking/cni v0.8.0 github.com/containernetworking/plugins v0.8.7 - github.com/containers/buildah v1.18.0 + github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c github.com/containers/common v0.29.0 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.8.1 @@ -57,7 +57,6 @@ require ( github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 github.com/uber/jaeger-client-go v2.25.0+incompatible github.com/uber/jaeger-lib v2.2.0+incompatible // indirect - github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b github.com/vishvananda/netlink v1.1.0 go.etcd.io/bbolt v1.3.5 go.uber.org/atomic v1.7.0 // indirect @@ -91,16 +91,12 @@ github.com/containernetworking/cni v0.8.0 h1:BT9lpgGoH4jw3lFC7Odz2prU5ruiYKcgAjM github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/plugins v0.8.7 h1:bU7QieuAp+sACI2vCzESJ3FoT860urYP+lThyZkb/2M= github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0= -github.com/containers/buildah v1.18.0 h1:mWEm013LVNGecF++sYo0T7fe/4pqMas/PQxQ/qviC68= -github.com/containers/buildah v1.18.0/go.mod h1:qHLk7RUL7cHfA7ve1MKkZ6cyKUxHD0YxiLJcKY+mJe8= -github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4= +github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c h1:vyc2iYz9b2vfDiigpLyhiXNqXITt/dmDk74HpHzlQow= +github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c/go.mod h1:B+0OkXUogxdwsEy4ax3a5/vDtJjL6vCisiV6frQZJ4A= github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ= github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= -github.com/containers/image/v5 v5.7.0/go.mod h1:8aOy+YaItukxghRORkvhq5ibWttHErzDLy6egrKfKos= -github.com/containers/image/v5 v5.8.0 h1:B3FGHi0bdGXgg698kBIGOlHCXN5n+scJr6/5354GOPU= -github.com/containers/image/v5 v5.8.0/go.mod h1:jKxdRtyIDumVa56hdsZvV+gwx4zB50hRou6pIuCWLkg= github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q= github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= @@ -109,10 +105,7 @@ github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6Gz github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g= github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA= github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= -github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY= github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI= -github.com/containers/storage v1.24.0 h1:Fo2LkF7tkMLmo38sTZ/G8wHjcn8JfUFPfyTxM4WwMfk= -github.com/containers/storage v1.24.0/go.mod h1:A4d3BzuZK9b3oLVEsiSRhZLPIx3z7utgiPyXLK/YMhY= github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc= github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -320,8 +313,6 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= -github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= @@ -370,7 +361,6 @@ github.com/moby/sys/mount v0.1.1 h1:mdhBytJ1SMmMat0gtzWWjFX/87K5j6E/7Q5z7rR0cZY= github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74= github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= -github.com/moby/sys/mountinfo v0.3.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/term v0.0.0-20200429084858-129dac9f73f6/go.mod h1:or9wGItza1sRcM4Wd3dIv8DsFHYQuFsMHEdxUIlUxms= @@ -545,8 +535,6 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b h1:hdDRrn9OP/roL8a/e/5Zu85ldrcdndu9IeBj2OEvQm0= -github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b/go.mod h1:YHaw8N660ESgMgLOZfLQqT1htFItynAUxMesFBho52s= github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE= github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g= github.com/vbauerster/mpb/v5 v5.3.0 h1:vgrEJjUzHaSZKDRRxul5Oh4C72Yy/5VEMb0em+9M0mQ= diff --git a/hack/golangci-lint.sh b/hack/golangci-lint.sh index 03c29c89a..50bf29bb8 100755 --- a/hack/golangci-lint.sh +++ b/hack/golangci-lint.sh @@ -6,8 +6,8 @@ set -e declare -A BUILD_TAGS # TODO: add systemd tag BUILD_TAGS[default]="apparmor,seccomp,selinux" -BUILD_TAGS[abi]="${BUILD_TAGS[default]},varlink,!remoteclient" -BUILD_TAGS[tunnel]="${BUILD_TAGS[default]},remote,varlink,remoteclient" +BUILD_TAGS[abi]="${BUILD_TAGS[default]},!remoteclient" +BUILD_TAGS[tunnel]="${BUILD_TAGS[default]},remote,remoteclient" declare -A SKIP_DIRS SKIP_DIRS[abi]="" diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages index 55c8b6582..08e56c77e 100755 --- a/hack/xref-helpmsgs-manpages +++ b/hack/xref-helpmsgs-manpages @@ -176,9 +176,6 @@ sub xref_by_man { # Special case: weirdness with Cobra and global/local options next if $k eq '--namespace' && $man =~ /-ps/; - # Special case: these require compiling with 'varlink' tag, - # which doesn't happen in CI gating task. - next if $k eq 'varlink'; next if "@subcommand" eq 'system' && $k eq 'service'; # Special case: podman completion is a hidden command diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index b81f3f716..56575c195 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -22,9 +22,9 @@ import ( cnitypes "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/buildah/pkg/overlay" - "github.com/containers/buildah/pkg/secrets" "github.com/containers/common/pkg/apparmor" "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/subscriptions" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/events" "github.com/containers/podman/v2/pkg/annotations" @@ -1435,7 +1435,7 @@ func (c *Container) makeBindMounts() error { } // Add Secret Mounts - secretMounts := secrets.SecretMountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.Containers.DefaultMountsFile, c.state.Mountpoint, c.RootUID(), c.RootGID(), rootless.IsRootless(), false) + secretMounts := subscriptions.MountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.Containers.DefaultMountsFile, c.state.Mountpoint, c.RootUID(), c.RootGID(), rootless.IsRootless(), false) for _, mount := range secretMounts { if _, ok := c.state.BindMounts[mount.Destination]; !ok { c.state.BindMounts[mount.Destination] = mount.Source diff --git a/libpod/container_top_linux.go b/libpod/container_top_linux.go index d6d4c6084..161367d75 100644 --- a/libpod/container_top_linux.go +++ b/libpod/container_top_linux.go @@ -80,8 +80,8 @@ func (c *Container) Top(descriptors []string) ([]string, error) { func (c *Container) GetContainerPidInformation(descriptors []string) ([]string, error) { pid := strconv.Itoa(c.state.PID) // TODO: psgo returns a [][]string to give users the ability to apply - // filters on the data. We need to change the API here and the - // varlink API to return a [][]string if we want to make use of + // filters on the data. We need to change the API here + // to return a [][]string if we want to make use of // filtering. opts := psgo.JoinNamespaceOpts{FillMappings: rootless.IsRootless()} diff --git a/libpod/events/config.go b/libpod/events/config.go index af09a65ae..fc1457289 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -95,10 +95,6 @@ type Type string type Status string const ( - // If you add or subtract any values to the following lists, make sure you also update - // the switch statements below and the enums for EventType or EventStatus in the - // varlink description file. - // Container - event is related to containers Container Type = "container" // Image - event is related to images diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 4e7ffaf81..15e470c80 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -1047,21 +1047,25 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro return err } + if err := c.runtime.state.NetworkDisconnect(c, netName); err != nil { + return err + } + + c.newNetworkEvent(events.NetworkDisconnect, netName) if c.state.State != define.ContainerStateRunning { - return errors.Wrapf(define.ErrCtrStateInvalid, "cannot disconnect container %s from networks as it is not running", nameOrID) + return nil } + if c.state.NetNS == nil { return errors.Wrapf(define.ErrNoNetwork, "unable to disconnect %s from %s", nameOrID, netName) } + podConfig := c.runtime.getPodNetwork(c.ID(), c.Name(), c.state.NetNS.Path(), []string{netName}, c.config.PortMappings, nil, nil, c.state.NetInterfaceDescriptions) if err := c.runtime.netPlugin.TearDownPod(podConfig); err != nil { return err } - if err := c.runtime.state.NetworkDisconnect(c, netName); err != nil { - return err - } - // update network status + // update network status if container is not running networkStatus := c.state.NetworkStatus // clip out the index of the network tmpNetworkStatus := make([]*cnitypes.Result, len(networkStatus)-1) @@ -1071,7 +1075,6 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro } } c.state.NetworkStatus = tmpNetworkStatus - c.newNetworkEvent(events.NetworkDisconnect, netName) return c.save() } @@ -1096,15 +1099,16 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e return err } + if err := c.runtime.state.NetworkConnect(c, netName, aliases); err != nil { + return err + } + c.newNetworkEvent(events.NetworkConnect, netName) if c.state.State != define.ContainerStateRunning { - return errors.Wrapf(define.ErrCtrStateInvalid, "cannot connect container %s to networks as it is not running", nameOrID) + return nil } if c.state.NetNS == nil { return errors.Wrapf(define.ErrNoNetwork, "unable to connect %s to %s", nameOrID, netName) } - if err := c.runtime.state.NetworkConnect(c, netName, aliases); err != nil { - return err - } ctrNetworks, _, err := c.networks() if err != nil { @@ -1159,7 +1163,6 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e networkStatus[index] = networkResults[0] c.state.NetworkStatus = networkStatus } - c.newNetworkEvent(events.NetworkConnect, netName) return c.save() } diff --git a/libpod/pod_top_linux.go b/libpod/pod_top_linux.go index 15ba02389..0e42c62df 100644 --- a/libpod/pod_top_linux.go +++ b/libpod/pod_top_linux.go @@ -53,9 +53,8 @@ func (p *Pod) GetPodPidInformation(descriptors []string) ([]string, error) { } // TODO: psgo returns a [][]string to give users the ability to apply - // filters on the data. We need to change the API here and the - // varlink API to return a [][]string if we want to make use of - // filtering. + // filters on the data. We need to change the API here to return + // a [][]string if we want to make use of filtering. opts := psgo.JoinNamespaceOpts{FillMappings: rootless.IsRootless()} output, err := psgo.JoinNamespaceAndProcessInfoByPidsWithOptions(pids, psgoDescriptors, &opts) if err != nil { diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 76419587a..3e4185db1 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -34,40 +34,56 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm // Set Pod hostname g.Config.Hostname = p.config.Hostname + var options []CtrCreateOption + + // Command: If user-specified, use that preferentially. + // If not set and the config file is set, fall back to that. + var infraCtrCommand []string + if p.config.InfraContainer.InfraCommand != nil { + logrus.Debugf("User-specified infra container entrypoint %v", p.config.InfraContainer.InfraCommand) + infraCtrCommand = p.config.InfraContainer.InfraCommand + } else if r.config.Engine.InfraCommand != "" { + logrus.Debugf("Config-specified infra container entrypoint %s", r.config.Engine.InfraCommand) + infraCtrCommand = []string{r.config.Engine.InfraCommand} + } + // Only if set by the user or containers.conf, we set entrypoint for the + // infra container. + // This is only used by commit, so it shouldn't matter... But someone + // may eventually want to commit an infra container? + // TODO: Should we actually do this if set by containers.conf? + if infraCtrCommand != nil { + // Need to duplicate the array - we are going to add Cmd later + // so the current array will be changed. + newArr := make([]string, 0, len(infraCtrCommand)) + newArr = append(newArr, infraCtrCommand...) + options = append(options, WithEntrypoint(newArr)) + } + isRootless := rootless.IsRootless() - entrypointSet := len(p.config.InfraContainer.InfraCommand) > 0 - entryPoint := p.config.InfraContainer.InfraCommand - entryCmd := []string{} - var options []CtrCreateOption // I've seen circumstances where config is being passed as nil. // Let's err on the side of safety and make sure it's safe to use. if config != nil { - // default to entrypoint in image if there is one - if !entrypointSet { - if len(config.Entrypoint) > 0 { - entrypointSet = true - entryPoint = config.Entrypoint - entryCmd = config.Entrypoint + if infraCtrCommand == nil { + // If we have no entrypoint and command from the image, + // we can't go on - the infra container has no command. + if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 { + return nil, errors.Errorf("infra container has no command") } - } else { // so use the InfraCommand - entrypointSet = true - entryCmd = entryPoint - } - - if len(config.Cmd) > 0 { - // We can't use the default pause command, since we're - // sourcing from the image. If we didn't already set an - // entrypoint, set one now. - if !entrypointSet { + if len(config.Entrypoint) > 0 { + infraCtrCommand = config.Entrypoint + } else { // Use the Docker default "/bin/sh -c" // entrypoint, as we're overriding command. // If an image doesn't want this, it can // override entrypoint too. - entryCmd = []string{"/bin/sh", "-c"} + infraCtrCommand = []string{"/bin/sh", "-c"} } - entryCmd = append(entryCmd, config.Cmd...) } + if len(config.Cmd) > 0 { + infraCtrCommand = append(infraCtrCommand, config.Cmd...) + } + if len(config.Env) > 0 { for _, nameValPair := range config.Env { nameValSlice := strings.Split(nameValPair, "=") @@ -127,9 +143,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm } g.SetRootReadonly(true) - g.SetProcessArgs(entryCmd) + g.SetProcessArgs(infraCtrCommand) - logrus.Debugf("Using %q as infra container entrypoint", entryCmd) + logrus.Debugf("Using %q as infra container command", infraCtrCommand) g.RemoveMount("/dev/shm") if isRootless { @@ -148,9 +164,6 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName)) options = append(options, WithName(containerName)) options = append(options, withIsInfra()) - if entrypointSet { - options = append(options, WithEntrypoint(entryPoint)) - } if len(p.config.InfraContainer.ConmonPidFile) > 0 { options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile)) } diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 293a17e0f..1dd563393 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -1,12 +1,379 @@ package compat import ( - "errors" - "net/http" + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "path/filepath" + "strings" + "github.com/containers/buildah/copier" + "github.com/containers/buildah/pkg/chrootuser" + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/storage/pkg/idtools" + "github.com/opencontainers/runtime-spec/specs-go" + + "net/http" + "os" + "time" + + "github.com/gorilla/schema" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func Archive(w http.ResponseWriter, r *http.Request) { - utils.Error(w, "not implemented", http.StatusNotImplemented, errors.New("not implemented")) + decoder := r.Context().Value("decoder").(*schema.Decoder) + runtime := r.Context().Value("runtime").(*libpod.Runtime) + + switch r.Method { + case http.MethodPut: + handlePut(w, r, decoder, runtime) + case http.MethodGet, http.MethodHead: + handleHeadOrGet(w, r, decoder, runtime) + default: + utils.Error(w, fmt.Sprintf("not implemented, method: %v", r.Method), http.StatusNotImplemented, errors.New(fmt.Sprintf("not implemented, method: %v", r.Method))) + } +} + +func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { + query := struct { + Path string `schema:"path"` + }{} + + err := decoder.Decode(&query, r.URL.Query()) + if err != nil { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) + return + } + + if query.Path == "" { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.New("missing `path` parameter")) + return + } + + containerName := utils.GetName(r) + + ctr, err := runtime.LookupContainer(containerName) + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists")) + return + } else if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + + mountPoint, err := ctr.Mount() + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to mount the container")) + return + } + + defer func() { + if err := ctr.Unmount(false); err != nil { + logrus.Warnf("failed to unmount container %s: %q", containerName, err) + } + }() + + opts := copier.StatOptions{} + + mountPoint, path, err := fixUpMountPointAndPath(runtime, ctr, mountPoint, query.Path) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + + stats, err := copier.Stat(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)}) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to get stats about file")) + return + } + + if len(stats) <= 0 || len(stats[0].Globbed) <= 0 { + errs := make([]string, 0, len(stats)) + + for _, stat := range stats { + if stat.Error != "" { + errs = append(errs, stat.Error) + } + } + + utils.Error(w, "Not found.", http.StatusNotFound, fmt.Errorf("file doesn't exist (errs: %q)", strings.Join(errs, ";"))) + + return + } + + statHeader, err := statsToHeader(stats[0].Results[stats[0].Globbed[0]]) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + + w.Header().Add("X-Docker-Container-Path-Stat", statHeader) + + if r.Method == http.MethodGet { + idMappingOpts, err := ctr.IDMappings() + if err != nil { + utils.Error(w, "Not found.", http.StatusInternalServerError, + errors.Wrapf(err, "error getting IDMappingOptions")) + return + } + + destOwner := idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()} + + opts := copier.GetOptions{ + UIDMap: idMappingOpts.UIDMap, + GIDMap: idMappingOpts.GIDMap, + ChownDirs: &destOwner, + ChownFiles: &destOwner, + KeepDirectoryNames: true, + } + + w.WriteHeader(http.StatusOK) + + err = copier.Get(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)}, w) + if err != nil { + logrus.Error(errors.Wrapf(err, "failed to copy from the %s container path %s", containerName, query.Path)) + return + } + } else { + w.WriteHeader(http.StatusOK) + } +} + +func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { + query := struct { + Path string `schema:"path"` + // TODO handle params below + NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"` + CopyUIDGID bool `schema:"copyUIDGID"` + }{} + + err := decoder.Decode(&query, r.URL.Query()) + if err != nil { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) + return + } + + ctrName := utils.GetName(r) + + ctr, err := runtime.LookupContainer(ctrName) + if err != nil { + utils.Error(w, "Not found", http.StatusNotFound, errors.Wrapf(err, "the %s container doesn't exists", ctrName)) + return + } + + mountPoint, err := ctr.Mount() + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "failed to mount the %s container", ctrName)) + return + } + + defer func() { + if err := ctr.Unmount(false); err != nil { + logrus.Warnf("failed to unmount container %s", ctrName) + } + }() + + user, err := getUser(mountPoint, ctr.User()) + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) + return + } + + idMappingOpts, err := ctr.IDMappings() + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "error getting IDMappingOptions")) + return + } + + destOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} + + opts := copier.PutOptions{ + UIDMap: idMappingOpts.UIDMap, + GIDMap: idMappingOpts.GIDMap, + ChownDirs: &destOwner, + ChownFiles: &destOwner, + } + + mountPoint, path, err := fixUpMountPointAndPath(runtime, ctr, mountPoint, query.Path) + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) + return + } + + w.WriteHeader(http.StatusOK) + + err = copier.Put(mountPoint, filepath.Join(mountPoint, path), opts, r.Body) + if err != nil { + logrus.Error(errors.Wrapf(err, "failed to copy to the %s container path %s", ctrName, query.Path)) + return + } +} + +func statsToHeader(stats *copier.StatForItem) (string, error) { + statsDTO := struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + ModTime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` + }{ + Name: filepath.Base(stats.Name), + Size: stats.Size, + Mode: stats.Mode, + ModTime: stats.ModTime, + LinkTarget: stats.ImmediateTarget, + } + + jsonBytes, err := json.Marshal(&statsDTO) + if err != nil { + return "", errors.Wrap(err, "failed to serialize file stats") + } + + buff := bytes.NewBuffer(make([]byte, 0, 128)) + base64encoder := base64.NewEncoder(base64.StdEncoding, buff) + + _, err = base64encoder.Write(jsonBytes) + if err != nil { + return "", err + } + + err = base64encoder.Close() + if err != nil { + return "", err + } + + return buff.String(), nil +} + +// the utility functions below are copied from abi/cp.go + +func getUser(mountPoint string, userspec string) (specs.User, error) { + uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec) + u := specs.User{ + UID: uid, + GID: gid, + Username: userspec, + } + + if !strings.Contains(userspec, ":") { + groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID)) + if err2 != nil { + if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil { + err = err2 + } + } else { + u.AdditionalGids = groups + } + } + + return u, err +} + +func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, mountPoint, ctrPath string) (string, string, error) { + if !filepath.IsAbs(ctrPath) { + endsWithSep := strings.HasSuffix(ctrPath, string(filepath.Separator)) + ctrPath = filepath.Join(ctr.WorkingDir(), ctrPath) + + if endsWithSep { + ctrPath = ctrPath + string(filepath.Separator) + } + } + if isVol, volDestName, volName := isVolumeDestName(ctrPath, ctr); isVol { //nolint(gocritic) + newMountPoint, path, err := pathWithVolumeMount(runtime, volDestName, volName, ctrPath) + if err != nil { + return "", "", errors.Wrapf(err, "error getting source path from volume %s", volDestName) + } + + mountPoint = newMountPoint + ctrPath = path + } else if isBindMount, mount := isBindMountDestName(ctrPath, ctr); isBindMount { //nolint(gocritic) + newMountPoint, path := pathWithBindMountSource(mount, ctrPath) + mountPoint = newMountPoint + ctrPath = path + } + + return mountPoint, ctrPath, nil +} + +func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) { + separator := string(os.PathSeparator) + + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, separator) + } + + if path == "" { + return false, "", "" + } + + for _, vol := range ctr.Config().NamedVolumes { + volNamePath := strings.TrimPrefix(vol.Dest, separator) + if matchVolumePath(path, volNamePath) { + return true, vol.Dest, vol.Name + } + } + + return false, "", "" +} + +func pathWithVolumeMount(runtime *libpod.Runtime, volDestName, volName, path string) (string, string, error) { + destVolume, err := runtime.GetVolume(volName) + if err != nil { + return "", "", errors.Wrapf(err, "error getting volume destination %s", volName) + } + + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + + return destVolume.MountPoint(), strings.TrimPrefix(path, volDestName), err +} + +func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) { + separator := string(os.PathSeparator) + + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, string(os.PathSeparator)) + } + + if path == "" { + return false, specs.Mount{} + } + + for _, m := range ctr.Config().Spec.Mounts { + if m.Type != "bind" { + continue + } + + mDest := strings.TrimPrefix(m.Destination, separator) + if matchVolumePath(path, mDest) { + return true, m + } + } + + return false, specs.Mount{} +} + +func matchVolumePath(path, target string) bool { + pathStr := filepath.Clean(path) + target = filepath.Clean(target) + + for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) { + pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))] + } + + return pathStr == target +} + +func pathWithBindMountSource(m specs.Mount, path string) (string, string) { + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + + return m.Source, strings.TrimPrefix(path, m.Destination) } diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index 185b724fc..1439a3a75 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -1,14 +1,11 @@ package utils import ( - "context" "net/http" "time" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/domain/entities" - createconfig "github.com/containers/podman/v2/pkg/spec" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -59,18 +56,3 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { } return con.WaitForConditionWithInterval(interval, condition) } - -func CreateContainer(ctx context.Context, w http.ResponseWriter, runtime *libpod.Runtime, cc *createconfig.CreateConfig) { - var pod *libpod.Pod - ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, runtime, cc, pod) - if err != nil { - Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "CreateContainerFromCreateConfig()")) - return - } - - response := entities.ContainerCreateResponse{ - ID: ctr.ID(), - Warnings: []string{}} - - WriteResponse(w, http.StatusCreated, response) -} diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go index ed40a37ab..b4e8446cb 100644 --- a/pkg/domain/entities/container_ps.go +++ b/pkg/domain/entities/container_ps.go @@ -3,6 +3,7 @@ package entities import ( "sort" "strings" + "time" "github.com/containers/podman/v2/pkg/ps/define" "github.com/cri-o/ocicni/pkg/ocicni" @@ -14,7 +15,7 @@ type ListContainer struct { // Container command Command []string // Container creation time - Created int64 + Created time.Time // Human readable container creation time. CreatedAt string // If container has exited/stopped @@ -137,7 +138,7 @@ func (a psSortedSize) Less(i, j int) bool { type PsSortedCreateTime struct{ SortListContainers } func (a PsSortedCreateTime) Less(i, j int) bool { - return a.SortListContainers[i].Created < a.SortListContainers[j].Created + return a.SortListContainers[i].Created.Before(a.SortListContainers[j].Created) } func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainers, error) { diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index b051d3eec..df7da616a 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -75,7 +75,6 @@ type ContainerEngine interface { Shutdown(ctx context.Context) SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error) Unshare(ctx context.Context, args []string) error - VarlinkService(ctx context.Context, opts ServiceOptions) error Version(ctx context.Context) (*SystemVersionReport, error) VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error) VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error) diff --git a/pkg/domain/infra/abi/system_novalink.go b/pkg/domain/infra/abi/system_novalink.go deleted file mode 100644 index 3518e9db6..000000000 --- a/pkg/domain/infra/abi/system_novalink.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build !varlink - -package abi - -import ( - "context" - - "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/pkg/errors" -) - -func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error { - return errors.Errorf("varlink is not supported") -} diff --git a/pkg/domain/infra/abi/system_varlink.go b/pkg/domain/infra/abi/system_varlink.go deleted file mode 100644 index ead84fc84..000000000 --- a/pkg/domain/infra/abi/system_varlink.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build varlink - -package abi - -import ( - "context" - - "github.com/containers/podman/v2/pkg/domain/entities" - iopodman "github.com/containers/podman/v2/pkg/varlink" - iopodmanAPI "github.com/containers/podman/v2/pkg/varlinkapi" - "github.com/containers/podman/v2/version" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/varlink/go/varlink" -) - -func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error { - var varlinkInterfaces = []*iopodman.VarlinkInterface{ - iopodmanAPI.New(opts.Command, ic.Libpod), - } - - service, err := varlink.NewService( - "Atomic", - "podman", - version.Version.String(), - "https://github.com/containers/podman", - ) - if err != nil { - return errors.Wrapf(err, "unable to create new varlink service") - } - - for _, i := range varlinkInterfaces { - if err := service.RegisterInterface(i); err != nil { - return errors.Errorf("unable to register varlink interface %v", i) - } - } - - // Run the varlink server at the given address - if err = service.Listen(opts.URI, opts.Timeout); err != nil { - switch err.(type) { - case varlink.ServiceTimeoutError: - logrus.Infof("varlink service expired (use --time to increase session time beyond %s ms, 0 means never timeout)", opts.Timeout.String()) - return nil - default: - return errors.Wrapf(err, "unable to start varlink service") - } - } - return nil -} diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go index c276e15c5..f3e8fbcb1 100644 --- a/pkg/domain/infra/tunnel/system.go +++ b/pkg/domain/infra/tunnel/system.go @@ -14,10 +14,6 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { return system.Info(ic.ClientCxt) } -func (ic *ContainerEngine) VarlinkService(_ context.Context, _ entities.ServiceOptions) error { - panic(errors.New("varlink service is not supported when tunneling")) -} - func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error { panic(errors.New("rootless engine mode is not supported when tunneling")) } diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index 3dd7eb0c6..cfdf3ee49 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -180,7 +180,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities ps := entities.ListContainer{ Command: conConfig.Command, - Created: conConfig.CreatedTime.Unix(), + Created: conConfig.CreatedTime, Exited: exited, ExitCode: exitCode, ExitedAt: exitedTime.Unix(), @@ -231,7 +231,7 @@ func ListStorageContainer(rt *libpod.Runtime, ctr storage.Container, opts entiti ps := entities.ListContainer{ ID: ctr.ID, - Created: ctr.Created.Unix(), + Created: ctr.Created, ImageID: ctr.ImageID, State: "storage", Names: []string{name}, @@ -301,5 +301,5 @@ func (a SortPSContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type SortPSCreateTime struct{ SortPSContainers } func (a SortPSCreateTime) Less(i, j int) bool { - return a.SortPSContainers[i].Created > a.SortPSContainers[j].Created + return a.SortPSContainers[i].Created.Before(a.SortPSContainers[j].Created) } diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go deleted file mode 100644 index 319cce61f..000000000 --- a/pkg/spec/config_linux.go +++ /dev/null @@ -1,371 +0,0 @@ -// +build linux - -package createconfig - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/containers/podman/v2/pkg/rootless" - "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/pkg/errors" - "golang.org/x/sys/unix" -) - -// 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)), - } -} - -// DevicesFromPath computes a list of devices -func DevicesFromPath(g *generate.Generator, devicePath string) error { - devs := strings.Split(devicePath, ":") - resolvedDevicePath := devs[0] - // check if it is a symbolic link - if src, err := os.Lstat(resolvedDevicePath); err == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink { - if linkedPathOnHost, err := filepath.EvalSymlinks(resolvedDevicePath); err == nil { - resolvedDevicePath = linkedPathOnHost - } - } - st, err := os.Stat(resolvedDevicePath) - if err != nil { - return errors.Wrapf(err, "cannot stat %s", devicePath) - } - if st.IsDir() { - found := false - src := resolvedDevicePath - dest := src - var devmode string - if len(devs) > 1 { - if len(devs[1]) > 0 && devs[1][0] == '/' { - dest = devs[1] - } else { - devmode = devs[1] - } - } - if len(devs) > 2 { - if devmode != "" { - return errors.Wrapf(unix.EINVAL, "invalid device specification %s", devicePath) - } - devmode = devs[2] - } - - // mount the internal devices recursively - if err := filepath.Walk(resolvedDevicePath, func(dpath string, f os.FileInfo, e error) error { - - if f.Mode()&os.ModeDevice == os.ModeDevice { - found = true - device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src))) - if devmode != "" { - device = fmt.Sprintf("%s:%s", device, devmode) - } - if err := addDevice(g, device); err != nil { - return errors.Wrapf(err, "failed to add %s device", dpath) - } - } - return nil - }); err != nil { - return err - } - if !found { - return errors.Wrapf(unix.EINVAL, "no devices found in %s", devicePath) - } - return nil - } - - return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":")) -} - -func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error { - for _, deviceCgroupRule := range deviceCgroupRules { - if err := validateDeviceCgroupRule(deviceCgroupRule); err != nil { - return err - } - ss := parseDeviceCgroupRule(deviceCgroupRule) - if len(ss[0]) != 5 { - return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule) - } - matches := ss[0] - var major, minor *int64 - if matches[2] == "*" { - majorDev := int64(-1) - major = &majorDev - } else { - majorDev, err := strconv.ParseInt(matches[2], 10, 64) - if err != nil { - return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule) - } - major = &majorDev - } - if matches[3] == "*" { - minorDev := int64(-1) - minor = &minorDev - } else { - minorDev, err := strconv.ParseInt(matches[2], 10, 64) - if err != nil { - return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule) - } - minor = &minorDev - } - g.AddLinuxResourcesDevice(true, matches[1], major, minor, matches[4]) - } - return nil -} - -func addDevice(g *generate.Generator, device string) error { - src, dst, permissions, err := ParseDevice(device) - if err != nil { - return err - } - dev, err := devices.DeviceFromPath(src, permissions) - if err != nil { - return errors.Wrapf(err, "%s is not a valid device", src) - } - if rootless.IsRootless() { - if _, err := os.Stat(src); err != nil { - if os.IsNotExist(err) { - return errors.Wrapf(err, "the specified device %s doesn't exist", src) - } - return errors.Wrapf(err, "stat device %s exist", src) - } - perm := "ro" - if strings.Contains(permissions, "w") { - perm = "rw" - } - devMnt := spec.Mount{ - Destination: dst, - Type: TypeBind, - Source: src, - Options: []string{"slave", "nosuid", "noexec", perm, "rbind"}, - } - g.Config.Mounts = append(g.Config.Mounts, devMnt) - return nil - } - dev.Path = dst - 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, string(dev.Permissions)) - return nil -} - -// based on getDevices from runc (libcontainer/devices/devices.go) -func getDevices(path string) ([]*configs.Device, error) { - files, err := ioutil.ReadDir(path) - if err != nil { - if rootless.IsRootless() && os.IsPermission(err) { - return nil, nil - } - return nil, err - } - out := []*configs.Device{} - for _, f := range files { - switch { - case f.IsDir(): - switch f.Name() { - // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 - case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts": - continue - default: - sub, err := getDevices(filepath.Join(path, f.Name())) - if err != nil { - return nil, err - } - if sub != nil { - out = append(out, sub...) - } - continue - } - case f.Name() == "console": - continue - case f.Mode()&os.ModeSymlink != 0: - // do not add symlink'd devices to privileged devices - continue - } - device, err := devices.DeviceFromPath(filepath.Join(path, f.Name()), "rwm") - if err != nil { - if err == devices.ErrNotADevice { - continue - } - if os.IsNotExist(err) { - continue - } - return nil, err - } - out = append(out, device) - } - return out, nil -} - -func addPrivilegedDevices(g *generate.Generator) error { - hostDevices, err := getDevices("/dev") - if err != nil { - return err - } - g.ClearLinuxDevices() - - if rootless.IsRootless() { - mounts := make(map[string]interface{}) - for _, m := range g.Mounts() { - mounts[m.Destination] = true - } - newMounts := []spec.Mount{} - for _, d := range hostDevices { - devMnt := spec.Mount{ - Destination: d.Path, - Type: TypeBind, - Source: d.Path, - Options: []string{"slave", "nosuid", "noexec", "rw", "rbind"}, - } - if d.Path == "/dev/ptmx" || strings.HasPrefix(d.Path, "/dev/tty") { - continue - } - if _, found := mounts[d.Path]; found { - continue - } - st, err := os.Stat(d.Path) - if err != nil { - if err == unix.EPERM { - continue - } - return errors.Wrapf(err, "stat %s", d.Path) - } - // Skip devices that the user has not access to. - if st.Mode()&0007 == 0 { - continue - } - newMounts = append(newMounts, devMnt) - } - g.Config.Mounts = append(newMounts, g.Config.Mounts...) - g.Config.Linux.Resources.Devices = nil - } else { - for _, d := range hostDevices { - g.AddDevice(Device(d)) - } - // Add resources device - need to clear the existing one first. - g.Config.Linux.Resources.Devices = nil - g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") - } - - return nil -} - -func (c *CreateConfig) createBlockIO() (*spec.LinuxBlockIO, error) { - var ret *spec.LinuxBlockIO - bio := &spec.LinuxBlockIO{} - if c.Resources.BlkioWeight > 0 { - ret = bio - bio.Weight = &c.Resources.BlkioWeight - } - if len(c.Resources.BlkioWeightDevice) > 0 { - var lwds []spec.LinuxWeightDevice - ret = bio - for _, i := range c.Resources.BlkioWeightDevice { - wd, err := ValidateweightDevice(i) - if err != nil { - return ret, errors.Wrapf(err, "invalid values for blkio-weight-device") - } - wdStat, err := GetStatFromPath(wd.Path) - if err != nil { - return ret, 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 { - ret = bio - readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps) - if err != nil { - return ret, err - } - bio.ThrottleReadBpsDevice = readBps - } - if len(c.Resources.DeviceWriteBps) > 0 { - ret = bio - writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps) - if err != nil { - return ret, err - } - bio.ThrottleWriteBpsDevice = writeBpds - } - if len(c.Resources.DeviceReadIOps) > 0 { - ret = bio - readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops) - if err != nil { - return ret, err - } - bio.ThrottleReadIOPSDevice = readIOps - } - if len(c.Resources.DeviceWriteIOps) > 0 { - ret = bio - writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops) - if err != nil { - return ret, err - } - bio.ThrottleWriteIOPSDevice = writeIOps - } - return ret, 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 -} - -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/config_linux_cgo.go b/pkg/spec/config_linux_cgo.go deleted file mode 100644 index d0891b574..000000000 --- a/pkg/spec/config_linux_cgo.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build linux,cgo - -package createconfig - -import ( - "io/ioutil" - - goSeccomp "github.com/containers/common/pkg/seccomp" - "github.com/containers/podman/v2/pkg/seccomp" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { - var seccompConfig *spec.LinuxSeccomp - var err error - - if config.SeccompPolicy == seccomp.PolicyImage && config.SeccompProfileFromImage != "" { - logrus.Debug("Loading seccomp profile from the security config") - seccompConfig, err = goSeccomp.LoadProfile(config.SeccompProfileFromImage, configSpec) - if err != nil { - return nil, errors.Wrap(err, "loading seccomp profile failed") - } - return seccompConfig, nil - } - - if config.SeccompProfilePath != "" { - logrus.Debugf("Loading seccomp profile from %q", config.SeccompProfilePath) - seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath) - if err != nil { - return nil, errors.Wrap(err, "opening seccomp profile failed") - } - seccompConfig, err = goSeccomp.LoadProfile(string(seccompProfile), configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) - } - } else { - logrus.Debug("Loading default seccomp profile") - seccompConfig, err = goSeccomp.GetDefaultProfile(configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading default seccomp profile failed") - } - } - - return seccompConfig, nil -} diff --git a/pkg/spec/config_linux_nocgo.go b/pkg/spec/config_linux_nocgo.go deleted file mode 100644 index 8d720b6d4..000000000 --- a/pkg/spec/config_linux_nocgo.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build linux,!cgo - -package createconfig - -import ( - spec "github.com/opencontainers/runtime-spec/specs-go" -) - -func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { - return nil, nil -} diff --git a/pkg/spec/config_unsupported.go b/pkg/spec/config_unsupported.go deleted file mode 100644 index 568afde55..000000000 --- a/pkg/spec/config_unsupported.go +++ /dev/null @@ -1,36 +0,0 @@ -// +build !linux - -package createconfig - -import ( - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/pkg/errors" -) - -func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { - return nil, errors.New("function not supported on non-linux OS's") -} -func addDevice(g *generate.Generator, device string) error { - return errors.New("function not implemented") -} - -func addPrivilegedDevices(g *generate.Generator) error { - return errors.New("function not implemented") -} - -func (c *CreateConfig) createBlockIO() (*spec.LinuxBlockIO, error) { - return nil, errors.New("function not implemented") -} - -func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) { - return nil, errors.New("function not implemented") -} - -func DevicesFromPath(g *generate.Generator, devicePath string) error { - return errors.New("function not implemented") -} - -func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error { - return errors.New("function not implemented") -} diff --git a/pkg/spec/containerconfig.go b/pkg/spec/containerconfig.go deleted file mode 100644 index f11d85b7e..000000000 --- a/pkg/spec/containerconfig.go +++ /dev/null @@ -1,41 +0,0 @@ -package createconfig - -import ( - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// MakeContainerConfig generates all configuration necessary to start a -// container with libpod from a completed CreateConfig struct. -func (config *CreateConfig) MakeContainerConfig(runtime *libpod.Runtime, pod *libpod.Pod) (*spec.Spec, []libpod.CtrCreateOption, error) { - if config.Pod != "" && pod == nil { - return nil, nil, errors.Wrapf(define.ErrInvalidArg, "pod was specified but no pod passed") - } else if config.Pod == "" && pod != nil { - return nil, nil, errors.Wrapf(define.ErrInvalidArg, "pod was given but no pod is specified") - } - - // Parse volumes flag into OCI spec mounts and libpod Named Volumes. - // If there is an identical mount in the OCI spec, we will replace it - // with a mount generated here. - mounts, namedVolumes, err := config.parseVolumes(runtime) - if err != nil { - return nil, nil, err - } - - runtimeSpec, err := config.createConfigToOCISpec(runtime, mounts) - if err != nil { - return nil, nil, err - } - - options, err := config.getContainerCreateOptions(runtime, pod, mounts, namedVolumes) - if err != nil { - return nil, nil, err - } - - logrus.Debugf("created OCI spec and options for new container") - - return runtimeSpec, options, nil -} diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go deleted file mode 100644 index 4887e9262..000000000 --- a/pkg/spec/createconfig.go +++ /dev/null @@ -1,426 +0,0 @@ -package createconfig - -import ( - "context" - "os" - "strconv" - "strings" - "syscall" - - "github.com/containers/image/v5/manifest" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/namespaces" - "github.com/containers/podman/v2/pkg/seccomp" - "github.com/containers/storage" - "github.com/docker/go-connections/nat" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// Type constants -const ( - bps = iota - iops -) - -// CreateResourceConfig represents resource elements in CreateConfig -// structures -type CreateResourceConfig struct { - BlkioWeight uint16 // blkio-weight - BlkioWeightDevice []string // blkio-weight-device - CgroupConf map[string]string - 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 - DeviceCgroupRules []string //device-cgroup-rule - 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 -} - -// PidConfig configures the pid namespace for the container -type PidConfig struct { - PidMode namespaces.PidMode //pid -} - -// IpcConfig configures the ipc namespace for the container -type IpcConfig struct { - IpcMode namespaces.IpcMode //ipc -} - -// CgroupConfig configures the cgroup namespace for the container -type CgroupConfig struct { - Cgroups string - Cgroupns string - CgroupParent string // cgroup-parent - CgroupMode namespaces.CgroupMode //cgroup -} - -// UserConfig configures the user namespace for the container -type UserConfig struct { - GroupAdd []string // group-add - IDMappings *storage.IDMappingOptions - UsernsMode namespaces.UsernsMode //userns - User string //user -} - -// UtsConfig configures the uts namespace for the container -type UtsConfig struct { - UtsMode namespaces.UTSMode //uts - NoHosts bool - HostAdd []string //add-host - Hostname string -} - -// NetworkConfig configures the network namespace for the container -type NetworkConfig struct { - DNSOpt []string //dns-opt - DNSSearch []string //dns-search - DNSServers []string //dns - ExposedPorts map[nat.Port]struct{} - HTTPProxy bool - IP6Address string //ipv6 - IPAddress string //ip - LinkLocalIP []string // link-local-ip - MacAddress string //mac-address - NetMode namespaces.NetworkMode //net - Network string //network - NetworkAlias []string //network-alias - PortBindings nat.PortMap - Publish []string //publish - PublishAll bool //publish-all -} - -// SecurityConfig configures the security features for the container -type SecurityConfig struct { - CapAdd []string // cap-add - CapDrop []string // cap-drop - CapRequired []string // cap-required - LabelOpts []string //SecurityOpts - NoNewPrivs bool //SecurityOpts - ApparmorProfile string //SecurityOpts - SeccompProfilePath string //SecurityOpts - SeccompProfileFromImage string // seccomp profile from the container image - SeccompPolicy seccomp.Policy - SecurityOpts []string - Privileged bool //privileged - ReadOnlyRootfs bool //read-only - ReadOnlyTmpfs bool //read-only-tmpfs - Sysctl map[string]string //sysctl - ProcOpts []string -} - -// CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI -// swagger:model CreateConfig -type CreateConfig struct { - Annotations map[string]string - Args []string - CidFile string - ConmonPidFile string - Command []string // Full command that will be used - UserCommand []string // User-entered command (or image CMD) - Detach bool // detach - Devices []string // device - Entrypoint []string //entrypoint - Env map[string]string //env - HealthCheck *manifest.Schema2HealthConfig - Init bool // init - InitPath string //init-path - Image string - ImageID string - RawImageName string - BuiltinImgVolumes map[string]struct{} // volumes defined in the image config - ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore - Interactive bool //interactive - Labels map[string]string //label - LogDriver string // log-driver - LogDriverOpt []string // log-opt - Name string //name - PodmanPath string - Pod string //pod - Quiet bool //quiet - Resources CreateResourceConfig - RestartPolicy string - Rm bool //rm - Rmi bool //rmi - StopSignal syscall.Signal // stop-signal - StopTimeout uint // stop-timeout - Systemd bool - Tmpfs []string // tmpfs - Tty bool //tty - Mounts []spec.Mount - MountsFlag []string // mounts - NamedVolumes []*libpod.ContainerNamedVolume - Volumes []string //volume - VolumesFrom []string - WorkDir string //workdir - Rootfs string - Security SecurityConfig - Syslog bool // Whether to enable syslog on exit commands - - // Namespaces - Pid PidConfig - Ipc IpcConfig - Cgroup CgroupConfig - User UserConfig - Uts UtsConfig - Network NetworkConfig -} - -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) { - return c.createBlockIO() -} - -func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, error) { - config, err := runtime.GetConfig() - if err != nil { - return nil, err - } - storageConfig := runtime.StorageConfig() - - // We need a cleanup process for containers in the current model. - // But we can't assume that the caller is Podman - it could be another - // user of the API. - // As such, provide a way to specify a path to Podman, so we can - // still invoke a cleanup process. - cmd := c.PodmanPath - if cmd == "" { - cmd, _ = os.Executable() - } - - command := []string{cmd, - "--root", storageConfig.GraphRoot, - "--runroot", storageConfig.RunRoot, - "--log-level", logrus.GetLevel().String(), - "--cgroup-manager", config.Engine.CgroupManager, - "--tmpdir", config.Engine.TmpDir, - } - if config.Engine.OCIRuntime != "" { - command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...) - } - if storageConfig.GraphDriverName != "" { - command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...) - } - for _, opt := range storageConfig.GraphDriverOptions { - command = append(command, []string{"--storage-opt", opt}...) - } - if config.Engine.EventsLogger != "" { - command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...) - } - - if c.Syslog { - command = append(command, "--syslog", "true") - } - command = append(command, []string{"container", "cleanup"}...) - - if c.Rm { - command = append(command, "--rm") - } - - if c.Rmi { - command = append(command, "--rmi") - } - - return command, nil -} - -// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions -func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) { - var options []libpod.CtrCreateOption - var err error - - if c.Interactive { - options = append(options, libpod.WithStdin()) - } - if c.Systemd { - options = append(options, libpod.WithSystemd()) - } - if c.Name != "" { - logrus.Debugf("setting container name %s", c.Name) - options = append(options, libpod.WithName(c.Name)) - } - if c.Pod != "" { - logrus.Debugf("adding container to pod %s", c.Pod) - options = append(options, runtime.WithPod(pod)) - } - - // handle some spec from the InfraContainer when it's a pod - if pod != nil && pod.HasInfraContainer() { - InfraCtr, err := pod.InfraContainer() - if err != nil { - return nil, err - } - // handle the pod.spec.hostAliases - options = append(options, libpod.WithHosts(InfraCtr.HostsAdd())) - } - - if len(mounts) != 0 || len(namedVolumes) != 0 { - destinations := []string{} - - // Take all mount and named volume destinations. - for _, mount := range mounts { - destinations = append(destinations, mount.Destination) - } - for _, volume := range namedVolumes { - destinations = append(destinations, volume.Dest) - } - - options = append(options, libpod.WithUserVolumes(destinations)) - } - - if len(namedVolumes) != 0 { - options = append(options, libpod.WithNamedVolumes(namedVolumes)) - } - - if len(c.UserCommand) != 0 { - options = append(options, libpod.WithCommand(c.UserCommand)) - } - - // Add entrypoint if it was set - // If it's empty it's because it was explicitly set to "" - if c.Entrypoint != nil { - options = append(options, libpod.WithEntrypoint(c.Entrypoint)) - } - - // TODO: MNT, USER, CGROUP - options = append(options, libpod.WithStopSignal(c.StopSignal)) - options = append(options, libpod.WithStopTimeout(c.StopTimeout)) - - logPath, logTag := getLoggingOpts(c.LogDriverOpt) - if logPath != "" { - options = append(options, libpod.WithLogPath(logPath)) - } - if logTag != "" { - options = append(options, libpod.WithLogTag(logTag)) - } - - if c.LogDriver != "" { - options = append(options, libpod.WithLogDriver(c.LogDriver)) - } - - secOpts, err := c.Security.ToCreateOptions() - if err != nil { - return nil, err - } - options = append(options, secOpts...) - - nsOpts, err := c.Cgroup.ToCreateOptions(runtime) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - nsOpts, err = c.Ipc.ToCreateOptions(runtime) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - nsOpts, err = c.Pid.ToCreateOptions(runtime) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - nsOpts, err = c.Uts.ToCreateOptions(runtime, pod) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - nsOpts, err = c.User.ToCreateOptions(runtime) - if err != nil { - return nil, err - } - options = append(options, nsOpts...) - - // Gather up the options for NewContainer which consist of With... funcs - options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, c.RawImageName)) - options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile)) - options = append(options, libpod.WithLabels(c.Labels)) - options = append(options, libpod.WithShmSize(c.Resources.ShmSize)) - if c.Rootfs != "" { - options = append(options, libpod.WithRootFS(c.Rootfs)) - } - // Default used if not overridden on command line - - if c.RestartPolicy != "" { - if c.RestartPolicy == "unless-stopped" { - return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported") - } - - split := strings.Split(c.RestartPolicy, ":") - if len(split) > 1 { - numTries, err := strconv.Atoi(split[1]) - if err != nil { - return nil, errors.Wrapf(err, "%s is not a valid number of retries for restart policy", split[1]) - } - if numTries < 0 { - return nil, errors.Wrapf(define.ErrInvalidArg, "restart policy requires a positive number of retries") - } - options = append(options, libpod.WithRestartRetries(uint(numTries))) - } - options = append(options, libpod.WithRestartPolicy(split[0])) - } - - // Always use a cleanup process to clean up Podman after termination - exitCmd, err := c.createExitCommand(runtime) - if err != nil { - return nil, err - } - options = append(options, libpod.WithExitCommand(exitCmd)) - - if c.HealthCheck != nil { - options = append(options, libpod.WithHealthCheck(c.HealthCheck)) - logrus.Debugf("New container has a health check") - } - return options, nil -} - -// AddPrivilegedDevices iterates through host devices and adds all -// host devices to the spec -func AddPrivilegedDevices(g *generate.Generator) error { - return addPrivilegedDevices(g) -} - -func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *CreateConfig, pod *libpod.Pod) (*libpod.Container, error) { - runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod) - if err != nil { - return nil, err - } - - ctr, err := r.NewContainer(ctx, runtimeSpec, options...) - if err != nil { - return nil, err - } - return ctr, nil -} diff --git a/pkg/spec/namespaces.go b/pkg/spec/namespaces.go deleted file mode 100644 index 8f98a9786..000000000 --- a/pkg/spec/namespaces.go +++ /dev/null @@ -1,463 +0,0 @@ -package createconfig - -import ( - "net" - "os" - "strconv" - "strings" - - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/cgroups" - "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/docker/go-connections/nat" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// DefaultKernelNamespaces is a comma-separated list of default kernel -// namespaces. -const DefaultKernelNamespaces = "cgroup,ipc,net,uts" - -// ToCreateOptions converts the input to a slice of container create options. -func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserConfig) ([]libpod.CtrCreateOption, error) { - var portBindings []ocicni.PortMapping - var err error - if len(c.PortBindings) > 0 { - portBindings, err = NatToOCIPortBindings(c.PortBindings) - if err != nil { - return nil, errors.Wrapf(err, "unable to create port bindings") - } - } - - options := make([]libpod.CtrCreateOption, 0) - userNetworks := c.NetMode.UserDefined() - networks := make([]string, 0) - - if IsPod(userNetworks) { - userNetworks = "" - } - if userNetworks != "" { - for _, netName := range strings.Split(userNetworks, ",") { - if netName == "" { - return nil, errors.Errorf("container networks %q invalid", userNetworks) - } - networks = append(networks, netName) - } - } - - switch { - case c.NetMode.IsNS(): - ns := c.NetMode.NS() - if ns == "" { - return nil, errors.Errorf("invalid empty user-defined network namespace") - } - _, err := os.Stat(ns) - if err != nil { - return nil, err - } - case c.NetMode.IsContainer(): - connectedCtr, err := runtime.LookupContainer(c.NetMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container()) - } - options = append(options, libpod.WithNetNSFrom(connectedCtr)) - case !c.NetMode.IsHost() && !c.NetMode.IsNone(): - postConfigureNetNS := userns.getPostConfigureNetNS() - options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks)) - } - - if len(c.DNSSearch) > 0 { - options = append(options, libpod.WithDNSSearch(c.DNSSearch)) - } - if len(c.DNSServers) > 0 { - if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" { - options = append(options, libpod.WithUseImageResolvConf()) - } else { - options = append(options, libpod.WithDNS(c.DNSServers)) - } - } - if len(c.DNSOpt) > 0 { - options = append(options, libpod.WithDNSOption(c.DNSOpt)) - } - if c.IPAddress != "" { - ip := net.ParseIP(c.IPAddress) - if ip == nil { - return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress) - } else if ip.To4() == nil { - return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress) - } - options = append(options, libpod.WithStaticIP(ip)) - } - - if c.MacAddress != "" { - mac, err := net.ParseMAC(c.MacAddress) - if err != nil { - return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err) - } - options = append(options, libpod.WithStaticMAC(mac)) - } - - return options, nil -} - -// ConfigureGenerator configures the generator based according to the current -// state of the NetworkConfig. -func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error { - netMode := c.NetMode - netCtr := netMode.Container() - switch { - case netMode.IsHost(): - logrus.Debug("Using host netmode") - if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil { - return err - } - case netMode.IsNone(): - logrus.Debug("Using none netmode") - case netMode.IsBridge(): - logrus.Debug("Using bridge netmode") - case netCtr != "": - logrus.Debugf("using container %s netmode", netCtr) - case IsNS(string(netMode)): - logrus.Debug("Using ns netmode") - if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode))); err != nil { - return err - } - case IsPod(string(netMode)): - logrus.Debug("Using pod netmode, unless pod is not sharing") - case netMode.IsSlirp4netns(): - logrus.Debug("Using slirp4netns netmode") - case netMode.IsUserDefined(): - logrus.Debug("Using user defined netmode") - default: - return errors.Errorf("unknown network mode") - } - - if c.HTTPProxy { - for _, envSpec := range []string{ - "http_proxy", - "HTTP_PROXY", - "https_proxy", - "HTTPS_PROXY", - "ftp_proxy", - "FTP_PROXY", - "no_proxy", - "NO_PROXY", - } { - envVal := os.Getenv(envSpec) - if envVal != "" { - g.AddProcessEnv(envSpec, envVal) - } - } - } - - if g.Config.Annotations == nil { - g.Config.Annotations = make(map[string]string) - } - - if c.PublishAll { - g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue - } else { - g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse - } - - return nil -} - -// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice -func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) { - var portBindings []ocicni.PortMapping - for containerPb, hostPb := range ports { - 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) - pm.Protocol = containerPb.Proto() - portBindings = append(portBindings, pm) - } - } - return portBindings, nil -} - -// ToCreateOptions converts the input to container create options. -func (c *CgroupConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - if c.CgroupMode.IsNS() { - ns := c.CgroupMode.NS() - if ns == "" { - return nil, errors.Errorf("invalid empty user-defined network namespace") - } - _, err := os.Stat(ns) - if err != nil { - return nil, err - } - } else if c.CgroupMode.IsContainer() { - connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container()) - } - options = append(options, libpod.WithCgroupNSFrom(connectedCtr)) - } - - if c.CgroupParent != "" { - options = append(options, libpod.WithCgroupParent(c.CgroupParent)) - } - - if c.Cgroups != "" { - options = append(options, libpod.WithCgroupsMode(c.Cgroups)) - } - - return options, nil -} - -// ToCreateOptions converts the input to container create options. -func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - switch { - case c.UsernsMode.IsNS(): - ns := c.UsernsMode.NS() - if ns == "" { - return nil, errors.Errorf("invalid empty user-defined user namespace") - } - _, err := os.Stat(ns) - if err != nil { - return nil, err - } - options = append(options, libpod.WithIDMappings(*c.IDMappings)) - case c.UsernsMode.IsContainer(): - connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container()) - } - options = append(options, libpod.WithUserNSFrom(connectedCtr)) - default: - options = append(options, libpod.WithIDMappings(*c.IDMappings)) - } - - options = append(options, libpod.WithUser(c.User)) - options = append(options, libpod.WithGroups(c.GroupAdd)) - - return options, nil -} - -// ConfigureGenerator configures the generator according to the current state -// of the UserConfig. -func (c *UserConfig) ConfigureGenerator(g *generate.Generator) error { - if IsNS(string(c.UsernsMode)) { - if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(c.UsernsMode))); err != nil { - return err - } - // runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping - g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1)) - g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1)) - } - - if (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() { - if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil { - return err - } - } - for _, uidmap := range c.IDMappings.UIDMap { - g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size)) - } - for _, gidmap := range c.IDMappings.GIDMap { - g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size)) - } - return nil -} - -func (c *UserConfig) getPostConfigureNetNS() bool { - hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0 - postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost() - return postConfigureNetNS -} - -// InNS returns true if the UserConfig indicates to be in a dedicated user -// namespace. -func (c *UserConfig) InNS(isRootless bool) bool { - hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0 - return isRootless || (hasUserns && !c.UsernsMode.IsHost()) -} - -// ToCreateOptions converts the input to container create options. -func (c *IpcConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - if c.IpcMode.IsHost() { - options = append(options, libpod.WithShmDir("/dev/shm")) - } else if c.IpcMode.IsContainer() { - connectedCtr, err := 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.WithShmDir(connectedCtr.ShmDir())) - } - - return options, nil -} - -// ConfigureGenerator configures the generator according to the current state -// of the IpcConfig. -func (c *IpcConfig) ConfigureGenerator(g *generate.Generator) error { - ipcMode := c.IpcMode - if IsNS(string(ipcMode)) { - return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode))) - } - if ipcMode.IsHost() { - return g.RemoveLinuxNamespace(string(spec.IPCNamespace)) - } - if ipcCtr := ipcMode.Container(); ipcCtr != "" { - logrus.Debugf("Using container %s ipcmode", ipcCtr) - } - - return nil -} - -// ConfigureGenerator configures the generator according to the current state -// of the CgroupConfig. -func (c *CgroupConfig) ConfigureGenerator(g *generate.Generator) error { - cgroupMode := c.CgroupMode - if cgroupMode.IsDefaultValue() { - // If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1. - unified, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - return err - } - if unified { - cgroupMode = "private" - } else { - cgroupMode = "host" - } - } - if cgroupMode.IsNS() { - return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode))) - } - if cgroupMode.IsHost() { - return g.RemoveLinuxNamespace(string(spec.CgroupNamespace)) - } - if cgroupMode.IsPrivate() { - return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "") - } - if cgCtr := cgroupMode.Container(); cgCtr != "" { - logrus.Debugf("Using container %s cgroup mode", cgCtr) - } - return nil -} - -// ToCreateOptions converts the input to container create options. -func (c *PidConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - if c.PidMode.IsContainer() { - connectedCtr, err := 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)) - } - - return options, nil -} - -// ConfigureGenerator configures the generator according to the current state -// of the PidConfig. -func (c *PidConfig) ConfigureGenerator(g *generate.Generator) error { - pidMode := c.PidMode - if IsNS(string(pidMode)) { - return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode))) - } - if pidMode.IsHost() { - return g.RemoveLinuxNamespace(string(spec.PIDNamespace)) - } - if pidCtr := pidMode.Container(); pidCtr != "" { - logrus.Debugf("using container %s pidmode", pidCtr) - } - if IsPod(string(pidMode)) { - logrus.Debug("using pod pidmode") - } - return nil -} - -// ToCreateOptions converts the input to container create options. -func (c *UtsConfig) ToCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - if IsPod(string(c.UtsMode)) { - options = append(options, libpod.WithUTSNSFromPod(pod)) - } - if c.UtsMode.IsContainer() { - connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container()) - } - - options = append(options, libpod.WithUTSNSFrom(connectedCtr)) - } - if c.NoHosts { - options = append(options, libpod.WithUseImageHosts()) - } - if len(c.HostAdd) > 0 && !c.NoHosts { - options = append(options, libpod.WithHosts(c.HostAdd)) - } - - return options, nil -} - -// ConfigureGenerator configures the generator according to the current state -// of the UtsConfig. -func (c *UtsConfig) ConfigureGenerator(g *generate.Generator, net *NetworkConfig, runtime *libpod.Runtime) error { - hostname := c.Hostname - utsCtrID := c.UtsMode.Container() - var err error - if hostname == "" { - switch { - case utsCtrID != "": - utsCtr, err := runtime.LookupContainer(utsCtrID) - if err != nil { - return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID) - } - hostname = utsCtr.Hostname() - case net.NetMode.IsHost() || c.UtsMode.IsHost(): - hostname, err = os.Hostname() - if err != nil { - return errors.Wrap(err, "unable to retrieve hostname of the host") - } - default: - logrus.Debug("No hostname set; container's hostname will default to runtime default") - } - } - g.RemoveHostname() - if c.Hostname != "" || !c.UtsMode.IsHost() { - // Set the hostname in the OCI configuration only - // if specified by the user or if we are creating - // a new UTS namespace. - g.SetHostname(hostname) - } - g.AddProcessEnv("HOSTNAME", hostname) - - utsMode := c.UtsMode - if IsNS(string(utsMode)) { - return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode))) - } - if utsMode.IsHost() { - return g.RemoveLinuxNamespace(string(spec.UTSNamespace)) - } - if utsCtr := utsMode.Container(); utsCtr != "" { - logrus.Debugf("using container %s utsmode", utsCtr) - } - return nil -} diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go deleted file mode 100644 index 9ebcf8d29..000000000 --- a/pkg/spec/parse.go +++ /dev/null @@ -1,225 +0,0 @@ -package createconfig - -import ( - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/docker/go-units" - "github.com/pkg/errors" -) - -// deviceCgroupRulegex defines the valid format of device-cgroup-rule -var deviceCgroupRuleRegex = regexp.MustCompile(`^([acb]) ([0-9]+|\*):([0-9]+|\*) ([rwm]{1,3})$`) - -// Pod signifies a kernel namespace is being shared -// by a container with the pod it is associated with -const Pod = "pod" - -// 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) -} - -// LinuxNS is a struct that contains namespace information -// It implemented Valid to show it is a valid namespace -type LinuxNS interface { - Valid() bool -} - -// IsNS returns if the specified string has a ns: prefix -func IsNS(s string) bool { - parts := strings.SplitN(s, ":", 2) - return len(parts) > 1 && parts[0] == "ns" -} - -// IsPod returns if the specified string is pod -func IsPod(s string) bool { - return s == Pod -} - -// Valid checks the validity of a linux namespace -// s should be the string representation of ns -func Valid(s string, ns LinuxNS) bool { - return IsPod(s) || IsNS(s) || ns.Valid() -} - -// NS is the path to the namespace to join. -func NS(s string) string { - parts := strings.SplitN(s, ":", 2) - if len(parts) > 1 { - return parts[1] - } - return "" -} - -// 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 <device-path>:<number>[<unit>]. 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 <device-path>:<number>[<unit>]. 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 <device-path>:<number>. Number must be a positive integer", val) - } - return &throttleDevice{ - path: split[0], - rate: rate, - }, nil -} - -// getLoggingOpts splits the path= and tag= options provided to --log-opt. -func getLoggingOpts(opts []string) (string, string) { - var path, tag string - for _, opt := range opts { - arr := strings.SplitN(opt, "=", 2) - if len(arr) == 2 { - if strings.TrimSpace(arr[0]) == "path" { - path = strings.TrimSpace(arr[1]) - } else if strings.TrimSpace(arr[0]) == "tag" { - tag = strings.TrimSpace(arr[1]) - } - } - if path != "" && tag != "" { - break - } - } - return path, tag -} - -// ParseDevice parses device mapping string to a src, dest & permissions string -func ParseDevice(device string) (string, string, string, error) { //nolint - src := "" - dst := "" - permissions := "rwm" - arr := strings.Split(device, ":") - switch len(arr) { - case 3: - if !IsValidDeviceMode(arr[2]) { - return "", "", "", fmt.Errorf("invalid device mode: %s", arr[2]) - } - permissions = arr[2] - fallthrough - case 2: - if IsValidDeviceMode(arr[1]) { - permissions = arr[1] - } else { - if len(arr[1]) == 0 || arr[1][0] != '/' { - return "", "", "", fmt.Errorf("invalid device mode: %s", arr[1]) - } - dst = arr[1] - } - fallthrough - case 1: - src = arr[0] - default: - return "", "", "", fmt.Errorf("invalid device specification: %s", device) - } - - if dst == "" { - dst = src - } - return src, dst, permissions, nil -} - -// IsValidDeviceMode checks if the mode for device is valid or not. -// IsValid mode is a composition of r (read), w (write), and m (mknod). -func IsValidDeviceMode(mode string) bool { - var legalDeviceMode = map[rune]bool{ - 'r': true, - 'w': true, - 'm': true, - } - if mode == "" { - return false - } - for _, c := range mode { - if !legalDeviceMode[c] { - return false - } - legalDeviceMode[c] = false - } - return true -} - -// validateDeviceCgroupRule validates the format of deviceCgroupRule -func validateDeviceCgroupRule(deviceCgroupRule string) error { - if !deviceCgroupRuleRegex.MatchString(deviceCgroupRule) { - return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule) - } - return nil -} - -// parseDeviceCgroupRule matches and parses the deviceCgroupRule into slice -func parseDeviceCgroupRule(deviceCgroupRule string) [][]string { - return deviceCgroupRuleRegex.FindAllStringSubmatch(deviceCgroupRule, -1) -} diff --git a/pkg/spec/ports.go b/pkg/spec/ports.go deleted file mode 100644 index bdd26bd83..000000000 --- a/pkg/spec/ports.go +++ /dev/null @@ -1,107 +0,0 @@ -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 <portnum>/[<proto>] or <startport-endport>/[<proto>] - _, 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 inputted 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 <portnum>/[<proto>] or <startport-endport>/[<proto>] - //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/security.go b/pkg/spec/security.go deleted file mode 100644 index 5f7db7edb..000000000 --- a/pkg/spec/security.go +++ /dev/null @@ -1,204 +0,0 @@ -package createconfig - -import ( - "fmt" - "strings" - - "github.com/containers/common/pkg/capabilities" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/util" - "github.com/opencontainers/runtime-tools/generate" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// ToCreateOptions convert the SecurityConfig to a slice of container create -// options. -func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) { - options := make([]libpod.CtrCreateOption, 0) - options = append(options, libpod.WithSecLabels(c.LabelOpts)) - options = append(options, libpod.WithPrivileged(c.Privileged)) - return options, nil -} - -// SetLabelOpts sets the label options of the SecurityConfig according to the -// input. -func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error { - if c.Privileged { - c.LabelOpts = label.DisableSecOpt() - return nil - } - - var labelOpts []string - if pidConfig.PidMode.IsHost() { - labelOpts = append(labelOpts, label.DisableSecOpt()...) - } else if pidConfig.PidMode.IsContainer() { - ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container()) - if err != nil { - return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container()) - } - secopts, err := label.DupSecOpt(ctr.ProcessLabel()) - if err != nil { - return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel()) - } - labelOpts = append(labelOpts, secopts...) - } - - if ipcConfig.IpcMode.IsHost() { - labelOpts = append(labelOpts, label.DisableSecOpt()...) - } else if ipcConfig.IpcMode.IsContainer() { - ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container()) - if err != nil { - return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container()) - } - secopts, err := label.DupSecOpt(ctr.ProcessLabel()) - if err != nil { - return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel()) - } - labelOpts = append(labelOpts, secopts...) - } - - c.LabelOpts = append(c.LabelOpts, labelOpts...) - return nil -} - -// SetSecurityOpts the the security options (labels, apparmor, seccomp, etc.). -func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error { - for _, opt := range securityOpts { - if opt == "no-new-privileges" { - c.NoNewPrivs = true - } else { - con := strings.SplitN(opt, "=", 2) - if len(con) != 2 { - return fmt.Errorf("invalid --security-opt 1: %q", opt) - } - - switch con[0] { - case "proc-opts": - c.ProcOpts = strings.Split(con[1], ",") - case "label": - c.LabelOpts = append(c.LabelOpts, con[1]) - case "apparmor": - c.ApparmorProfile = con[1] - case "seccomp": - c.SeccompProfilePath = con[1] - default: - return fmt.Errorf("invalid --security-opt 2: %q", opt) - } - } - } - - if c.SeccompProfilePath == "" { - var err error - c.SeccompProfilePath, err = libpod.DefaultSeccompPath() - if err != nil { - return err - } - } - c.SecurityOpts = securityOpts - return nil -} - -// ConfigureGenerator configures the generator according to the input. -func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error { - // HANDLE CAPABILITIES - // NOTE: Must happen before SECCOMP - if c.Privileged { - g.SetupPrivileged(true) - } - - useNotRoot := func(user string) bool { - if user == "" || user == "root" || user == "0" { - return false - } - return true - } - - configSpec := g.Config - var err error - var defaultCaplist []string - bounding := configSpec.Process.Capabilities.Bounding - if useNotRoot(user.User) { - configSpec.Process.Capabilities.Bounding = defaultCaplist - } - defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop) - if err != nil { - return err - } - - privCapRequired := []string{} - - if !c.Privileged && len(c.CapRequired) > 0 { - // Pass CapRequired in CapAdd field to normalize capabilities names - capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil) - if err != nil { - logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(c.CapRequired, ",")) - } else { - // Verify all capRequiered are in the defaultCapList - for _, cap := range capRequired { - if !util.StringInSlice(cap, defaultCaplist) { - privCapRequired = append(privCapRequired, cap) - } - } - } - if len(privCapRequired) == 0 { - defaultCaplist = capRequired - } else { - logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ",")) - } - } - configSpec.Process.Capabilities.Bounding = defaultCaplist - configSpec.Process.Capabilities.Permitted = defaultCaplist - configSpec.Process.Capabilities.Inheritable = defaultCaplist - configSpec.Process.Capabilities.Effective = defaultCaplist - configSpec.Process.Capabilities.Ambient = defaultCaplist - if useNotRoot(user.User) { - defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) - if err != nil { - return err - } - } - configSpec.Process.Capabilities.Bounding = defaultCaplist - - // HANDLE SECCOMP - if c.SeccompProfilePath != "unconfined" { - seccompConfig, err := getSeccompConfig(c, configSpec) - if err != nil { - return err - } - configSpec.Linux.Seccomp = seccompConfig - } - - // Clear default Seccomp profile from Generator for privileged containers - if c.SeccompProfilePath == "unconfined" || c.Privileged { - configSpec.Linux.Seccomp = nil - } - - for _, opt := range c.SecurityOpts { - // Split on both : and = - splitOpt := strings.SplitN(opt, "=", 2) - if len(splitOpt) == 1 { - splitOpt = strings.Split(opt, ":") - } - if len(splitOpt) < 2 { - continue - } - switch splitOpt[0] { - case "label": - configSpec.Annotations[define.InspectAnnotationLabel] = splitOpt[1] - case "seccomp": - configSpec.Annotations[define.InspectAnnotationSeccomp] = splitOpt[1] - case "apparmor": - configSpec.Annotations[define.InspectAnnotationApparmor] = splitOpt[1] - } - } - - g.SetRootReadonly(c.ReadOnlyRootfs) - for sysctlKey, sysctlVal := range c.Sysctl { - g.AddLinuxSysctl(sysctlKey, sysctlVal) - } - - return nil -} diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go deleted file mode 100644 index 81620997f..000000000 --- a/pkg/spec/spec.go +++ /dev/null @@ -1,593 +0,0 @@ -package createconfig - -import ( - "strings" - - "github.com/containers/common/pkg/capabilities" - cconfig "github.com/containers/common/pkg/config" - "github.com/containers/common/pkg/sysinfo" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/cgroups" - "github.com/containers/podman/v2/pkg/env" - "github.com/containers/podman/v2/pkg/rootless" - "github.com/containers/podman/v2/pkg/util" - "github.com/docker/go-units" - "github.com/opencontainers/runc/libcontainer/user" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -const CpuPeriod = 100000 - -func GetAvailableGids() (int64, error) { - idMap, err := user.ParseIDMapFile("/proc/self/gid_map") - if err != nil { - return 0, err - } - count := int64(0) - for _, r := range idMap { - count += r.Count - } - return count, nil -} - -// CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec -func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userMounts []spec.Mount) (*spec.Spec, error) { - cgroupPerm := "ro" - g, err := generate.New("linux") - if err != nil { - return nil, err - } - // Remove the default /dev/shm mount to ensure we overwrite it - g.RemoveMount("/dev/shm") - g.HostSpecific = true - addCgroup := true - canMountSys := true - - isRootless := rootless.IsRootless() - inUserNS := config.User.InNS(isRootless) - - if inUserNS && config.Network.NetMode.IsHost() { - canMountSys = false - } - - if config.Security.Privileged && canMountSys { - cgroupPerm = "rw" - g.RemoveMount("/sys") - sysMnt := spec.Mount{ - Destination: "/sys", - Type: "sysfs", - Source: "sysfs", - Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"}, - } - g.AddMount(sysMnt) - } else if !canMountSys { - addCgroup = false - g.RemoveMount("/sys") - r := "ro" - if config.Security.Privileged { - r = "rw" - } - sysMnt := spec.Mount{ - Destination: "/sys", - Type: TypeBind, - Source: "/sys", - Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"}, - } - g.AddMount(sysMnt) - if !config.Security.Privileged && isRootless { - g.AddLinuxMaskedPaths("/sys/kernel") - } - } - var runtimeConfig *cconfig.Config - - if runtime != nil { - runtimeConfig, err = runtime.GetConfig() - if err != nil { - return nil, err - } - g.Config.Process.Capabilities.Bounding = runtimeConfig.Containers.DefaultCapabilities - sysctls, err := util.ValidateSysctls(runtimeConfig.Containers.DefaultSysctls) - if err != nil { - return nil, err - } - - for name, val := range config.Security.Sysctl { - sysctls[name] = val - } - config.Security.Sysctl = sysctls - if !util.StringInSlice("host", config.Resources.Ulimit) { - config.Resources.Ulimit = append(runtimeConfig.Containers.DefaultUlimits, config.Resources.Ulimit...) - } - if config.Resources.PidsLimit < 0 && !config.cgroupDisabled() { - config.Resources.PidsLimit = runtimeConfig.Containers.PidsLimit - } - - } else { - g.Config.Process.Capabilities.Bounding = cconfig.DefaultCapabilities - if config.Resources.PidsLimit < 0 && !config.cgroupDisabled() { - config.Resources.PidsLimit = cconfig.DefaultPidsLimit - } - } - - gid5Available := true - if isRootless { - nGids, err := GetAvailableGids() - if err != nil { - return nil, err - } - gid5Available = nGids >= 5 - } - // When using a different user namespace, check that the GID 5 is mapped inside - // the container. - if gid5Available && len(config.User.IDMappings.GIDMap) > 0 { - mappingFound := false - for _, r := range config.User.IDMappings.GIDMap { - if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size { - mappingFound = true - break - } - } - if !mappingFound { - gid5Available = false - } - - } - if !gid5Available { - // If we have no GID mappings, the gid=5 default option would fail, so drop it. - g.RemoveMount("/dev/pts") - devPts := spec.Mount{ - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}, - } - g.AddMount(devPts) - } - - if inUserNS && config.Ipc.IpcMode.IsHost() { - g.RemoveMount("/dev/mqueue") - devMqueue := spec.Mount{ - Destination: "/dev/mqueue", - Type: TypeBind, - Source: "/dev/mqueue", - Options: []string{"bind", "nosuid", "noexec", "nodev"}, - } - g.AddMount(devMqueue) - } - if inUserNS && config.Pid.PidMode.IsHost() { - g.RemoveMount("/proc") - procMount := spec.Mount{ - Destination: "/proc", - Type: TypeBind, - Source: "/proc", - Options: []string{"rbind", "nosuid", "noexec", "nodev"}, - } - g.AddMount(procMount) - } - - if addCgroup { - cgroupMnt := spec.Mount{ - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm}, - } - g.AddMount(cgroupMnt) - } - g.SetProcessCwd(config.WorkDir) - - ProcessArgs := make([]string, 0) - // We need to iterate the input for entrypoint because it is a []string - // but "" is a legit json input, which translates into a []string with an - // empty position. This messes up the eventual command being executed - // in the container - for _, a := range config.Entrypoint { - if len(a) > 0 { - ProcessArgs = append(ProcessArgs, a) - } - } - // Same issue as explained above for config.Entrypoint. - for _, a := range config.Command { - if len(a) > 0 { - ProcessArgs = append(ProcessArgs, a) - } - } - - g.SetProcessArgs(ProcessArgs) - g.SetProcessTerminal(config.Tty) - - for key, val := range config.Annotations { - g.AddAnnotation(key, val) - } - - addedResources := false - - // RESOURCES - MEMORY - if config.Resources.Memory != 0 { - g.SetLinuxResourcesMemoryLimit(config.Resources.Memory) - // If a swap limit is not explicitly set, also set a swap limit - // Default to double the memory limit - if config.Resources.MemorySwap == 0 { - g.SetLinuxResourcesMemorySwap(2 * config.Resources.Memory) - } - addedResources = true - } - if config.Resources.MemoryReservation != 0 { - g.SetLinuxResourcesMemoryReservation(config.Resources.MemoryReservation) - addedResources = true - } - if config.Resources.MemorySwap != 0 { - g.SetLinuxResourcesMemorySwap(config.Resources.MemorySwap) - addedResources = true - } - if config.Resources.KernelMemory != 0 { - g.SetLinuxResourcesMemoryKernel(config.Resources.KernelMemory) - addedResources = true - } - if config.Resources.MemorySwappiness != -1 { - g.SetLinuxResourcesMemorySwappiness(uint64(config.Resources.MemorySwappiness)) - addedResources = true - } - g.SetLinuxResourcesMemoryDisableOOMKiller(config.Resources.DisableOomKiller) - g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj) - - // RESOURCES - CPU - if config.Resources.CPUShares != 0 { - g.SetLinuxResourcesCPUShares(config.Resources.CPUShares) - addedResources = true - } - if config.Resources.CPUQuota != 0 { - g.SetLinuxResourcesCPUQuota(config.Resources.CPUQuota) - addedResources = true - } - if config.Resources.CPUPeriod != 0 { - g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod) - addedResources = true - } - if config.Resources.CPUs != 0 { - g.SetLinuxResourcesCPUPeriod(CpuPeriod) - g.SetLinuxResourcesCPUQuota(int64(config.Resources.CPUs * CpuPeriod)) - addedResources = true - } - if config.Resources.CPURtRuntime != 0 { - g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime) - addedResources = true - } - if config.Resources.CPURtPeriod != 0 { - g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod) - addedResources = true - } - if config.Resources.CPUsetCPUs != "" { - g.SetLinuxResourcesCPUCpus(config.Resources.CPUsetCPUs) - addedResources = true - } - if config.Resources.CPUsetMems != "" { - g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems) - addedResources = true - } - - // Devices - if config.Security.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 := AddPrivilegedDevices(&g); err != nil { - return nil, err - } - } else { - for _, devicePath := range config.Devices { - if err := DevicesFromPath(&g, devicePath); err != nil { - return nil, err - } - } - if len(config.Resources.DeviceCgroupRules) != 0 { - if err := deviceCgroupRules(&g, config.Resources.DeviceCgroupRules); err != nil { - return nil, err - } - addedResources = true - } - } - - g.SetProcessNoNewPrivileges(config.Security.NoNewPrivs) - - if !config.Security.Privileged { - g.SetProcessApparmorProfile(config.Security.ApparmorProfile) - } - - // Unless already set via the CLI, check if we need to disable process - // labels or set the defaults. - if len(config.Security.LabelOpts) == 0 && runtimeConfig != nil { - if !runtimeConfig.Containers.EnableLabeling { - // Disabled in the config. - config.Security.LabelOpts = append(config.Security.LabelOpts, "disable") - } else if err := config.Security.SetLabelOpts(runtime, &config.Pid, &config.Ipc); err != nil { - // Defaults! - return nil, err - } - } - - BlockAccessToKernelFilesystems(config.Security.Privileged, config.Pid.PidMode.IsHost(), &g) - - // RESOURCES - PIDS - if config.Resources.PidsLimit > 0 { - // if running on rootless on a cgroupv1 machine or using the cgroupfs manager, pids - // limit is not supported. If the value is still the default - // then ignore the settings. If the caller asked for a - // non-default, then try to use it. - setPidLimit := true - if rootless.IsRootless() { - cgroup2, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - return nil, err - } - if (!cgroup2 || (runtimeConfig != nil && runtimeConfig.Engine.CgroupManager != cconfig.SystemdCgroupsManager)) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() { - setPidLimit = false - } - } - if setPidLimit { - g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit) - addedResources = true - } - } - - // Make sure to always set the default variables unless overridden in the - // config. - var defaultEnv map[string]string - if runtimeConfig == nil { - defaultEnv = env.DefaultEnvVariables() - } else { - defaultEnv, err = env.ParseSlice(runtimeConfig.Containers.Env) - if err != nil { - return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse") - } - defaultEnv = env.Join(env.DefaultEnvVariables(), defaultEnv) - } - - if err := addRlimits(config, &g); err != nil { - return nil, err - } - - // NAMESPACES - - if err := config.Pid.ConfigureGenerator(&g); err != nil { - return nil, err - } - - if err := config.User.ConfigureGenerator(&g); err != nil { - return nil, err - } - - if err := config.Network.ConfigureGenerator(&g); err != nil { - return nil, err - } - - if err := config.Uts.ConfigureGenerator(&g, &config.Network, runtime); err != nil { - return nil, err - } - - if err := config.Ipc.ConfigureGenerator(&g); err != nil { - return nil, err - } - - if err := config.Cgroup.ConfigureGenerator(&g); err != nil { - return nil, err - } - - config.Env = env.Join(defaultEnv, config.Env) - for name, val := range config.Env { - g.AddProcessEnv(name, val) - } - configSpec := g.Config - - // If the container image specifies an label with a - // capabilities.ContainerImageLabel then split the comma separated list - // of capabilities and record them. This list indicates the only - // capabilities, required to run the container. - var capRequired []string - for key, val := range config.Labels { - if util.StringInSlice(key, capabilities.ContainerImageLabels) { - capRequired = strings.Split(val, ",") - } - } - config.Security.CapRequired = capRequired - - if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil { - return nil, err - } - - // BIND MOUNTS - configSpec.Mounts = SupercedeUserMounts(userMounts, configSpec.Mounts) - // Process mounts to ensure correct options - if err := InitFSMounts(configSpec.Mounts); err != nil { - return nil, err - } - - // 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 - addedResources = true - } - - if rootless.IsRootless() { - cgroup2, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - return nil, err - } - if !addedResources { - configSpec.Linux.Resources = &spec.LinuxResources{} - } - - canUseResources := cgroup2 && runtimeConfig != nil && (runtimeConfig.Engine.CgroupManager == cconfig.SystemdCgroupsManager) - - if addedResources && !canUseResources { - return nil, errors.New("invalid configuration, cannot specify resource limits without cgroups v2 and --cgroup-manager=systemd") - } - if !canUseResources { - // Force the resources block to be empty instead of having default values. - configSpec.Linux.Resources = &spec.LinuxResources{} - } - } - - switch config.Cgroup.Cgroups { - case "disabled": - if addedResources { - return nil, errors.New("cannot specify resource limits when cgroups are disabled is specified") - } - configSpec.Linux.Resources = &spec.LinuxResources{} - case "enabled", "no-conmon", "": - // Do nothing - default: - return nil, errors.New("unrecognized option for cgroups; supported are 'default', 'disabled', 'no-conmon'") - } - - // Add annotations - if configSpec.Annotations == nil { - configSpec.Annotations = make(map[string]string) - } - - if config.CidFile != "" { - configSpec.Annotations[define.InspectAnnotationCIDFile] = config.CidFile - } - - if config.Rm { - configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue - } else { - configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse - } - - if len(config.VolumesFrom) > 0 { - configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",") - } - - if config.Security.Privileged { - configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue - } else { - configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse - } - - if config.Init { - configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue - } else { - configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse - } - - return configSpec, nil -} - -func (config *CreateConfig) cgroupDisabled() bool { - return config.Cgroup.Cgroups == "disabled" -} - -func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, g *generate.Generator) { - if !privileged { - for _, mp := range []string{ - "/proc/acpi", - "/proc/kcore", - "/proc/keys", - "/proc/latency_stats", - "/proc/timer_list", - "/proc/timer_stats", - "/proc/sched_debug", - "/proc/scsi", - "/sys/firmware", - "/sys/fs/selinux", - } { - g.AddLinuxMaskedPaths(mp) - } - - if pidModeIsHost && rootless.IsRootless() { - return - } - - for _, rp := range []string{ - "/proc/asound", - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger", - } { - g.AddLinuxReadonlyPaths(rp) - } - } -} - -func addRlimits(config *CreateConfig, g *generate.Generator) error { - var ( - isRootless = rootless.IsRootless() - nofileSet = false - nprocSet = false - ) - - for _, u := range config.Resources.Ulimit { - if u == "host" { - if len(config.Resources.Ulimit) != 1 { - return errors.New("ulimit can use host only once") - } - g.Config.Process.Rlimits = nil - break - } - - ul, err := units.ParseUlimit(u) - if err != nil { - return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u) - } - - if ul.Name == "nofile" { - nofileSet = true - } else if ul.Name == "nproc" { - nprocSet = true - } - - g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft)) - } - - // If not explicitly overridden by the user, default number of open - // files and number of processes to the maximum they can be set to - // (without overriding a sysctl) - if !nofileSet { - max := define.RLimitDefaultValue - current := define.RLimitDefaultValue - if isRootless { - var rlimit unix.Rlimit - if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit); err != nil { - logrus.Warnf("failed to return RLIMIT_NOFILE ulimit %q", err) - } - if rlimit.Cur < current { - current = rlimit.Cur - } - if rlimit.Max < max { - max = rlimit.Max - } - } - g.AddProcessRlimits("RLIMIT_NOFILE", max, current) - } - if !nprocSet { - max := define.RLimitDefaultValue - current := define.RLimitDefaultValue - if isRootless { - var rlimit unix.Rlimit - if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlimit); err != nil { - logrus.Warnf("failed to return RLIMIT_NPROC ulimit %q", err) - } - if rlimit.Cur < current { - current = rlimit.Cur - } - if rlimit.Max < max { - max = rlimit.Max - } - } - g.AddProcessRlimits("RLIMIT_NPROC", max, current) - } - - return nil -} diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go deleted file mode 100644 index d01102fa2..000000000 --- a/pkg/spec/spec_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package createconfig - -import ( - "runtime" - "testing" - - "github.com/containers/common/pkg/sysinfo" - "github.com/containers/podman/v2/pkg/cgroups" - "github.com/containers/podman/v2/pkg/rootless" - "github.com/containers/storage" - "github.com/containers/storage/pkg/idtools" - "github.com/docker/go-units" - "github.com/stretchr/testify/assert" -) - -var ( - sysInfo = sysinfo.New(true) -) - -// Make createconfig to test with -func makeTestCreateConfig() *CreateConfig { - cc := new(CreateConfig) - cc.Resources = CreateResourceConfig{} - cc.User.IDMappings = new(storage.IDMappingOptions) - cc.User.IDMappings.UIDMap = []idtools.IDMap{} - cc.User.IDMappings.GIDMap = []idtools.IDMap{} - - return cc -} - -func doCommonSkipChecks(t *testing.T) { - // The default configuration of podman enables seccomp, which is not available on non-Linux systems. - // Thus, any tests that use the default seccomp setting would fail. - // Skip the tests on non-Linux platforms rather than explicitly disable seccomp in the test and possibly affect the test result. - if runtime.GOOS != "linux" { - t.Skip("seccomp, which is enabled by default, is only supported on Linux") - } - - if rootless.IsRootless() { - isCgroupV2, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if !isCgroupV2 { - t.Skip("cgroups v1 cannot be used when rootless") - } - } -} - -// TestPIDsLimit verifies the given pid-limit is correctly defined in the spec -func TestPIDsLimit(t *testing.T) { - doCommonSkipChecks(t) - - if !sysInfo.PidsLimit { - t.Skip("running test not supported by the host system") - } - - cc := makeTestCreateConfig() - cc.Resources.PidsLimit = 22 - - spec, err := cc.createConfigToOCISpec(nil, nil) - assert.NoError(t, err) - - assert.Equal(t, spec.Linux.Resources.Pids.Limit, int64(22)) -} - -// TestBLKIOWeightDevice verifies the given blkio weight is correctly set in the -// spec. -func TestBLKIOWeightDevice(t *testing.T) { - doCommonSkipChecks(t) - - if !sysInfo.BlkioWeightDevice { - t.Skip("running test not supported by the host system") - } - - cc := makeTestCreateConfig() - cc.Resources.BlkioWeightDevice = []string{"/dev/zero:100"} - - spec, err := cc.createConfigToOCISpec(nil, nil) - assert.NoError(t, err) - - // /dev/zero is guaranteed 1,5 by the Linux kernel - assert.Equal(t, spec.Linux.Resources.BlockIO.WeightDevice[0].Major, int64(1)) - assert.Equal(t, spec.Linux.Resources.BlockIO.WeightDevice[0].Minor, int64(5)) - assert.Equal(t, *(spec.Linux.Resources.BlockIO.WeightDevice[0].Weight), uint16(100)) -} - -// TestMemorySwap verifies that the given swap memory limit is correctly set in -// the spec. -func TestMemorySwap(t *testing.T) { - doCommonSkipChecks(t) - - if !sysInfo.SwapLimit { - t.Skip("running test not supported by the host system") - } - - swapLimit, err := units.RAMInBytes("45m") - assert.NoError(t, err) - - cc := makeTestCreateConfig() - cc.Resources.MemorySwap = swapLimit - - spec, err := cc.createConfigToOCISpec(nil, nil) - assert.NoError(t, err) - - assert.Equal(t, *(spec.Linux.Resources.Memory.Swap), swapLimit) -} diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go deleted file mode 100644 index b441daf08..000000000 --- a/pkg/spec/storage.go +++ /dev/null @@ -1,875 +0,0 @@ -package createconfig - -import ( - "fmt" - "os" - "path" - "path/filepath" - "strings" - - "github.com/containers/buildah/pkg/parse" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/pkg/util" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -const ( - // TypeBind is the type for mounting host dir - TypeBind = "bind" - // TypeVolume is the type for named volumes - TypeVolume = "volume" - // TypeTmpfs is the type for mounting tmpfs - TypeTmpfs = "tmpfs" -) - -var ( - errDuplicateDest = errors.Errorf("duplicate mount destination") - optionArgError = errors.Errorf("must provide an argument for option") - noDestError = errors.Errorf("must set volume destination") -) - -// Parse all volume-related options in the create config into a set of mounts -// and named volumes to add to the container. -// Handles --volumes-from, --volumes, --tmpfs, --init, and --init-path flags. -// TODO: Named volume options - should we default to rprivate? It bakes into a -// bind mount under the hood... -// TODO: handle options parsing/processing via containers/storage/pkg/mount -func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, []*libpod.ContainerNamedVolume, error) { - // Add image volumes. - baseMounts, baseVolumes, err := config.getImageVolumes() - if err != nil { - return nil, nil, err - } - - // Add --volumes-from. - // Overrides image volumes unconditionally. - vFromMounts, vFromVolumes, err := config.getVolumesFrom(runtime) - if err != nil { - return nil, nil, err - } - for dest, mount := range vFromMounts { - baseMounts[dest] = mount - } - for dest, volume := range vFromVolumes { - baseVolumes[dest] = volume - } - - // Next mounts from the --mounts flag. - // Do not override yet. - unifiedMounts, unifiedVolumes, err := config.getMounts() - if err != nil { - return nil, nil, err - } - - // Next --volumes flag. - // Do not override yet. - volumeMounts, volumeVolumes, err := config.getVolumeMounts() - if err != nil { - return nil, nil, err - } - - // Next --tmpfs flag. - // Do not override yet. - tmpfsMounts, err := config.getTmpfsMounts() - if err != nil { - return nil, nil, err - } - - // Unify mounts from --mount, --volume, --tmpfs. - // Also add mounts + volumes directly from createconfig. - // Start with --volume. - for dest, mount := range volumeMounts { - if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) - } - unifiedMounts[dest] = mount - } - for dest, volume := range volumeVolumes { - if _, ok := unifiedVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) - } - unifiedVolumes[dest] = volume - } - // Now --tmpfs - for dest, tmpfs := range tmpfsMounts { - if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) - } - unifiedMounts[dest] = tmpfs - } - // Now spec mounts and volumes - for _, mount := range config.Mounts { - dest := mount.Destination - if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) - } - unifiedMounts[dest] = mount - } - for _, volume := range config.NamedVolumes { - dest := volume.Dest - if _, ok := unifiedVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) - } - unifiedVolumes[dest] = volume - } - - // If requested, add container init binary - if config.Init { - initPath := config.InitPath - if initPath == "" { - rtc, err := runtime.GetConfig() - if err != nil { - return nil, nil, err - } - initPath = rtc.Engine.InitPath - } - initMount, err := config.addContainerInitBinary(initPath) - if err != nil { - return nil, nil, err - } - if _, ok := unifiedMounts[initMount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination) - } - unifiedMounts[initMount.Destination] = initMount - } - - // Before superseding, we need to find volume mounts which conflict with - // named volumes, and vice versa. - // We'll delete the conflicts here as we supersede. - for dest := range unifiedMounts { - if _, ok := baseVolumes[dest]; ok { - delete(baseVolumes, dest) - } - } - for dest := range unifiedVolumes { - if _, ok := baseMounts[dest]; ok { - delete(baseMounts, dest) - } - } - - // Supersede volumes-from/image volumes with unified volumes from above. - // This is an unconditional replacement. - for dest, mount := range unifiedMounts { - baseMounts[dest] = mount - } - for dest, volume := range unifiedVolumes { - baseVolumes[dest] = volume - } - - // If requested, add tmpfs filesystems for read-only containers. - if config.Security.ReadOnlyRootfs && config.Security.ReadOnlyTmpfs { - readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"} - options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"} - for _, dest := range readonlyTmpfs { - if _, ok := baseMounts[dest]; ok { - continue - } - if _, ok := baseVolumes[dest]; ok { - continue - } - localOpts := options - if dest == "/run" { - localOpts = append(localOpts, "noexec", "size=65536k") - } else { - localOpts = append(localOpts, "exec") - } - baseMounts[dest] = spec.Mount{ - Destination: dest, - Type: "tmpfs", - Source: "tmpfs", - Options: localOpts, - } - } - } - - // Check for conflicts between named volumes and mounts - for dest := range baseMounts { - if _, ok := baseVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) - } - } - for dest := range baseVolumes { - if _, ok := baseMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) - } - } - - // Final step: maps to arrays - finalMounts := make([]spec.Mount, 0, len(baseMounts)) - for _, mount := range baseMounts { - if mount.Type == TypeBind { - absSrc, err := filepath.Abs(mount.Source) - if err != nil { - return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) - } - mount.Source = absSrc - } - finalMounts = append(finalMounts, mount) - } - finalVolumes := make([]*libpod.ContainerNamedVolume, 0, len(baseVolumes)) - for _, volume := range baseVolumes { - finalVolumes = append(finalVolumes, volume) - } - - return finalMounts, finalVolumes, nil -} - -// Parse volumes from - a set of containers whose volumes we will mount in. -// Grab the containers, retrieve any user-created spec mounts and all named -// volumes, and return a list of them. -// Conflicts are resolved simply - the last container specified wins. -// Container names may be suffixed by mount options after a colon. -// TODO: We should clean these paths if possible -func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - // Both of these are maps of mount destination to mount type. - // We ensure that each destination is only mounted to once in this way. - finalMounts := make(map[string]spec.Mount) - finalNamedVolumes := make(map[string]*libpod.ContainerNamedVolume) - - for _, vol := range config.VolumesFrom { - var ( - options = []string{} - err error - splitVol = strings.SplitN(vol, ":", 2) - ) - if len(splitVol) == 2 { - splitOpts := strings.Split(splitVol[1], ",") - for _, checkOpt := range splitOpts { - switch checkOpt { - case "z", "ro", "rw": - // Do nothing, these are valid options - default: - return nil, nil, errors.Errorf("invalid options %q, can only specify 'ro', 'rw', and 'z'", splitVol[1]) - } - } - - if options, err = parse.ValidateVolumeOpts(splitOpts); err != nil { - return nil, nil, err - } - } - ctr, err := runtime.LookupContainer(splitVol[0]) - if err != nil { - return nil, nil, errors.Wrapf(err, "error looking up container %q for volumes-from", splitVol[0]) - } - - logrus.Debugf("Adding volumes from container %s", ctr.ID()) - - // Look up the container's user volumes. This gets us the - // destinations of all mounts the user added to the container. - userVolumesArr := ctr.UserVolumes() - - // We're going to need to access them a lot, so convert to a map - // to reduce looping. - // We'll also use the map to indicate if we missed any volumes along the way. - userVolumes := make(map[string]bool) - for _, dest := range userVolumesArr { - userVolumes[dest] = false - } - - // Now we get the container's spec and loop through its volumes - // and append them in if we can find them. - spec := ctr.Spec() - if spec == nil { - return nil, nil, errors.Errorf("error retrieving container %s spec for volumes-from", ctr.ID()) - } - for _, mnt := range spec.Mounts { - if mnt.Type != TypeBind { - continue - } - if _, exists := userVolumes[mnt.Destination]; exists { - userVolumes[mnt.Destination] = true - - if len(options) != 0 { - mnt.Options = options - } - - if _, ok := finalMounts[mnt.Destination]; ok { - logrus.Debugf("Overriding mount to %s with new mount from container %s", mnt.Destination, ctr.ID()) - } - finalMounts[mnt.Destination] = mnt - } - } - - // We're done with the spec mounts. Add named volumes. - // Add these unconditionally - none of them are automatically - // part of the container, as some spec mounts are. - namedVolumes := ctr.NamedVolumes() - for _, namedVol := range namedVolumes { - if _, exists := userVolumes[namedVol.Dest]; exists { - userVolumes[namedVol.Dest] = true - } - - if len(options) != 0 { - namedVol.Options = options - } - - if _, ok := finalMounts[namedVol.Dest]; ok { - logrus.Debugf("Overriding named volume mount to %s with new named volume from container %s", namedVol.Dest, ctr.ID()) - } - finalNamedVolumes[namedVol.Dest] = namedVol - } - - // Check if we missed any volumes - for volDest, found := range userVolumes { - if !found { - logrus.Warnf("Unable to match volume %s from container %s for volumes-from", volDest, ctr.ID()) - } - } - } - - return finalMounts, finalNamedVolumes, nil -} - -// getMounts takes user-provided input from the --mount flag and creates OCI -// spec mounts and Libpod named volumes. -// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ... -// podman run --mount type=tmpfs,target=/dev/shm ... -// podman run --mount type=volume,source=test-volume, ... -func (config *CreateConfig) getMounts() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - finalMounts := make(map[string]spec.Mount) - finalNamedVolumes := make(map[string]*libpod.ContainerNamedVolume) - - errInvalidSyntax := errors.Errorf("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]") - - // TODO(vrothberg): the manual parsing can be replaced with a regular expression - // to allow a more robust parsing of the mount format and to give - // precise errors regarding supported format versus supported options. - for _, mount := range config.MountsFlag { - arr := strings.SplitN(mount, ",", 2) - if len(arr) < 2 { - return nil, nil, errors.Wrapf(errInvalidSyntax, "%q", mount) - } - kv := strings.Split(arr[0], "=") - // TODO: type is not explicitly required in Docker. - // If not specified, it defaults to "volume". - if len(kv) != 2 || kv[0] != "type" { - return nil, nil, errors.Wrapf(errInvalidSyntax, "%q", mount) - } - - tokens := strings.Split(arr[1], ",") - switch kv[1] { - case TypeBind: - mount, err := getBindMount(tokens) - if err != nil { - return nil, nil, err - } - if _, ok := finalMounts[mount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination) - } - finalMounts[mount.Destination] = mount - case TypeTmpfs: - mount, err := getTmpfsMount(tokens) - if err != nil { - return nil, nil, err - } - if _, ok := finalMounts[mount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination) - } - finalMounts[mount.Destination] = mount - case "volume": - volume, err := getNamedVolume(tokens) - if err != nil { - return nil, nil, err - } - if _, ok := finalNamedVolumes[volume.Dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest) - } - finalNamedVolumes[volume.Dest] = volume - default: - return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1]) - } - } - - return finalMounts, finalNamedVolumes, nil -} - -// Parse a single bind mount entry from the --mount flag. -func getBindMount(args []string) (spec.Mount, error) { - newMount := spec.Mount{ - Type: TypeBind, - } - - var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel bool - - for _, val := range args { - kv := strings.SplitN(val, "=", 2) - switch kv[0] { - case "bind-nonrecursive": - newMount.Options = append(newMount.Options, "bind") - case "ro", "rw": - if setRORW { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' or 'rw' options more than once") - } - setRORW = true - // Can be formatted as one of: - // ro - // ro=[true|false] - // rw - // rw=[true|false] - switch len(kv) { - case 1: - newMount.Options = append(newMount.Options, kv[0]) - case 2: - switch strings.ToLower(kv[1]) { - case "true": - newMount.Options = append(newMount.Options, kv[0]) - case "false": - // Set the opposite only for rw - // ro's opposite is the default - if kv[0] == "rw" { - newMount.Options = append(newMount.Options, "ro") - } - default: - return newMount, errors.Wrapf(optionArgError, "%s must be set to true or false, instead received %q", kv[0], kv[1]) - } - default: - return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val) - } - case "nosuid", "suid": - if setSuid { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") - } - setSuid = true - newMount.Options = append(newMount.Options, kv[0]) - case "nodev", "dev": - if setDev { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") - } - setDev = true - newMount.Options = append(newMount.Options, kv[0]) - case "noexec", "exec": - if setExec { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") - } - setExec = true - newMount.Options = append(newMount.Options, kv[0]) - case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z": - newMount.Options = append(newMount.Options, kv[0]) - case "bind-propagation": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - newMount.Options = append(newMount.Options, kv[1]) - case "src", "source": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - if err := parse.ValidateVolumeHostDir(kv[1]); err != nil { - return newMount, err - } - newMount.Source = kv[1] - setSource = true - case "target", "dst", "destination": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { - return newMount, err - } - newMount.Destination = filepath.Clean(kv[1]) - setDest = true - case "relabel": - if setRelabel { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'relabel' option more than once") - } - setRelabel = true - if len(kv) != 2 { - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) - } - switch kv[1] { - case "private": - newMount.Options = append(newMount.Options, "z") - case "shared": - newMount.Options = append(newMount.Options, "Z") - default: - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) - } - default: - return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0]) - } - } - - if !setDest { - return newMount, noDestError - } - - if !setSource { - newMount.Source = newMount.Destination - } - - options, err := parse.ValidateVolumeOpts(newMount.Options) - if err != nil { - return newMount, err - } - newMount.Options = options - return newMount, nil -} - -// Parse a single tmpfs mount entry from the --mount flag -func getTmpfsMount(args []string) (spec.Mount, error) { - newMount := spec.Mount{ - Type: TypeTmpfs, - Source: TypeTmpfs, - } - - var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup bool - - for _, val := range args { - kv := strings.SplitN(val, "=", 2) - switch kv[0] { - case "tmpcopyup", "notmpcopyup": - if setTmpcopyup { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'tmpcopyup' and 'notmpcopyup' options more than once") - } - setTmpcopyup = true - newMount.Options = append(newMount.Options, kv[0]) - case "ro", "rw": - if setRORW { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once") - } - setRORW = true - newMount.Options = append(newMount.Options, kv[0]) - case "nosuid", "suid": - if setSuid { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") - } - setSuid = true - newMount.Options = append(newMount.Options, kv[0]) - case "nodev", "dev": - if setDev { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") - } - setDev = true - newMount.Options = append(newMount.Options, kv[0]) - case "noexec", "exec": - if setExec { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") - } - setExec = true - newMount.Options = append(newMount.Options, kv[0]) - case "tmpfs-mode": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - newMount.Options = append(newMount.Options, fmt.Sprintf("mode=%s", kv[1])) - case "tmpfs-size": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - newMount.Options = append(newMount.Options, fmt.Sprintf("size=%s", kv[1])) - case "src", "source": - return newMount, errors.Errorf("source is not supported with tmpfs mounts") - case "target", "dst", "destination": - if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) - } - if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { - return newMount, err - } - newMount.Destination = filepath.Clean(kv[1]) - setDest = true - default: - return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0]) - } - } - - if !setDest { - return newMount, noDestError - } - - return newMount, nil -} - -// Parse a single volume mount entry from the --mount flag. -// Note that the volume-label option for named volumes is currently NOT supported. -// TODO: add support for --volume-label -func getNamedVolume(args []string) (*libpod.ContainerNamedVolume, error) { - newVolume := new(libpod.ContainerNamedVolume) - - var setSource, setDest, setRORW, setSuid, setDev, setExec bool - - for _, val := range args { - kv := strings.SplitN(val, "=", 2) - switch kv[0] { - case "ro", "rw": - if setRORW { - return nil, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once") - } - setRORW = true - newVolume.Options = append(newVolume.Options, kv[0]) - case "nosuid", "suid": - if setSuid { - return nil, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") - } - setSuid = true - newVolume.Options = append(newVolume.Options, kv[0]) - case "nodev", "dev": - if setDev { - return nil, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") - } - setDev = true - newVolume.Options = append(newVolume.Options, kv[0]) - case "noexec", "exec": - if setExec { - return nil, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") - } - setExec = true - newVolume.Options = append(newVolume.Options, kv[0]) - case "volume-label": - return nil, errors.Errorf("the --volume-label option is not presently implemented") - case "src", "source": - if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) - } - newVolume.Name = kv[1] - setSource = true - case "target", "dst", "destination": - if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) - } - if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { - return nil, err - } - newVolume.Dest = filepath.Clean(kv[1]) - setDest = true - default: - return nil, errors.Wrapf(util.ErrBadMntOption, kv[0]) - } - } - - if !setSource { - return nil, errors.Errorf("must set source volume") - } - if !setDest { - return nil, noDestError - } - - return newVolume, nil -} - -func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - mounts := make(map[string]spec.Mount) - volumes := make(map[string]*libpod.ContainerNamedVolume) - - volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]") - - for _, vol := range config.Volumes { - var ( - options []string - src string - dest string - err error - ) - - splitVol := strings.Split(vol, ":") - if len(splitVol) > 3 { - return nil, nil, errors.Wrapf(volumeFormatErr, vol) - } - - src = splitVol[0] - if len(splitVol) == 1 { - // This is an anonymous named volume. Only thing given - // is destination. - // Name/source will be blank, and populated by libpod. - src = "" - dest = splitVol[0] - } else if len(splitVol) > 1 { - dest = splitVol[1] - } - if len(splitVol) > 2 { - if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil { - return nil, nil, err - } - } - - // Do not check source dir for anonymous volumes - if len(splitVol) > 1 { - if err := parse.ValidateVolumeHostDir(src); err != nil { - return nil, nil, err - } - } - if err := parse.ValidateVolumeCtrDir(dest); err != nil { - return nil, nil, err - } - - cleanDest := filepath.Clean(dest) - - if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { - // This is not a named volume - newMount := spec.Mount{ - Destination: cleanDest, - Type: string(TypeBind), - Source: src, - Options: options, - } - if _, ok := mounts[newMount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) - } - mounts[newMount.Destination] = newMount - } else { - // This is a named volume - newNamedVol := new(libpod.ContainerNamedVolume) - newNamedVol.Name = src - newNamedVol.Dest = cleanDest - newNamedVol.Options = options - - if _, ok := volumes[newNamedVol.Dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) - } - volumes[newNamedVol.Dest] = newNamedVol - } - - logrus.Debugf("User mount %s:%s options %v", src, dest, options) - } - - return mounts, volumes, nil -} - -// Get mounts for container's image volumes -func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - mounts := make(map[string]spec.Mount) - volumes := make(map[string]*libpod.ContainerNamedVolume) - - if config.ImageVolumeType == "ignore" { - return mounts, volumes, nil - } - - for vol := range config.BuiltinImgVolumes { - cleanDest := filepath.Clean(vol) - logrus.Debugf("Adding image volume at %s", cleanDest) - if config.ImageVolumeType == "tmpfs" { - // Tmpfs image volumes are handled as mounts - mount := spec.Mount{ - Destination: cleanDest, - Source: TypeTmpfs, - Type: TypeTmpfs, - Options: []string{"rprivate", "rw", "nodev", "exec"}, - } - mounts[cleanDest] = mount - } else { - // Anonymous volumes have no name. - namedVolume := new(libpod.ContainerNamedVolume) - namedVolume.Options = []string{"rprivate", "rw", "nodev", "exec"} - namedVolume.Dest = cleanDest - volumes[cleanDest] = namedVolume - } - } - - return mounts, volumes, nil -} - -// GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts -func (config *CreateConfig) getTmpfsMounts() (map[string]spec.Mount, error) { - m := make(map[string]spec.Mount) - for _, i := range config.Tmpfs { - // Default options if nothing passed - var options []string - spliti := strings.Split(i, ":") - destPath := spliti[0] - if err := parse.ValidateVolumeCtrDir(spliti[0]); err != nil { - return nil, err - } - if len(spliti) > 1 { - options = strings.Split(spliti[1], ",") - } - - if _, ok := m[destPath]; ok { - return nil, errors.Wrapf(errDuplicateDest, destPath) - } - - mount := spec.Mount{ - Destination: filepath.Clean(destPath), - Type: string(TypeTmpfs), - Options: options, - Source: string(TypeTmpfs), - } - m[destPath] = mount - } - return m, nil -} - -// AddContainerInitBinary adds the init binary specified by path iff the -// container will run in a private PID namespace that is not shared with the -// host or another pre-existing container, where an init-like process is -// already running. -// -// Note that AddContainerInitBinary prepends "/dev/init" "--" to the command -// to execute the bind-mounted binary as PID 1. -func (config *CreateConfig) addContainerInitBinary(path string) (spec.Mount, error) { - mount := spec.Mount{ - Destination: "/dev/init", - Type: TypeBind, - Source: path, - Options: []string{TypeBind, "ro"}, - } - - if path == "" { - return mount, fmt.Errorf("please specify a path to the container-init binary") - } - if !config.Pid.PidMode.IsPrivate() { - return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)") - } - if config.Systemd { - return mount, fmt.Errorf("cannot use container-init binary with systemd") - } - if _, err := os.Stat(path); os.IsNotExist(err) { - return mount, errors.Wrap(err, "container-init binary not found on the host") - } - config.Command = append([]string{"/dev/init", "--"}, config.Command...) - return mount, nil -} - -// Supersede existing mounts in the spec with new, user-specified mounts. -// TODO: Should we unmount subtree mounts? E.g., if /tmp/ is mounted by -// one mount, and we already have /tmp/a and /tmp/b, should we remove -// the /tmp/a and /tmp/b mounts in favor of the more general /tmp? -func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount { - if len(mounts) > 0 { - // If we have overlappings mounts, remove them from the spec in favor of - // the user-added volume mounts - destinations := make(map[string]bool) - for _, mount := range mounts { - destinations[path.Clean(mount.Destination)] = true - } - // Copy all mounts from spec to defaultMounts, except for - // - mounts overridden by a user supplied mount; - // - all mounts under /dev if a user supplied /dev is present; - mountDev := destinations["/dev"] - for _, mount := range configMount { - if _, ok := destinations[path.Clean(mount.Destination)]; !ok { - if mountDev && strings.HasPrefix(mount.Destination, "/dev/") { - // filter out everything under /dev if /dev is user-mounted - continue - } - - logrus.Debugf("Adding mount %s", mount.Destination) - mounts = append(mounts, mount) - } - } - return mounts - } - return configMount -} - -// Ensure mount options on all mounts are correct -func InitFSMounts(mounts []spec.Mount) error { - for i, m := range mounts { - switch { - case m.Type == TypeBind: - opts, err := util.ProcessOptions(m.Options, false, m.Source) - if err != nil { - return err - } - mounts[i].Options = opts - case m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev": - opts, err := util.ProcessOptions(m.Options, true, "") - if err != nil { - return err - } - mounts[i].Options = opts - } - } - return nil -} diff --git a/pkg/spec/storage_test.go b/pkg/spec/storage_test.go deleted file mode 100644 index 04a9d6976..000000000 --- a/pkg/spec/storage_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package createconfig - -import ( - "testing" - - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/stretchr/testify/assert" -) - -func TestGetVolumeMountsOneVolume(t *testing.T) { - data := spec.Mount{ - Destination: "/foobar", - Type: "bind", - Source: "/tmp", - Options: []string{"ro"}, - } - config := CreateConfig{ - Volumes: []string{"/tmp:/foobar:ro"}, - } - specMount, _, err := config.getVolumeMounts() - assert.NoError(t, err) - assert.EqualValues(t, data, specMount[data.Destination]) -} - -func TestGetTmpfsMounts(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, err := config.getTmpfsMounts() - assert.NoError(t, err) - assert.EqualValues(t, data, tmpfsMount[data.Destination]) -} diff --git a/pkg/varlink/generate.go b/pkg/varlink/generate.go deleted file mode 100644 index b3f58d4a5..000000000 --- a/pkg/varlink/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package iopodman - -//go:generate go run ../../vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go io.podman.varlink diff --git a/pkg/varlink/io.podman.varlink b/pkg/varlink/io.podman.varlink deleted file mode 100644 index cd6316011..000000000 --- a/pkg/varlink/io.podman.varlink +++ /dev/null @@ -1,1398 +0,0 @@ -# Podman Service Interface and API description. The master version of this document can be found -# in the [API.md](https://github.com/containers/podman/blob/master/API.md) file in the upstream libpod repository. -interface io.podman - -type Volume ( - name: string, - labels: [string]string, - mountPoint: string, - driver: string, - options: [string]string -) - -type NotImplemented ( - comment: string -) - -type StringResponse ( - message: string -) - -type RemoveImageResponse ( - untagged: []string, - deleted: string -) - -type LogLine ( - device: string, - parseLogType : string, - time: string, - msg: string, - cid: string -) - -# ContainerChanges describes the return struct for ListContainerChanges -type ContainerChanges ( - changed: []string, - added: []string, - deleted: []string -) - -type ImageSaveOptions ( - name: string, - format: string, - output: string, - outputType: string, - moreTags: []string, - quiet: bool, - compress: bool -) - -type VolumeCreateOpts ( - volumeName: string, - driver: string, - labels: [string]string, - options: [string]string -) - -type VolumeRemoveOpts ( - volumes: []string, - all: bool, - force: bool -) - -type Image ( - id: string, - digest: string, - digests: []string, - parentId: string, - repoTags: []string, - repoDigests: []string, - created: string, # as RFC3339 - size: int, - virtualSize: int, - containers: int, - labels: [string]string, - isParent: bool, - topLayer: string, - readOnly: bool, - history: []string -) - -# ImageHistory describes the returned structure from ImageHistory. -type ImageHistory ( - id: string, - created: string, # as RFC3339 - createdBy: string, - tags: []string, - size: int, - comment: string -) - -# Represents a single search result from SearchImages -type ImageSearchResult ( - description: string, - is_official: bool, - is_automated: bool, - registry: string, - name: string, - star_count: int -) - -type ImageSearchFilter ( - is_official: ?bool, - is_automated: ?bool, - star_count: int -) - -type AuthConfig ( - username: string, - password: string -) - -type KubePodService ( - pod: string, - service: string -) - -type Container ( - id: string, - image: string, - imageid: string, - command: []string, - createdat: string, # as RFC3339 - runningfor: string, - status: string, - ports: []ContainerPortMappings, - rootfssize: int, - rwsize: int, - names: string, - labels: [string]string, - mounts: []ContainerMount, - containerrunning: bool, - namespaces: ContainerNameSpace -) - -# ContainerStats is the return struct for the stats of a container -type ContainerStats ( - id: string, - name: string, - cpu: float, - cpu_nano: int, - system_nano: int, - mem_usage: int, - mem_limit: int, - mem_perc: float, - net_input: int, - net_output: int, - block_output: int, - block_input: int, - pids: int -) - -type PsOpts ( - all: bool, - filters: ?[]string, - last: ?int, - latest: ?bool, - noTrunc: ?bool, - pod: ?bool, - quiet: ?bool, - size: ?bool, - sort: ?string, - sync: ?bool -) - -type PsContainer ( - id: string, - image: string, - command: string, - created: string, - ports: string, - names: string, - isInfra: bool, - status: string, - state: string, - pidNum: int, - rootFsSize: int, - rwSize: int, - pod: string, - createdAt: string, - exitedAt: string, - startedAt: string, - labels: [string]string, - nsPid: string, - cgroup: string, - ipc: string, - mnt: string, - net: string, - pidNs: string, - user: string, - uts: string, - mounts: string -) - -# ContainerMount describes the struct for mounts in a container -type ContainerMount ( - destination: string, - type: string, - source: string, - options: []string -) - -# ContainerPortMappings describes the struct for portmappings in an existing container -type ContainerPortMappings ( - host_port: string, - host_ip: string, - protocol: string, - container_port: string -) - -# ContainerNamespace describes the namespace structure for an existing container -type ContainerNameSpace ( - user: string, - uts: string, - pidns: string, - pid: string, - cgroup: string, - net: string, - mnt: string, - ipc: string -) - -# InfoDistribution describes the host's distribution -type InfoDistribution ( - distribution: string, - version: string -) - -# InfoHost describes the host stats portion of PodmanInfo -type InfoHost ( - buildah_version: string, - distribution: InfoDistribution, - mem_free: int, - mem_total: int, - swap_free: int, - swap_total: int, - arch: string, - cpus: int, - hostname: string, - kernel: string, - os: string, - uptime: string, - eventlogger: string -) - -# InfoGraphStatus describes the detailed status of the storage driver -type InfoGraphStatus ( - backing_filesystem: string, - native_overlay_diff: string, - supports_d_type: string -) - -# InfoRegistry describes the host's registry information -type InfoRegistry ( - search: []string, - insecure: []string, - blocked: []string -) - -# InfoStore describes the host's storage information -type InfoStore ( - containers: int, - images: int, - graph_driver_name: string, - graph_driver_options: string, - graph_root: string, - graph_status: InfoGraphStatus, - run_root: string -) - -# InfoPodman provides details on the Podman binary -type InfoPodmanBinary ( - compiler: string, - go_version: string, - podman_version: string, - git_commit: string -) - -# PodmanInfo describes the Podman host and build -type PodmanInfo ( - host: InfoHost, - registries: InfoRegistry, - store: InfoStore, - 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. -# args[0] is the image name or id -# args[1-] are the new commands if changed -type Create ( - args: []string, - addHost: ?[]string, - annotation: ?[]string, - attach: ?[]string, - blkioWeight: ?string, - blkioWeightDevice: ?[]string, - capAdd: ?[]string, - capDrop: ?[]string, - cgroupParent: ?string, - cidFile: ?string, - conmonPidfile: ?string, - command: ?[]string, - cpuPeriod: ?int, - cpuQuota: ?int, - cpuRtPeriod: ?int, - cpuRtRuntime: ?int, - cpuShares: ?int, - cpus: ?float, - cpuSetCpus: ?string, - cpuSetMems: ?string, - detach: ?bool, - detachKeys: ?string, - device: ?[]string, - deviceReadBps: ?[]string, - deviceReadIops: ?[]string, - deviceWriteBps: ?[]string, - deviceWriteIops: ?[]string, - dns: ?[]string, - dnsOpt: ?[]string, - dnsSearch: ?[]string, - dnsServers: ?[]string, - entrypoint: ?string, - env: ?[]string, - envFile: ?[]string, - expose: ?[]string, - gidmap: ?[]string, - groupadd: ?[]string, - healthcheckCommand: ?string, - healthcheckInterval: ?string, - healthcheckRetries: ?int, - healthcheckStartPeriod: ?string, - healthcheckTimeout:?string, - hostname: ?string, - imageVolume: ?string, - init: ?bool, - initPath: ?string, - interactive: ?bool, - ip: ?string, - ipc: ?string, - kernelMemory: ?string, - label: ?[]string, - labelFile: ?[]string, - logDriver: ?string, - logOpt: ?[]string, - macAddress: ?string, - memory: ?string, - memoryReservation: ?string, - memorySwap: ?string, - memorySwappiness: ?int, - name: ?string, - network: ?string, - noHosts: ?bool, - oomKillDisable: ?bool, - oomScoreAdj: ?int, - overrideArch: ?string, - overrideOS: ?string, - pid: ?string, - pidsLimit: ?int, - pod: ?string, - privileged: ?bool, - publish: ?[]string, - publishAll: ?bool, - pull: ?string, - quiet: ?bool, - readonly: ?bool, - readonlytmpfs: ?bool, - restart: ?string, - rm: ?bool, - rootfs: ?bool, - securityOpt: ?[]string, - shmSize: ?string, - stopSignal: ?string, - stopTimeout: ?int, - storageOpt: ?[]string, - subuidname: ?string, - subgidname: ?string, - sysctl: ?[]string, - systemd: ?string, - tmpfs: ?[]string, - tty: ?bool, - uidmap: ?[]string, - ulimit: ?[]string, - user: ?string, - userns: ?string, - uts: ?string, - mount: ?[]string, - volume: ?[]string, - volumesFrom: ?[]string, - workDir: ?string -) - -# BuildOptions are are used to describe describe physical attributes of the build -type BuildOptions ( - addHosts: []string, - cgroupParent: string, - cpuPeriod: int, - cpuQuota: int, - cpuShares: int, - cpusetCpus: string, - cpusetMems: string, - memory: int, - memorySwap: int, - shmSize: string, - ulimit: []string, - volume: []string -) - -# BuildInfo is used to describe user input for building images -type BuildInfo ( - architecture: string, - addCapabilities: []string, - additionalTags: []string, - annotations: []string, - buildArgs: [string]string, - buildOptions: BuildOptions, - cniConfigDir: string, - cniPluginDir: string, - compression: string, - contextDir: string, - defaultsMountFilePath: string, - devices: []string, - dockerfiles: []string, - dropCapabilities: []string, - err: string, - forceRmIntermediateCtrs: bool, - iidfile: string, - label: []string, - layers: bool, - nocache: bool, - os: string, - out: string, - output: string, - outputFormat: string, - pullPolicy: string, - quiet: bool, - remoteIntermediateCtrs: bool, - reportWriter: string, - runtimeArgs: []string, - signBy: string, - squash: bool, - target: string, - transientMounts: []string -) - -# MoreResponse is a struct for when responses from varlink requires longer output -type MoreResponse ( - logs: []string, - id: string -) - -# ListPodContainerInfo is a returned struct for describing containers -# in a pod. -type ListPodContainerInfo ( - name: string, - id: string, - status: string -) - -# PodCreate is an input structure for creating pods. -# It emulates options to podman pod create. The infraCommand and -# infraImage options are currently NotSupported. -type PodCreate ( - name: string, - cgroupParent: string, - labels: [string]string, - share: []string, - infra: bool, - infraCommand: string, - infraImage: string, - publish: []string -) - -# ListPodData is the returned struct for an individual pod -type ListPodData ( - id: string, - name: string, - createdat: string, - cgroup: string, - status: string, - labels: [string]string, - numberofcontainers: string, - containersinfo: []ListPodContainerInfo -) - -type PodContainerErrorData ( - containerid: string, - reason: string -) - -# Runlabel describes the required input for container runlabel -type Runlabel( - image: string, - authfile: string, - display: bool, - name: string, - pull: bool, - label: string, - extraArgs: []string, - opts: [string]string -) - -# Event describes a libpod struct -type Event( - # TODO: make status and type a enum at some point? - # id is the container, volume, pod, image ID - id: string, - # image is the image name where applicable - image: string, - # name is the name of the pod, container, image - name: string, - # status describes the event that happened (i.e. create, remove, ...) - status: string, - # time the event happened - time: string, - # type describes object the event happened with (image, container...) - type: string -) - -type DiffInfo( - # path that is different - path: string, - # Add, Delete, Modify - changeType: string -) - -type ExecOpts( - # container name or id - name: string, - # Create pseudo tty - tty: bool, - # privileged access in container - privileged: bool, - # command to execute in container - cmd: []string, - # user to use in container - user: ?string, - # workdir to run command in container - workdir: ?string, - # slice of keyword=value environment variables - env: ?[]string, - # string of detach keys - detachKeys: ?string -) - -# GetVersion returns version and build information of the podman service -method GetVersion() -> ( - version: string, - go_version: string, - git_commit: string, - built: string, # as RFC3339 - os_arch: string, - remote_api_version: int -) - -# Reset resets Podman back to its initial state. -# Removes all Pods, Containers, Images and Volumes -method Reset() -> () - -# GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats, -# build information of Podman, and system-wide registries. -method GetInfo() -> (info: PodmanInfo) - -# ListContainers returns information about all containers. -# See also [GetContainer](#GetContainer). -method ListContainers() -> (containers: []Container) - -method Ps(opts: PsOpts) -> (containers: []PsContainer) - -method GetContainersByStatus(status: []string) -> (containerS: []Container) - -method Top (nameOrID: string, descriptors: []string) -> (top: []string) - -# HealthCheckRun executes defined container's healthcheck command -# and returns the container's health status. -method HealthCheckRun (nameOrID: string) -> (healthCheckStatus: string) - -# GetContainer returns information about a single container. If a container -# with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound) -# error will be returned. See also [ListContainers](ListContainers) and -# [InspectContainer](#InspectContainer). -method GetContainer(id: string) -> (container: Container) - -# GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of -# container names. The definition of latest container means the latest by creation date. In a multi- -# user environment, results might differ from what you expect. -method GetContainersByContext(all: bool, latest: bool, args: []string) -> (containers: []string) - -# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. -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) -# error will be returned if the container cannot be found. See also [InspectImage](#InspectImage). -method InspectContainer(name: string) -> (container: string) - -# ListContainerProcesses takes a name or ID of a container and returns the processes -# running inside the container as array of strings. It will accept an array of string -# arguments that represent ps options. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -# error will be returned. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerProcesses '{"name": "135d71b9495f", "opts": []}' -# { -# "container": [ -# " UID PID PPID C STIME TTY TIME CMD", -# " 0 21220 21210 0 09:05 pts/0 00:00:00 /bin/sh", -# " 0 21232 21220 0 09:05 pts/0 00:00:00 top", -# " 0 21284 21220 0 09:05 pts/0 00:00:00 vi /etc/hosts" -# ] -# } -# ~~~ -method ListContainerProcesses(name: string, opts: []string) -> (container: []string) - -# GetContainerLogs takes a name or ID of a container and returns the logs of that container. -# If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned. -# The container logs are returned as an array of strings. GetContainerLogs will honor the streaming -# capability of varlink if the client invokes it. -method GetContainerLogs(name: string) -> (container: []string) - -method GetContainersLogs(names: []string, follow: bool, latest: bool, since: string, tail: int, timestamps: bool) -> (log: LogLine) - -# ListContainerChanges takes a name or ID of a container and returns changes between the container and -# its base image. It returns a struct of changed, deleted, and added path names. -method ListContainerChanges(name: string) -> (container: ContainerChanges) - -# ExportContainer creates an image from a container. It takes the name or ID of a container and a -# path representing the target tarfile. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -# error will be returned. -# The return value is the written tarfile. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ExportContainer '{"name": "flamboyant_payne", "path": "/tmp/payne.tar" }' -# { -# "tarfile": "/tmp/payne.tar" -# } -# ~~~ -method ExportContainer(name: string, path: string) -> (tarfile: string) - -# GetContainerStats takes the name or ID of a container and returns a single ContainerStats structure which -# contains attributes like memory and cpu usage. If the container cannot be found, a -# [ContainerNotFound](#ContainerNotFound) error will be returned. If the container is not running, a [NoContainerRunning](#NoContainerRunning) -# error will be returned -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name": "c33e4164f384"}' -# { -# "container": { -# "block_input": 0, -# "block_output": 0, -# "cpu": 2.571123918839990154678e-08, -# "cpu_nano": 49037378, -# "id": "c33e4164f384aa9d979072a63319d66b74fd7a128be71fa68ede24f33ec6cfee", -# "mem_limit": 33080606720, -# "mem_perc": 2.166828456524753747370e-03, -# "mem_usage": 716800, -# "name": "competent_wozniak", -# "net_input": 768, -# "net_output": 5910, -# "pids": 1, -# "system_nano": 10000000 -# } -# } -# ~~~ -method GetContainerStats(name: string) -> (container: ContainerStats) - -# GetContainerStatsWithHistory takes a previous set of container statistics and uses libpod functions -# to calculate the containers statistics based on current and previous measurements. -method GetContainerStatsWithHistory(previousStats: ContainerStats) -> (container: ContainerStats) - -# This method has not be implemented yet. -# method ResizeContainerTty() -> (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 forcible stop to the container is applied. It -# returns the container ID once stopped. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) -# error will be returned instead. See also [KillContainer](KillContainer). -# #### Error -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.StopContainer '{"name": "135d71b9495f", "timeout": 5}' -# { -# "container": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -# } -# ~~~ -method StopContainer(name: string, timeout: int) -> (container: string) - -# InitContainer initializes the given container. It accepts a container name or -# ID, and will initialize the container matching that ID if possible, and error -# if not. Containers can only be initialized when they are in the Created or -# Exited states. Initialization prepares a container to be started, but does not -# start the container. It is intended to be used to debug a container's state -# prior to starting it. -method InitContainer(name: string) -> (container: string) - -# RestartContainer will restart a running container given a container name or ID and timeout value. The timeout -# value is the time before a forcible stop is used to stop the container. If the container cannot be found by -# name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise, the ID of the -# container will be returned. -method RestartContainer(name: string, timeout: int) -> (container: string) - -# KillContainer takes the name or ID of a container as well as a signal to be applied to the container. Once the -# container has been killed, the container's ID is returned. If the container cannot be found, a -# [ContainerNotFound](#ContainerNotFound) error is returned. See also [StopContainer](StopContainer). -method KillContainer(name: string, signal: int) -> (container: string) - -# This method has not be implemented yet. -# method UpdateContainer() -> (notimplemented: NotImplemented) - -# This method has not be implemented yet. -# method RenameContainer() -> (notimplemented: NotImplemented) - -# PauseContainer takes the name or ID of container and pauses it. If the container cannot be found, -# a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. -# See also [UnpauseContainer](#UnpauseContainer). -method PauseContainer(name: string) -> (container: string) - -# UnpauseContainer takes the name or ID of container and unpauses a paused container. If the container cannot be -# found, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. -# See also [PauseContainer](#PauseContainer). -method UnpauseContainer(name: string) -> (container: string) - -# Attach takes the name or ID of a container and sets up the ability to remotely attach to its console. The start -# bool is whether you wish to start the container in question first. -method Attach(name: string, detachKeys: string, start: bool) -> () - -method AttachControl(name: string) -> () - -# 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.podman/io.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 the given interval in milliseconds 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, interval: int) -> (exitcode: int) - -# RemoveContainer requires the name or ID of a container as well as a boolean that -# indicates whether a container should be forcefully removed (e.g., by stopping it), and a boolean -# indicating whether to remove builtin volumes. Upon successful removal of the -# container, its ID is returned. If the -# container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned. -# See also [EvictContainer](EvictContainer). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.RemoveContainer '{"name": "62f4fd98cb57"}' -# { -# "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -# } -# ~~~ -method RemoveContainer(name: string, force: bool, removeVolumes: bool) -> (container: string) - -# EvictContainer requires the name or ID of a container as well as a boolean that -# indicates to remove builtin volumes. Upon successful eviction of the container, -# its ID is returned. If the container cannot be found by name or ID, -# a [ContainerNotFound](#ContainerNotFound) error will be returned. -# See also [RemoveContainer](RemoveContainer). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.EvictContainer '{"name": "62f4fd98cb57"}' -# { -# "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -# } -# ~~~ -method EvictContainer(name: string, removeVolumes: bool) -> (container: string) - -# DeleteStoppedContainers will delete all containers that are not running. It will return a list the deleted -# container IDs. See also [RemoveContainer](RemoveContainer). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteStoppedContainers -# { -# "containers": [ -# "451410b931d00def8aa9b4f8084e4d4a39e5e04ea61f358cf53a5cf95afcdcee", -# "8b60f754a3e01389494a9581ade97d35c2765b6e2f19acd2d3040c82a32d1bc0", -# "cf2e99d4d3cad6073df199ed32bbe64b124f3e1aba6d78821aa8460e70d30084", -# "db901a329587312366e5ecff583d08f0875b4b79294322df67d90fc6eed08fc1" -# ] -# } -# ~~~ -method DeleteStoppedContainers() -> (containers: []string) - -# ListImages returns information about the images that are currently in storage. -# See also [InspectImage](#InspectImage). -method ListImages() -> (images: []Image) - -# ListImagesWithFilters returns information about the images that are currently in storage -# after one or more filters has been applied. -# See also [InspectImage](#InspectImage). -method ListImagesWithFilters(filters: []string) -> (images: []Image) - -# GetImage returns information about a single image in storage. -# If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned. -method GetImage(id: string) -> (image: Image) - -# BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the -# contextDir tarball path, the 'dockerfiles' path, and 'output' option in the BuildInfo structure. The 'output' -# options is the name of the of the resulting build. It will return a [MoreResponse](#MoreResponse) structure -# that contains the build logs and resulting image ID. -# #### Example -# ~~~ -# $ sudo varlink call -m unix:///run/podman/io.podman/io.podman.BuildImage '{"build":{"contextDir":"/tmp/t/context.tar","dockerfiles":["Dockerfile"], "output":"foobar"}}' -# { -# "image": { -# "id": "", -# "logs": [ -# "STEP 1: FROM alpine\n" -# ] -# } -# } -# { -# "image": { -# "id": "", -# "logs": [ -# "STEP 2: COMMIT foobar\n" -# ] -# } -# } -# { -# "image": { -# "id": "", -# "logs": [ -# "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9\n" -# ] -# } -# } -# { -# "image": { -# "id": "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9", -# "logs": [] -# } -# } -# ~~~ -method BuildImage(build: BuildInfo) -> (image: MoreResponse) - -# This function is not implemented yet. -# method CreateImage() -> (notimplemented: NotImplemented) - -# InspectImage takes the name or ID of an image and returns a string representation of data associated with the -#image. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will -# be returned if the image cannot be found. -method InspectImage(name: string) -> (image: string) - -# HistoryImage takes the name or ID of an image and returns information about its history and layers. The returned -# history is in the form of an array of ImageHistory structures. If the image cannot be found, an -# [ImageNotFound](#ImageNotFound) error is returned. -method HistoryImage(name: string) -> (history: []ImageHistory) - -# PushImage takes two input arguments: the name or ID of an image, the fully-qualified destination name of the image, -# It will return an [ImageNotFound](#ImageNotFound) error if -# the image cannot be found in local storage; otherwise it will return a [MoreResponse](#MoreResponse) -method PushImage(name: string, tag: string, compress: bool, format: string, removeSignatures: bool, signBy: string) -> (reply: MoreResponse) - -# TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot -# be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success. -method TagImage(name: string, tagged: string) -> (image: string) - -# UntagImage takes the name or ID of an image in local storage as well as the -# tag name to be removed. If the image cannot be found, an -# [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of -# the image is returned on success. -method UntagImage(name: string, tag: string) -> (image: string) - -# RemoveImage takes the name or ID of an image as well as a boolean that determines if containers using that image -# should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The -# ID of the removed image is returned when complete. See also [DeleteUnusedImages](DeleteUnusedImages). -# #### Example -# ~~~ -# varlink call -m unix:/run/podman/io.podman/io.podman.RemoveImage '{"name": "registry.fedoraproject.org/fedora", "force": true}' -# { -# "image": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e" -# } -# ~~~ -method RemoveImage(name: string, force: bool) -> (image: string) - -# RemoveImageWithResponse takes the name or ID of an image as well as a boolean that determines if containers using that image -# should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The response is -# in the form of a RemoveImageResponse . -method RemoveImageWithResponse(name: string, force: bool) -> (response: RemoveImageResponse) - -# SearchImages searches available registries for images that contain the -# contents of "query" in their name. If "limit" is given, limits the amount of -# search results per registry. -method SearchImages(query: string, limit: ?int, filter: ImageSearchFilter) -> (results: []ImageSearchResult) - -# DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned -# in a string array. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteUnusedImages -# { -# "images": [ -# "166ea6588079559c724c15223f52927f514f73dd5c5cf2ae2d143e3b2e6e9b52", -# "da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e", -# "3ef70f7291f47dfe2b82931a993e16f5a44a0e7a68034c3e0e086d77f5829adc", -# "59788edf1f3e78cd0ebe6ce1446e9d10788225db3dedcfd1a59f764bad2b2690" -# ] -# } -# ~~~ -method DeleteUnusedImages() -> (images: []string) - -# Commit, creates an image from an existing container. It requires the name or -# ID of the container as well as the resulting image name. Optionally, you can define an author and message -# to be added to the resulting image. You can also define changes to the resulting image for the following -# attributes: _CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, ONBUILD, STOPSIGNAL, USER, VOLUME, and WORKDIR_. To pause the -# container while it is being committed, pass a _true_ bool for the pause argument. If the container cannot -# be found by the ID or name provided, a (ContainerNotFound)[#ContainerNotFound] error will be returned; otherwise, -# the resulting image's ID will be returned as a string inside a MoreResponse. -method Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) -> (reply: MoreResponse) - -# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional -# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage). -method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string) - -# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also -# a boolean option to force compression. It also takes in a string array of tags to be able to save multiple -# tags of the same image to a tarball (each tag should be of the form <image>:<tag>). 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). -method ExportImage(name: string, destination: string, compress: bool, tags: []string) -> (image: string) - -# PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs -# are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send -# status as it occurs. -method PullImage(name: string, creds: AuthConfig) -> (reply: MoreResponse) - -# CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input. -# On success, the ID of the newly created pod will be returned. -# #### Example -# ~~~ -# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"name": "test"}}' -# { -# "pod": "b05dee7bd4ccfee688099fe1588a7a898d6ddd6897de9251d4671c9b0feacb2a" -# } -# -# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"infra": true, "share": ["ipc", "net", "uts"]}}' -# { -# "pod": "d7697449a8035f613c1a8891286502aca68fff7d5d49a85279b3bda229af3b28" -# } -# ~~~ -method CreatePod(create: PodCreate) -> (pod: string) - -# ListPods returns a list of pods in no particular order. They are -# returned as an array of ListPodData structs. See also [GetPod](#GetPod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListPods -# { -# "pods": [ -# { -# "cgroup": "machine.slice", -# "containersinfo": [ -# { -# "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45", -# "name": "1840835294cf-infra", -# "status": "running" -# }, -# { -# "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6", -# "name": "upbeat_murdock", -# "status": "running" -# } -# ], -# "createdat": "2018-12-07 13:10:15.014139258 -0600 CST", -# "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f", -# "name": "foobar", -# "numberofcontainers": "2", -# "status": "Running" -# }, -# { -# "cgroup": "machine.slice", -# "containersinfo": [ -# { -# "id": "1ca4b7bbba14a75ba00072d4b705c77f3df87db0109afaa44d50cb37c04a477e", -# "name": "784306f655c6-infra", -# "status": "running" -# } -# ], -# "createdat": "2018-12-07 13:09:57.105112457 -0600 CST", -# "id": "784306f655c6200aea321dd430ba685e9b2cc1f7d7528a72f3ff74ffb29485a2", -# "name": "nostalgic_pike", -# "numberofcontainers": "1", -# "status": "Running" -# } -# ] -# } -# ~~~ -method ListPods() -> (pods: []ListPodData) - -# GetPod takes a name or ID of a pod and returns single [ListPodData](#ListPodData) -# structure. A [PodNotFound](#PodNotFound) error will be returned if the pod cannot be found. -# See also [ListPods](ListPods). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.GetPod '{"name": "foobar"}' -# { -# "pod": { -# "cgroup": "machine.slice", -# "containersinfo": [ -# { -# "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45", -# "name": "1840835294cf-infra", -# "status": "running" -# }, -# { -# "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6", -# "name": "upbeat_murdock", -# "status": "running" -# } -# ], -# "createdat": "2018-12-07 13:10:15.014139258 -0600 CST", -# "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f", -# "name": "foobar", -# "numberofcontainers": "2", -# "status": "Running" -# } -# } -# ~~~ -method GetPod(name: string) -> (pod: ListPodData) - -# InspectPod takes the name or ID of an image and returns a string representation of data associated with the -# pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will -# be returned if the pod cannot be found. -method InspectPod(name: string) -> (pod: string) - -# StartPod starts containers in a pod. It takes the name or ID of pod. If the pod cannot be found, a [PodNotFound](#PodNotFound) -# error will be returned. Containers in a pod are started independently. If there is an error starting one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was started with no errors, the pod ID is returned. -# See also [CreatePod](#CreatePod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.StartPod '{"name": "135d71b9495f"}' -# { -# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6", -# } -# ~~~ -method StartPod(name: string) -> (pod: string) - -# StopPod stops containers in a pod. It takes the name or ID of a pod and a timeout. -# If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead. -# Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was stopped with no errors, the pod ID is returned. -# See also [KillPod](KillPod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71b9495f"}' -# { -# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -# } -# ~~~ -method StopPod(name: string, timeout: int) -> (pod: string) - -# RestartPod will restart containers in a pod given a pod name or ID. Containers in -# the pod that are running will be stopped, then all stopped containers will be run. -# If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. -# Containers in a pod are restarted independently. If there is an error restarting one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was restarted with no errors, the pod ID is returned. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.RestartPod '{"name": "135d71b9495f"}' -# { -# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" -# } -# ~~~ -method RestartPod(name: string) -> (pod: string) - -# KillPod takes the name or ID of a pod as well as a signal to be applied to the pod. If the pod cannot be found, a -# [PodNotFound](#PodNotFound) error is returned. -# Containers in a pod are killed independently. If there is an error killing one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was killed with no errors, the pod ID is returned. -# See also [StopPod](StopPod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.KillPod '{"name": "foobar", "signal": 15}' -# { -# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -# } -# ~~~ -method KillPod(name: string, signal: int) -> (pod: string) - -# PausePod takes the name or ID of a pod and pauses the running containers associated with it. If the pod cannot be found, -# a [PodNotFound](#PodNotFound) error will be returned. -# Containers in a pod are paused independently. If there is an error pausing one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was paused with no errors, the pod ID is returned. -# See also [UnpausePod](#UnpausePod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.PausePod '{"name": "foobar"}' -# { -# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -# } -# ~~~ -method PausePod(name: string) -> (pod: string) - -# UnpausePod takes the name or ID of a pod and unpauses the paused containers associated with it. If the pod cannot be -# found, a [PodNotFound](#PodNotFound) error will be returned. -# Containers in a pod are unpaused independently. If there is an error unpausing one container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was unpaused with no errors, the pod ID is returned. -# See also [PausePod](#PausePod). -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foobar"}' -# { -# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f" -# } -# ~~~ -method UnpausePod(name: string) -> (pod: string) - -# RemovePod takes the name or ID of a pod as well a boolean representing whether a running -# container in the pod can be stopped and removed. If a pod has containers associated with it, and force is not true, -# an error will occur. -# If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. -# Containers in a pod are removed independently. If there is an error removing any container, the ID of those containers -# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). -# If the pod was removed with no errors, the pod ID is returned. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4fd98cb57", "force": "true"}' -# { -# "pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" -# } -# ~~~ -method RemovePod(name: string, force: bool) -> (pod: string) - -# This method has not be implemented yet. -# method WaitPod() -> (notimplemented: NotImplemented) - -method TopPod(pod: string, latest: bool, descriptors: []string) -> (stats: []string) - -# GetPodStats takes the name or ID of a pod and returns a pod name and slice of ContainerStats structure which -# contains attributes like memory and cpu usage. If the pod cannot be found, a [PodNotFound](#PodNotFound) -# error will be returned. If the pod has no running containers associated with it, a [NoContainerRunning](#NoContainerRunning) -# error will be returned. -# #### Example -# ~~~ -# $ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b508b6f12b11d8fe02e"}' -# { -# "containers": [ -# { -# "block_input": 0, -# "block_output": 0, -# "cpu": 2.833470544016107524276e-08, -# "cpu_nano": 54363072, -# "id": "a64b51f805121fe2c5a3dc5112eb61d6ed139e3d1c99110360d08b58d48e4a93", -# "mem_limit": 12276146176, -# "mem_perc": 7.974359265237864966003e-03, -# "mem_usage": 978944, -# "name": "quirky_heisenberg", -# "net_input": 866, -# "net_output": 7388, -# "pids": 1, -# "system_nano": 20000000 -# } -# ], -# "pod": "7f62b508b6f12b11d8fe02e0db4de6b9e43a7d7699b33a4fc0d574f6e82b4ebd" -# } -# ~~~ -method GetPodStats(name: string) -> (pod: string, containers: []ContainerStats) - -# GetPodsByStatus searches for pods whose status is included in statuses -method GetPodsByStatus(statuses: []string) -> (pods: []string) - -# ImageExists talks a full or partial image ID or name and returns an int as to whether -# the image exists in local storage. An int result of 0 means the image does exist in -# local storage; whereas 1 indicates the image does not exists in local storage. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ImageExists '{"name": "imageddoesntexist"}' -# { -# "exists": 1 -# } -# ~~~ -method ImageExists(name: string) -> (exists: int) - -# ImageTree returns the image tree for the provided image name or ID -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ImageTree '{"name": "alpine"}' -# { -# "tree": "Image ID: e7d92cdc71fe\nTags: [docker.io/library/alpine:latest]\nSize: 5.861MB\nImage Layers\n└── ID: 5216338b40a7 Size: 5.857MB Top Layer of: [docker.io/library/alpine:latest]\n" -# } -# ~~~ -method ImageTree(name: string, whatRequires: bool) -> (tree: string) - -# ContainerExists takes a full or partial container ID or name and returns an int as to -# whether the container exists in local storage. A result of 0 means the container does -# exists; whereas a result of 1 means it could not be found. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ContainerExists '{"name": "flamboyant_payne"}'{ -# "exists": 0 -# } -# ~~~ -method ContainerExists(name: string) -> (exists: int) - -# ContainerCheckPoint performs a checkpopint on a container by its name or full/partial container -# ID. On successful checkpoint, the id of the checkpointed container is returned. -method ContainerCheckpoint(name: string, keep: bool, leaveRunning: bool, tcpEstablished: bool) -> (id: string) - -# ContainerRestore restores a container that has been checkpointed. The container to be restored can -# be identified by its name or full/partial container ID. A successful restore will result in the return -# of the container's ID. -method ContainerRestore(name: string, keep: bool, tcpEstablished: bool) -> (id: string) - -# ContainerRunlabel runs executes a command as described by a given container image label. -method ContainerRunlabel(runlabel: Runlabel) -> () - -# ExecContainer executes a command in the given container. -method ExecContainer(opts: ExecOpts) -> () - -# ListContainerMounts gathers all the mounted container mount points and returns them as an array -# of strings -# #### Example -# ~~~ -# $ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts -# { -# "mounts": { -# "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged", -# "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged" -# } -# } -# ~~~ -method ListContainerMounts() -> (mounts: [string]string) - -# MountContainer mounts a container by name or full/partial ID. Upon a successful mount, the destination -# mount is returned as a string. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.MountContainer '{"name": "jolly_shannon"}'{ -# "path": "/var/lib/containers/storage/overlay/419eeb04e783ea159149ced67d9fcfc15211084d65e894792a96bedfae0470ca/merged" -# } -# ~~~ -method MountContainer(name: string) -> (path: string) - -# UnmountContainer umounts a container by its name or full/partial container ID. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.UnmountContainer '{"name": "jolly_shannon", "force": false}' -# {} -# ~~~ -method UnmountContainer(name: string, force: bool) -> () - -# ImagesPrune removes all unused images from the local store. Upon successful pruning, -# the IDs of the removed images are returned. -method ImagesPrune(all: bool, filter: []string) -> (pruned: []string) - -# This function is not implemented yet. -# method ListContainerPorts(name: string) -> (notimplemented: NotImplemented) - -# GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod -# and its containers. The description is in YAML. See also [ReplayKube](ReplayKube). -method GenerateKube(name: string, service: bool) -> (pod: KubePodService) - -# ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML) -# like that created by GenerateKube. See also [GenerateKube](GenerateKube). -# method ReplayKube() -> (notimplemented: NotImplemented) - -# ContainerConfig returns a container's config in string form. This call is for -# development of Podman only and generally should not be used. -method ContainerConfig(name: string) -> (config: string) - -# ContainerArtifacts returns a container's artifacts in string form. This call is for -# development of Podman only and generally should not be used. -method ContainerArtifacts(name: string, artifactName: string) -> (config: string) - -# ContainerInspectData returns a container's inspect data in string form. This call is for -# development of Podman only and generally should not be used. -method ContainerInspectData(name: string, size: bool) -> (config: string) - -# ContainerStateData returns a container's state config in string form. This call is for -# development of Podman only and generally should not be used. -method ContainerStateData(name: string) -> (config: string) - -# PodStateData returns inspectr level information of a given pod in string form. This call is for -# development of Podman only and generally should not be used. -method PodStateData(name: string) -> (config: string) - -# This call is for the development of Podman only and should not be used. -method CreateFromCC(in: []string) -> (id: string) - -# Spec returns the oci spec for a container. This call is for development of Podman only and generally should not be used. -method Spec(name: string) -> (config: string) - -# Sendfile allows a remote client to send a file to the host -method SendFile(type: string, length: int) -> (file_handle: string) - -# ReceiveFile allows the host to send a remote client a file -method ReceiveFile(path: string, delete: bool) -> (len: int) - -# VolumeCreate creates a volume on a remote host -method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string) - -# VolumeRemove removes a volume on a remote host -method VolumeRemove(options: VolumeRemoveOpts) -> (successes: []string, failures: [string]string) - -# GetVolumes gets slice of the volumes on a remote host -method GetVolumes(args: []string, all: bool) -> (volumes: []Volume) - -# InspectVolume inspects a single volume. Returns inspect JSON in the form of a -# string. -method InspectVolume(name: string) -> (volume: string) - -# VolumesPrune removes unused volumes on the host -method VolumesPrune() -> (prunedNames: []string, prunedErrors: []string) - -# ImageSave allows you to save an image from the local image storage to a tarball -method ImageSave(options: ImageSaveOptions) -> (reply: MoreResponse) - -# GetPodsByContext allows you to get a list pod ids depending on all, latest, or a list of -# pod names. The definition of latest pod means the latest by creation date. In a multi- -# user environment, results might differ from what you expect. -method GetPodsByContext(all: bool, latest: bool, args: []string) -> (pods: []string) - -# LoadImage allows you to load an image into local storage from a tarball. -method LoadImage(name: string, inputFile: string, quiet: bool, deleteFile: bool) -> (reply: MoreResponse) - -# GetEvents returns known libpod events filtered by the options provided. -method GetEvents(filter: []string, since: string, until: string) -> (events: Event) - -# Diff returns a diff between libpod objects -method Diff(name: string) -> (diffs: []DiffInfo) - -# GetLayersMapWithImageInfo is for the development of Podman and should not be used. -method GetLayersMapWithImageInfo() -> (layerMap: string) - -# BuildImageHierarchyMap is for the development of Podman and should not be used. -method BuildImageHierarchyMap(name: string) -> (imageInfo: string) - -# ImageNotFound means the image could not be found by the provided name or ID in local storage. -error ImageNotFound (id: string, reason: string) - -# ContainerNotFound means the container could not be found by the provided name or ID in local storage. -error ContainerNotFound (id: string, reason: string) - -# NoContainerRunning means none of the containers requested are running in a command that requires a running container. -error NoContainerRunning () - -# PodNotFound means the pod could not be found by the provided name or ID in local storage. -error PodNotFound (name: string, reason: string) - -# VolumeNotFound means the volume could not be found by the name or ID in local storage. -error VolumeNotFound (id: string, reason: string) - -# PodContainerError means a container associated with a pod failed to perform an operation. It contains -# a container ID of the container that failed. -error PodContainerError (podname: string, errors: []PodContainerErrorData) - -# NoContainersInPod means a pod has no containers on which to perform the operation. It contains -# the pod ID. -error NoContainersInPod (name: string) - -# InvalidState indicates that a container or pod was in an improper state for the requested operation -error InvalidState (id: string, reason: string) - -# ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message -# is includes as part of the error's text. -error ErrorOccurred (reason: string) - -# RuntimeErrors generally means a runtime could not be found or gotten. -error RuntimeError (reason: string) - -# The Podman endpoint requires that you use a streaming connection. -error WantsMoreRequired (reason: string) - -# Container is already stopped -error ErrCtrStopped (id: string) - -# This function requires CGroupsV2 to run in rootless mode. -error ErrRequiresCgroupsV2ForRootless(reason: string) diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go deleted file mode 100644 index 38354a790..000000000 --- a/pkg/varlinkapi/attach.go +++ /dev/null @@ -1,144 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "bufio" - "context" - "io" - - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/events" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/podman/v2/pkg/varlinkapi/virtwriter" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "k8s.io/client-go/tools/remotecommand" -) - -func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *define.AttachStreams) { - - // These are the varlink sockets - reader := call.Call.Reader - writer := call.Call.Writer - - // This pipe is used to pass stdin from the client to the input stream - // once the msg has been "decoded" - pr, pw := io.Pipe() - - stdoutWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdout) - // TODO if runc ever starts passing stderr, we can too - // stderrWriter := NewVirtWriteCloser(writer, ToStderr) - - streams := define.AttachStreams{ - OutputStream: stdoutWriter, - InputStream: bufio.NewReader(pr), - // Runc eats the error stream - ErrorStream: stdoutWriter, - AttachInput: true, - AttachOutput: true, - // Runc eats the error stream - AttachError: true, - } - return reader, writer, pr, pw, &streams -} - -// Attach connects to a containers console -func (i *VarlinkAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys string, start bool) error { - var finalErr error - resize := make(chan remotecommand.TerminalSize) - errChan := make(chan error) - - if !call.WantsUpgrade() { - return call.ReplyErrorOccurred("client must use upgraded connection to attach") - } - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - state, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if !start && state != define.ContainerStateRunning { - return call.ReplyErrorOccurred("container must be running to attach") - } - - // ACK the client upgrade request - if err := call.ReplyAttach(); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - reader, writer, _, pw, streams := setupStreams(call) - go func() { - if err := virtwriter.Reader(reader, nil, nil, pw, resize, nil); err != nil { - errChan <- err - } - }() - - if state == define.ContainerStateRunning { - finalErr = attach(ctr, streams, detachKeys, resize, errChan) - } else { - finalErr = startAndAttach(ctr, streams, detachKeys, resize, errChan) - } - - exitCode := define.ExitCode(finalErr) - if finalErr != define.ErrDetach && finalErr != nil { - logrus.Error(finalErr) - } else { - if ecode, err := ctr.Wait(); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - // Check events - event, err := i.Runtime.GetLastContainerEvent(context.Background(), ctr.ID(), events.Exited) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - exitCode = define.ExecErrorCodeNotFound - } else { - exitCode = event.ContainerExitCode - } - } else { - exitCode = define.ExitCode(err) - } - } else { - exitCode = int(ecode) - } - } - - if ctr.AutoRemove() { - err := i.Runtime.RemoveContainer(getContext(), ctr, false, false) - if err != nil { - logrus.Errorf("Failed to remove container %s: %s", ctr.ID(), err.Error()) - } - } - - if err = virtwriter.HangUp(writer, uint32(exitCode)); err != nil { - logrus.Errorf("Failed to HANG-UP attach to %s: %s", ctr.ID(), err.Error()) - } - return call.Writer.Flush() -} - -func attach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error { - go func() { - if err := ctr.Attach(streams, detachKeys, resize); err != nil { - errChan <- err - } - }() - attachError := <-errChan - return attachError -} - -func startAndAttach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error { - var finalErr error - attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, false) - if err != nil { - return err - } - select { - case attachChanErr := <-attachChan: - finalErr = attachChanErr - case chanError := <-errChan: - finalErr = chanError - } - return finalErr -} diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go deleted file mode 100644 index 50e6fb833..000000000 --- a/pkg/varlinkapi/config.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "github.com/containers/podman/v2/libpod" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/spf13/cobra" -) - -// VarlinkAPI is the basic varlink struct for libpod -type VarlinkAPI struct { - Cli *cobra.Command - iopodman.VarlinkInterface - Runtime *libpod.Runtime -} - -// New creates a new varlink client -func New(cli *cobra.Command, runtime *libpod.Runtime) *iopodman.VarlinkInterface { - lp := VarlinkAPI{Cli: cli, Runtime: runtime} - return iopodman.VarlinkNew(&lp) -} diff --git a/pkg/varlinkapi/container.go b/pkg/varlinkapi/container.go deleted file mode 100644 index c4e8c1feb..000000000 --- a/pkg/varlinkapi/container.go +++ /dev/null @@ -1,928 +0,0 @@ -package varlinkapi - -import ( - "context" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "runtime" - "sort" - "strconv" - "strings" - "sync" - "time" - - "github.com/containers/image/v5/types" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/image" - "github.com/containers/podman/v2/pkg/timetype" - "github.com/containers/podman/v2/pkg/util" - "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/docker/go-units" - "github.com/google/shlex" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - v1 "k8s.io/api/core/v1" -) - -const ( - cidTruncLength = 12 - podTruncLength = 12 - iidTruncLength = 12 - cmdTruncLength = 17 -) - -// PsOptions describes the struct being formed for ps. -type PsOptions struct { - All bool - Format string - Last int - Latest bool - NoTrunc bool - Pod bool - Quiet bool - Size bool - Sort string - Namespace bool - Sync bool -} - -// BatchContainerStruct is the return object from BatchContainer and contains -// container related information. -type BatchContainerStruct struct { - ConConfig *libpod.ContainerConfig - ConState define.ContainerStatus - ExitCode int32 - Exited bool - Pid int - StartedTime time.Time - ExitedTime time.Time - Size *ContainerSize -} - -// PsContainerOutput is the struct being returned from a parallel -// batch operation. -type PsContainerOutput struct { - ID string - Image string - ImageID string - Command string - Created string - Ports string - Names string - IsInfra bool - Status string - State define.ContainerStatus - Pid int - Size *ContainerSize - Pod string - PodName string - CreatedAt time.Time - ExitedAt time.Time - StartedAt time.Time - Labels map[string]string - PID string - Cgroup string - IPC string - MNT string - NET string - PIDNS string - User string - UTS string - Mounts string -} - -// Namespace describes output for ps namespace. -type Namespace struct { - PID string `json:"pid,omitempty"` - Cgroup string `json:"cgroup,omitempty"` - IPC string `json:"ipc,omitempty"` - MNT string `json:"mnt,omitempty"` - NET string `json:"net,omitempty"` - PIDNS string `json:"pidns,omitempty"` - User string `json:"user,omitempty"` - UTS string `json:"uts,omitempty"` -} - -// ContainerSize holds the size of the container's root filesystem and top -// read-write layer. -type ContainerSize struct { - RootFsSize int64 `json:"rootFsSize"` - RwSize int64 `json:"rwSize"` -} - -// NewBatchContainer runs a batch process under one lock to get container information and only -// be called in PBatch. -func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions) (PsContainerOutput, error) { - var ( - conState define.ContainerStatus - command string - created string - status string - exitedAt time.Time - startedAt time.Time - exitCode int32 - err error - pid int - size *ContainerSize - ns *Namespace - pso PsContainerOutput - ) - batchErr := ctr.Batch(func(c *libpod.Container) error { - if opts.Sync { - if err := c.Sync(); err != nil { - return err - } - } - - conState, err = c.State() - if err != nil { - return errors.Wrapf(err, "unable to obtain container state") - } - command = strings.Join(c.Command(), " ") - created = units.HumanDuration(time.Since(c.CreatedTime())) + " ago" - - exitCode, _, err = c.ExitCode() - if err != nil { - return errors.Wrapf(err, "unable to obtain container exit code") - } - startedAt, err = c.StartedTime() - if err != nil { - logrus.Errorf("error getting started time for %q: %v", c.ID(), err) - } - exitedAt, err = c.FinishedTime() - if err != nil { - logrus.Errorf("error getting exited time for %q: %v", c.ID(), err) - } - if opts.Namespace { - pid, err = c.PID() - if err != nil { - return errors.Wrapf(err, "unable to obtain container pid") - } - ns = GetNamespaces(pid) - } - if opts.Size { - size = new(ContainerSize) - - rootFsSize, err := c.RootFsSize() - if err != nil { - logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err) - } - - rwSize, err := c.RWSize() - if err != nil { - logrus.Errorf("error getting rw size for %q: %v", c.ID(), err) - } - - size.RootFsSize = rootFsSize - size.RwSize = rwSize - } - - return nil - }) - - if batchErr != nil { - return pso, batchErr - } - - switch conState.String() { - case define.ContainerStateExited.String(): - fallthrough - case define.ContainerStateStopped.String(): - exitedSince := units.HumanDuration(time.Since(exitedAt)) - status = fmt.Sprintf("Exited (%d) %s ago", exitCode, exitedSince) - case define.ContainerStateRunning.String(): - status = "Up " + units.HumanDuration(time.Since(startedAt)) + " ago" - case define.ContainerStatePaused.String(): - status = "Paused" - case define.ContainerStateCreated.String(), define.ContainerStateConfigured.String(): - status = "Created" - case define.ContainerStateRemoving.String(): - status = "Removing" - default: - status = "Error" - } - - imageID, imageName := ctr.Image() - cid := ctr.ID() - podID := ctr.PodID() - if !opts.NoTrunc { - cid = cid[0:cidTruncLength] - if len(podID) > podTruncLength { - podID = podID[0:podTruncLength] - } - if len(command) > cmdTruncLength { - command = command[0:cmdTruncLength] + "..." - } - if len(imageID) > iidTruncLength { - imageID = imageID[0:iidTruncLength] - } - } - - ports, err := ctr.PortMappings() - if err != nil { - logrus.Errorf("unable to lookup namespace container for %s", ctr.ID()) - } - - pso.ID = cid - pso.Image = imageName - pso.ImageID = imageID - pso.Command = command - pso.Created = created - pso.Ports = portsToString(ports) - pso.Names = ctr.Name() - pso.IsInfra = ctr.IsInfra() - pso.Status = status - pso.State = conState - pso.Pid = pid - pso.Size = size - pso.ExitedAt = exitedAt - pso.CreatedAt = ctr.CreatedTime() - pso.StartedAt = startedAt - pso.Labels = ctr.Labels() - pso.Mounts = strings.Join(ctr.UserVolumes(), " ") - - // Add pod name and pod ID if requested by user. - // No need to look up the pod if its ID is empty. - if opts.Pod && len(podID) > 0 { - // The pod name is not in the container definition - // so we need to retrieve it using the pod ID. - var podName string - pod, err := r.LookupPod(podID) - if err != nil { - logrus.Errorf("unable to lookup pod for container %s", ctr.ID()) - } else { - podName = pod.Name() - } - - pso.Pod = podID - pso.PodName = podName - } - - if opts.Namespace { - pso.Cgroup = ns.Cgroup - pso.IPC = ns.IPC - pso.MNT = ns.MNT - pso.NET = ns.NET - pso.User = ns.User - pso.UTS = ns.UTS - pso.PIDNS = ns.PIDNS - } - - return pso, nil -} - -type batchFunc func() (PsContainerOutput, error) - -type workerInput struct { - parallelFunc batchFunc - opts PsOptions - cid string - job int -} - -// worker is a "threaded" worker that takes jobs from the channel "queue". -func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContainerOutput, errors chan<- error) { - for j := range jobs { - r, err := j.parallelFunc() - // If we find an error, we return just the error. - if err != nil { - errors <- err - } else { - // Return the result. - results <- r - } - wg.Done() - } -} - -// GenerateContainerFilterFuncs return ContainerFilter functions based of filter. -func GenerateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) { - switch filter { - case "id": - return func(c *libpod.Container) bool { - return strings.Contains(c.ID(), filterValue) - }, nil - case "label": - var filterArray = strings.SplitN(filterValue, "=", 2) - var filterKey = filterArray[0] - if len(filterArray) > 1 { - filterValue = filterArray[1] - } else { - filterValue = "" - } - return func(c *libpod.Container) bool { - for labelKey, labelValue := range c.Labels() { - if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { - return true - } - } - return false - }, nil - case "name": - return func(c *libpod.Container) bool { - match, err := regexp.MatchString(filterValue, c.Name()) - if err != nil { - return false - } - return match - }, nil - case "exited": - exitCode, err := strconv.ParseInt(filterValue, 10, 32) - if err != nil { - return nil, errors.Wrapf(err, "exited code out of range %q", filterValue) - } - return func(c *libpod.Container) bool { - ec, exited, err := c.ExitCode() - if ec == int32(exitCode) && err == nil && exited { - return true - } - return false - }, nil - case "status": - if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) { - return nil, errors.Errorf("%s is not a valid status", filterValue) - } - return func(c *libpod.Container) bool { - status, err := c.State() - if err != nil { - return false - } - if filterValue == "stopped" { - filterValue = "exited" - } - state := status.String() - if status == define.ContainerStateConfigured { - state = "created" - } else if status == define.ContainerStateStopped { - state = "exited" - } - return state == filterValue - }, nil - case "ancestor": - // This needs to refine to match docker - // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant. - return func(c *libpod.Container) bool { - containerConfig := c.Config() - if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) { - return true - } - return false - }, nil - case "before": - ctr, err := r.LookupContainer(filterValue) - if err != nil { - return nil, errors.Errorf("unable to find container by name or id of %s", filterValue) - } - containerConfig := ctr.Config() - createTime := containerConfig.CreatedTime - return func(c *libpod.Container) bool { - cc := c.Config() - return createTime.After(cc.CreatedTime) - }, nil - case "since": - ctr, err := r.LookupContainer(filterValue) - if err != nil { - return nil, errors.Errorf("unable to find container by name or id of %s", filterValue) - } - containerConfig := ctr.Config() - createTime := containerConfig.CreatedTime - return func(c *libpod.Container) bool { - cc := c.Config() - return createTime.Before(cc.CreatedTime) - }, nil - case "volume": - //- volume=(<volume-name>|<mount-point-destination>) - return func(c *libpod.Container) bool { - containerConfig := c.Config() - var dest string - arr := strings.Split(filterValue, ":") - source := arr[0] - if len(arr) == 2 { - dest = arr[1] - } - for _, mount := range containerConfig.Spec.Mounts { - if dest != "" && (mount.Source == source && mount.Destination == dest) { - return true - } - if dest == "" && mount.Source == source { - return true - } - } - return false - }, nil - case "health": - return func(c *libpod.Container) bool { - hcStatus, err := c.HealthCheckStatus() - if err != nil { - return false - } - return hcStatus == filterValue - }, nil - case "until": - ts, err := timetype.GetTimestamp(filterValue, time.Now()) - if err != nil { - return nil, err - } - seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) - if err != nil { - return nil, err - } - until := time.Unix(seconds, nanoseconds) - return func(c *libpod.Container) bool { - if !until.IsZero() && c.CreatedTime().After((until)) { - return true - } - return false - }, nil - } - return nil, errors.Errorf("%s is an invalid filter", filter) -} - -// GetPsContainerOutput returns a slice of containers specifically for ps output. -func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, maxWorkers int) ([]PsContainerOutput, error) { - var ( - filterFuncs []libpod.ContainerFilter - outputContainers []*libpod.Container - ) - - if len(filters) > 0 { - for _, f := range filters { - filterSplit := strings.SplitN(f, "=", 2) - if len(filterSplit) < 2 { - return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) - } - generatedFunc, err := GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r) - if err != nil { - return nil, errors.Wrapf(err, "invalid filter") - } - filterFuncs = append(filterFuncs, generatedFunc) - } - } - if !opts.Latest { - // Get all containers. - containers, err := r.GetContainers(filterFuncs...) - if err != nil { - return nil, err - } - - // We only want the last few containers. - if opts.Last > 0 && opts.Last <= len(containers) { - return nil, errors.Errorf("--last not yet supported") - } else { - outputContainers = containers - } - } else { - // Get just the latest container. - // Ignore filters. - latestCtr, err := r.GetLatestContainer() - if err != nil { - return nil, err - } - - outputContainers = []*libpod.Container{latestCtr} - } - - pss := PBatch(r, outputContainers, maxWorkers, opts) - return pss, nil -} - -// PBatch performs batch operations on a container in parallel. It spawns the -// number of workers relative to the number of parallel operations desired. -func PBatch(r *libpod.Runtime, containers []*libpod.Container, workers int, opts PsOptions) []PsContainerOutput { - var wg sync.WaitGroup - psResults := []PsContainerOutput{} - - // If the number of containers in question is less than the number of - // proposed parallel operations, we shouldn't spawn so many workers. - if workers > len(containers) { - workers = len(containers) - } - - jobs := make(chan workerInput, len(containers)) - results := make(chan PsContainerOutput, len(containers)) - batchErrors := make(chan error, len(containers)) - - // Create the workers. - for w := 1; w <= workers; w++ { - go worker(&wg, jobs, results, batchErrors) - } - - // Add jobs to the workers. - for i, j := range containers { - j := j - wg.Add(1) - f := func() (PsContainerOutput, error) { - return NewBatchContainer(r, j, opts) - } - jobs <- workerInput{ - parallelFunc: f, - opts: opts, - cid: j.ID(), - job: i, - } - } - close(jobs) - wg.Wait() - close(results) - close(batchErrors) - for err := range batchErrors { - logrus.Errorf("unable to get container info: %q", err) - } - for res := range results { - // We sort out running vs non-running here to save lots of copying - // later. - if !opts.All && !opts.Latest && opts.Last < 1 { - if !res.IsInfra && res.State == define.ContainerStateRunning { - psResults = append(psResults, res) - } - } else { - psResults = append(psResults, res) - } - } - return psResults -} - -// BatchContainerOp is used in ps to reduce performance hits by "batching" -// locks. -func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStruct, error) { - var ( - conConfig *libpod.ContainerConfig - conState define.ContainerStatus - err error - exitCode int32 - exited bool - pid int - size *ContainerSize - startedTime time.Time - exitedTime time.Time - ) - - batchErr := ctr.Batch(func(c *libpod.Container) error { - conConfig = c.Config() - conState, err = c.State() - if err != nil { - return errors.Wrapf(err, "unable to obtain container state") - } - - exitCode, exited, err = c.ExitCode() - if err != nil { - return errors.Wrapf(err, "unable to obtain container exit code") - } - startedTime, err = c.StartedTime() - if err != nil { - logrus.Errorf("error getting started time for %q: %v", c.ID(), err) - } - exitedTime, err = c.FinishedTime() - if err != nil { - logrus.Errorf("error getting exited time for %q: %v", c.ID(), err) - } - - if !opts.Size && !opts.Namespace { - return nil - } - - if opts.Namespace { - pid, err = c.PID() - if err != nil { - return errors.Wrapf(err, "unable to obtain container pid") - } - } - if opts.Size { - size = new(ContainerSize) - - rootFsSize, err := c.RootFsSize() - if err != nil { - logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err) - } - - rwSize, err := c.RWSize() - if err != nil { - logrus.Errorf("error getting rw size for %q: %v", c.ID(), err) - } - - size.RootFsSize = rootFsSize - size.RwSize = rwSize - } - return nil - }) - if batchErr != nil { - return BatchContainerStruct{}, batchErr - } - return BatchContainerStruct{ - ConConfig: conConfig, - ConState: conState, - ExitCode: exitCode, - Exited: exited, - Pid: pid, - StartedTime: startedTime, - ExitedTime: exitedTime, - Size: size, - }, nil -} - -// GetNamespaces returns a populated namespace struct. -func GetNamespaces(pid int) *Namespace { - ctrPID := strconv.Itoa(pid) - cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup")) - ipc, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc")) - mnt, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt")) - net, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net")) - pidns, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid")) - user, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user")) - uts, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts")) - - return &Namespace{ - PID: ctrPID, - Cgroup: cgroup, - IPC: ipc, - MNT: mnt, - NET: net, - PIDNS: pidns, - User: user, - UTS: uts, - } -} - -// GetNamespaceInfo is an exported wrapper for getNamespaceInfo -func GetNamespaceInfo(path string) (string, error) { - return getNamespaceInfo(path) -} - -func getNamespaceInfo(path string) (string, error) { - val, err := os.Readlink(path) - if err != nil { - return "", errors.Wrapf(err, "error getting info from %q", path) - } - return getStrFromSquareBrackets(val), nil -} - -// getStrFromSquareBrackets gets the string inside [] from a string. -func getStrFromSquareBrackets(cmd string) string { - reg := regexp.MustCompile(`.*\[|\].*`) - arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",") - return strings.Join(arr, ",") -} - -func comparePorts(i, j ocicni.PortMapping) bool { - if i.ContainerPort != j.ContainerPort { - return i.ContainerPort < j.ContainerPort - } - - if i.HostIP != j.HostIP { - return i.HostIP < j.HostIP - } - - if i.HostPort != j.HostPort { - return i.HostPort < j.HostPort - } - - return i.Protocol < j.Protocol -} - -// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto> -// e.g 0.0.0.0:1000-1006->1000-1006/tcp. -func formatGroup(key string, start, last int32) string { - parts := strings.Split(key, "/") - groupType := parts[0] - var ip string - if len(parts) > 1 { - ip = parts[0] - groupType = parts[1] - } - group := strconv.Itoa(int(start)) - if start != last { - group = fmt.Sprintf("%s-%d", group, last) - } - if ip != "" { - group = fmt.Sprintf("%s:%s->%s", ip, group, group) - } - return fmt.Sprintf("%s/%s", group, groupType) -} - -// portsToString converts the ports used to a string of the from "port1, port2" -// and also groups a continuous list of ports into a readable format. -func portsToString(ports []ocicni.PortMapping) string { - type portGroup struct { - first int32 - last int32 - } - var portDisplay []string - if len(ports) == 0 { - return "" - } - //Sort the ports, so grouping continuous ports become easy. - sort.Slice(ports, func(i, j int) bool { - return comparePorts(ports[i], ports[j]) - }) - - // portGroupMap is used for grouping continuous ports. - portGroupMap := make(map[string]*portGroup) - var groupKeyList []string - - for _, v := range ports { - - hostIP := v.HostIP - if hostIP == "" { - hostIP = "0.0.0.0" - } - // If hostPort and containerPort are not same, consider as individual port. - if v.ContainerPort != v.HostPort { - portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol)) - continue - } - - portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol) - - portgroup, ok := portGroupMap[portMapKey] - if !ok { - portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort} - // This list is required to traverse portGroupMap. - groupKeyList = append(groupKeyList, portMapKey) - continue - } - - if portgroup.last == (v.ContainerPort - 1) { - portgroup.last = v.ContainerPort - continue - } - } - // For each portMapKey, format group list and append to output string. - for _, portKey := range groupKeyList { - group := portGroupMap[portKey] - portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last)) - } - return strings.Join(portDisplay, ", ") -} - -// GetRunlabel is a helper function for runlabel; it gets the image if needed and begins the -// construction of the runlabel output and environment variables. -func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtime *libpod.Runtime, pull bool, inputCreds string, dockerRegistryOptions image.DockerRegistryOptions, authfile string, signaturePolicyPath string, output io.Writer) (string, string, error) { - var ( - newImage *image.Image - err error - imageName string - ) - if pull { - var registryCreds *types.DockerAuthConfig - if inputCreds != "" { - creds, err := util.ParseRegistryCreds(inputCreds) - if err != nil { - return "", "", err - } - registryCreds = creds - } - dockerRegistryOptions.DockerRegistryCreds = registryCreds - newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, &label, util.PullImageMissing) - } else { - newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage) - } - if err != nil { - return "", "", errors.Wrapf(err, "unable to find image") - } - - if len(newImage.Names()) < 1 { - imageName = newImage.ID() - } else { - imageName = newImage.Names()[0] - } - - runLabel, err := newImage.GetLabel(ctx, label) - return runLabel, imageName, err -} - -// GenerateRunlabelCommand generates the command that will eventually be executed by Podman. -func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) { - // If no name is provided, we use the image's basename instead. - if name == "" { - baseName, err := image.GetImageBaseName(imageName) - if err != nil { - return nil, nil, err - } - name = baseName - } - // The user provided extra arguments that need to be tacked onto the label's command. - if len(extraArgs) > 0 { - runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(extraArgs, " ")) - } - cmd, err := GenerateCommand(runLabel, imageName, name, globalOpts) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to generate command") - } - env := GenerateRunEnvironment(name, imageName, opts) - env = append(env, "PODMAN_RUNLABEL_NESTED=1") - - envmap := envSliceToMap(env) - - envmapper := func(k string) string { - switch k { - case "OPT1": - return envmap["OPT1"] - case "OPT2": - return envmap["OPT2"] - case "OPT3": - return envmap["OPT3"] - case "PWD": - // I would prefer to use os.getenv but it appears PWD is not in the os env list. - d, err := os.Getwd() - if err != nil { - logrus.Error("unable to determine current working directory") - return "" - } - return d - } - return "" - } - newS := os.Expand(strings.Join(cmd, " "), envmapper) - cmd, err = shlex.Split(newS) - if err != nil { - return nil, nil, err - } - return cmd, env, nil -} - -func envSliceToMap(env []string) map[string]string { - m := make(map[string]string) - for _, i := range env { - split := strings.Split(i, "=") - m[split[0]] = strings.Join(split[1:], " ") - } - return m -} - -// GenerateKube generates kubernetes yaml based on a pod or container. -func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Service, error) { - var ( - pod *libpod.Pod - podYAML *v1.Pod - err error - container *libpod.Container - servicePorts []v1.ServicePort - serviceYAML v1.Service - ) - // Get the container in question. - container, err = r.LookupContainer(name) - if err != nil { - pod, err = r.LookupPod(name) - if err != nil { - return nil, nil, err - } - podYAML, servicePorts, err = pod.GenerateForKube() - } else { - if len(container.Dependencies()) > 0 { - return nil, nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies") - } - podYAML, err = container.GenerateForKube() - } - if err != nil { - return nil, nil, err - } - - if service { - serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts) - } - return podYAML, &serviceYAML, nil -} - -// Parallelize provides the maximum number of parallel workers (int) as calculated by a basic -// heuristic. This can be overridden by the --max-workers primary switch to podman. -func Parallelize(job string) int { - numCpus := runtime.NumCPU() - switch job { - case "kill": - if numCpus <= 3 { - return numCpus * 3 - } - return numCpus * 4 - case "pause": - if numCpus <= 3 { - return numCpus * 3 - } - return numCpus * 4 - case "ps": - return 8 - case "restart": - return numCpus * 2 - case "rm": - if numCpus <= 3 { - return numCpus * 3 - } else { - return numCpus * 4 - } - case "stop": - if numCpus <= 2 { - return 4 - } else { - return numCpus * 3 - } - case "unpause": - if numCpus <= 3 { - return numCpus * 3 - } - return numCpus * 4 - } - return 3 -} diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go deleted file mode 100644 index fef3b6476..000000000 --- a/pkg/varlinkapi/containers.go +++ /dev/null @@ -1,912 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "sync" - "syscall" - "time" - - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/logs" - "github.com/containers/podman/v2/pkg/cgroups" - "github.com/containers/podman/v2/pkg/rootless" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/podman/v2/pkg/varlinkapi/virtwriter" - "github.com/containers/storage/pkg/archive" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "k8s.io/client-go/tools/remotecommand" -) - -// ListContainers ... -func (i *VarlinkAPI) ListContainers(call iopodman.VarlinkCall) error { - var ( - listContainers []iopodman.Container - ) - - containers, err := i.Runtime.GetAllContainers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - opts := PsOptions{ - Namespace: true, - Size: true, - } - for _, ctr := range containers { - batchInfo, err := BatchContainerOp(ctr, opts) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - listContainers = append(listContainers, makeListContainer(ctr.ID(), batchInfo)) - } - return call.ReplyListContainers(listContainers) -} - -func (i *VarlinkAPI) Ps(call iopodman.VarlinkCall, opts iopodman.PsOpts) error { - var ( - containers []iopodman.PsContainer - ) - maxWorkers := Parallelize("ps") - psOpts := makePsOpts(opts) - filters := []string{} - if opts.Filters != nil { - filters = *opts.Filters - } - psContainerOutputs, err := GetPsContainerOutput(i.Runtime, psOpts, filters, maxWorkers) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - for _, ctr := range psContainerOutputs { - container := iopodman.PsContainer{ - Id: ctr.ID, - Image: ctr.Image, - Command: ctr.Command, - Created: ctr.Created, - Ports: ctr.Ports, - Names: ctr.Names, - IsInfra: ctr.IsInfra, - Status: ctr.Status, - State: ctr.State.String(), - PidNum: int64(ctr.Pid), - Pod: ctr.Pod, - CreatedAt: ctr.CreatedAt.Format(time.RFC3339Nano), - ExitedAt: ctr.ExitedAt.Format(time.RFC3339Nano), - StartedAt: ctr.StartedAt.Format(time.RFC3339Nano), - Labels: ctr.Labels, - NsPid: ctr.PID, - Cgroup: ctr.Cgroup, - Ipc: ctr.Cgroup, - Mnt: ctr.MNT, - Net: ctr.NET, - PidNs: ctr.PIDNS, - User: ctr.User, - Uts: ctr.UTS, - Mounts: ctr.Mounts, - } - if ctr.Size != nil { - container.RootFsSize = ctr.Size.RootFsSize - container.RwSize = ctr.Size.RwSize - } - containers = append(containers, container) - } - return call.ReplyPs(containers) -} - -// GetContainer ... -func (i *VarlinkAPI) GetContainer(call iopodman.VarlinkCall, id string) error { - ctr, err := i.Runtime.LookupContainer(id) - if err != nil { - return call.ReplyContainerNotFound(id, err.Error()) - } - opts := PsOptions{ - Namespace: true, - Size: true, - } - batchInfo, err := BatchContainerOp(ctr, opts) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyGetContainer(makeListContainer(ctr.ID(), batchInfo)) -} - -// getContainersByContext returns a slice of container ids based on all, latest, or a list -func (i *VarlinkAPI) GetContainersByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error { - var ids []string - - ctrs, err := getContainersByContext(all, latest, input, i.Runtime) - if err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - return call.ReplyContainerNotFound("", err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - - for _, c := range ctrs { - ids = append(ids, c.ID()) - } - return call.ReplyGetContainersByContext(ids) -} - -// GetContainersByStatus returns a slice of containers filtered by a libpod status -func (i *VarlinkAPI) GetContainersByStatus(call iopodman.VarlinkCall, statuses []string) error { - var ( - filterFuncs []libpod.ContainerFilter - containers []iopodman.Container - ) - for _, status := range statuses { - lpstatus, err := define.StringToContainerStatus(status) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - filterFuncs = append(filterFuncs, func(c *libpod.Container) bool { - state, _ := c.State() - return state == lpstatus - }) - } - filteredContainers, err := i.Runtime.GetContainers(filterFuncs...) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - opts := PsOptions{Size: true, Namespace: true} - for _, ctr := range filteredContainers { - batchInfo, err := BatchContainerOp(ctr, opts) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - containers = append(containers, makeListContainer(ctr.ID(), batchInfo)) - } - return call.ReplyGetContainersByStatus(containers) -} - -// InspectContainer ... -func (i *VarlinkAPI) InspectContainer(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - data, err := ctr.Inspect(true) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(data) - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize")) - } - return call.ReplyInspectContainer(string(b)) -} - -// ListContainerProcesses ... -func (i *VarlinkAPI) ListContainerProcesses(call iopodman.VarlinkCall, name string, opts []string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - containerState, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if containerState != define.ContainerStateRunning { - return call.ReplyErrorOccurred(fmt.Sprintf("container %s is not running", name)) - } - var psArgs []string - psOpts := []string{"user", "pid", "ppid", "pcpu", "etime", "tty", "time", "comm"} - if len(opts) > 1 { - psOpts = opts - } - psArgs = append(psArgs, psOpts...) - psOutput, err := ctr.GetContainerPidInformation(psArgs) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - return call.ReplyListContainerProcesses(psOutput) -} - -// GetContainerLogs ... -func (i *VarlinkAPI) GetContainerLogs(call iopodman.VarlinkCall, name string) error { - var logs []string - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - logPath := ctr.LogPath() - - containerState, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if _, err := os.Stat(logPath); err != nil { - if containerState == define.ContainerStateConfigured { - return call.ReplyGetContainerLogs(logs) - } - } - file, err := os.Open(logPath) - if err != nil { - return errors.Wrapf(err, "unable to read container log file") - } - defer file.Close() - reader := bufio.NewReader(file) - if call.WantsMore() { - call.Continues = true - } - for { - line, err := reader.ReadString('\n') - // We've read the entire file - if err == io.EOF { - if !call.WantsMore() { - // If this is a non-following log request, we return what we have - break - } else { - // If we want to follow, return what we have, wipe the slice, and make - // sure the container is still running before iterating. - call.ReplyGetContainerLogs(logs) - logs = []string{} - time.Sleep(1 * time.Second) - state, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if state != define.ContainerStateRunning && state != define.ContainerStatePaused { - return call.ReplyErrorOccurred(fmt.Sprintf("%s is no longer running", ctr.ID())) - } - - } - } else if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } else { - logs = append(logs, line) - } - } - - call.Continues = false - - return call.ReplyGetContainerLogs(logs) -} - -// ListContainerChanges ... -func (i *VarlinkAPI) ListContainerChanges(call iopodman.VarlinkCall, name string) error { - changes, err := i.Runtime.GetDiff("", name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - result := iopodman.ContainerChanges{} - for _, change := range changes { - switch change.Kind { - case archive.ChangeModify: - result.Changed = append(result.Changed, change.Path) - case archive.ChangeDelete: - result.Deleted = append(result.Deleted, change.Path) - case archive.ChangeAdd: - result.Added = append(result.Added, change.Path) - } - } - return call.ReplyListContainerChanges(result) -} - -// ExportContainer ... -func (i *VarlinkAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - outputFile, err := ioutil.TempFile("", "varlink_recv") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - defer outputFile.Close() - if outPath == "" { - outPath = outputFile.Name() - } - if err := ctr.Export(outPath); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyExportContainer(outPath) - -} - -// GetContainerStats ... -func (i *VarlinkAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error { - if rootless.IsRootless() { - cgroupv2, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if !cgroupv2 { - return call.ReplyErrRequiresCgroupsV2ForRootless("rootless containers cannot report container stats") - } - } - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - containerStats, err := ctr.GetContainerStats(&define.ContainerStats{}) - if err != nil { - if errors.Cause(err) == define.ErrCtrStateInvalid { - return call.ReplyNoContainerRunning() - } - return call.ReplyErrorOccurred(err.Error()) - } - cs := iopodman.ContainerStats{ - Id: ctr.ID(), - Name: ctr.Name(), - Cpu: containerStats.CPU, - Cpu_nano: int64(containerStats.CPUNano), - System_nano: int64(containerStats.SystemNano), - Mem_usage: int64(containerStats.MemUsage), - Mem_limit: int64(containerStats.MemLimit), - Mem_perc: containerStats.MemPerc, - Net_input: int64(containerStats.NetInput), - Net_output: int64(containerStats.NetOutput), - Block_input: int64(containerStats.BlockInput), - Block_output: int64(containerStats.BlockOutput), - Pids: int64(containerStats.PIDs), - } - return call.ReplyGetContainerStats(cs) -} - -// StartContainer ... -func (i *VarlinkAPI) StartContainer(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - state, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if state == define.ContainerStateRunning || state == define.ContainerStatePaused { - return call.ReplyErrorOccurred("container is already running or paused") - } - recursive := false - if ctr.PodID() != "" { - recursive = true - } - if err := ctr.Start(getContext(), recursive); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyStartContainer(ctr.ID()) -} - -// InitContainer initializes the container given by Varlink. -func (i *VarlinkAPI) InitContainer(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.Init(getContext(), false); err != nil { - if errors.Cause(err) == define.ErrCtrStateInvalid { - return call.ReplyInvalidState(ctr.ID(), err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyInitContainer(ctr.ID()) -} - -// StopContainer ... -func (i *VarlinkAPI) StopContainer(call iopodman.VarlinkCall, name string, timeout int64) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.StopWithTimeout(uint(timeout)); err != nil { - if errors.Cause(err) == define.ErrCtrStopped { - return call.ReplyErrCtrStopped(ctr.ID()) - } - if errors.Cause(err) == define.ErrCtrStateInvalid { - return call.ReplyInvalidState(ctr.ID(), err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyStopContainer(ctr.ID()) -} - -// RestartContainer ... -func (i *VarlinkAPI) RestartContainer(call iopodman.VarlinkCall, name string, timeout int64) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.RestartWithTimeout(getContext(), uint(timeout)); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyRestartContainer(ctr.ID()) -} - -// ContainerExists looks in local storage for the existence of a container -func (i *VarlinkAPI) ContainerExists(call iopodman.VarlinkCall, name string) error { - _, err := i.Runtime.LookupContainer(name) - if errors.Cause(err) == define.ErrNoSuchCtr { - return call.ReplyContainerExists(1) - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyContainerExists(0) -} - -// KillContainer kills a running container. If you want to use the default SIGTERM signal, just send a -1 -// for the signal arg. -func (i *VarlinkAPI) KillContainer(call iopodman.VarlinkCall, name string, signal int64) error { - killSignal := uint(syscall.SIGTERM) - if signal != -1 { - killSignal = uint(signal) - } - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.Kill(killSignal); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyKillContainer(ctr.ID()) -} - -// PauseContainer ... -func (i *VarlinkAPI) PauseContainer(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.Pause(); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyPauseContainer(ctr.ID()) -} - -// UnpauseContainer ... -func (i *VarlinkAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := ctr.Unpause(); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyUnpauseContainer(ctr.ID()) -} - -// WaitContainer ... -func (i *VarlinkAPI) WaitContainer(call iopodman.VarlinkCall, name string, interval int64) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - exitCode, err := ctr.WaitWithInterval(time.Duration(interval)) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyWaitContainer(int64(exitCode)) -} - -// RemoveContainer ... -func (i *VarlinkAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool, removeVolumes bool) error { - ctx := getContext() - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - return call.ReplyContainerExists(1) - } - if errors.Cause(err) == define.ErrCtrStateInvalid { - return call.ReplyInvalidState(ctr.ID(), err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyRemoveContainer(ctr.ID()) -} - -// EvictContainer ... -func (i *VarlinkAPI) EvictContainer(call iopodman.VarlinkCall, name string, removeVolumes bool) error { - ctx := getContext() - id, err := i.Runtime.EvictContainer(ctx, name, removeVolumes) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyEvictContainer(id) -} - -// DeleteStoppedContainers ... -func (i *VarlinkAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error { - ctx := getContext() - var deletedContainers []string - containers, err := i.Runtime.GetAllContainers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - for _, ctr := range containers { - state, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if state != define.ContainerStateRunning { - if err := i.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - deletedContainers = append(deletedContainers, ctr.ID()) - } - } - return call.ReplyDeleteStoppedContainers(deletedContainers) -} - -// GetAttachSockets ... -func (i *VarlinkAPI) GetAttachSockets(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - - status, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - // If the container hasn't been run, we need to run init - // so the conmon sockets get created. - if status == define.ContainerStateConfigured || status == define.ContainerStateStopped { - if err := ctr.Init(getContext(), false); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - } - - sockPath, err := ctr.AttachSocketPath() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - s := iopodman.Sockets{ - Container_id: ctr.ID(), - Io_socket: sockPath, - Control_socket: ctr.ControlSocketPath(), - } - return call.ReplyGetAttachSockets(s) -} - -// ContainerCheckpoint ... -func (i *VarlinkAPI) ContainerCheckpoint(call iopodman.VarlinkCall, name string, keep, leaveRunning, tcpEstablished bool) error { - ctx := getContext() - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - - options := libpod.ContainerCheckpointOptions{ - Keep: keep, - TCPEstablished: tcpEstablished, - KeepRunning: leaveRunning, - } - if err := ctr.Checkpoint(ctx, options); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyContainerCheckpoint(ctr.ID()) -} - -// ContainerRestore ... -func (i *VarlinkAPI) ContainerRestore(call iopodman.VarlinkCall, name string, keep, tcpEstablished bool) error { - ctx := getContext() - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - - options := libpod.ContainerCheckpointOptions{ - Keep: keep, - TCPEstablished: tcpEstablished, - } - if err := ctr.Restore(ctx, options); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyContainerRestore(ctr.ID()) -} - -// ContainerConfig returns just the container.config struct -func (i *VarlinkAPI) ContainerConfig(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - config := ctr.Config() - b, err := json.Marshal(config) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize container config") - } - return call.ReplyContainerConfig(string(b)) -} - -// ContainerArtifacts returns an untouched container's artifact in string format -func (i *VarlinkAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifactName string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - artifacts, err := ctr.GetArtifact(artifactName) - if err != nil { - return call.ReplyErrorOccurred("unable to get container artifacts") - } - b, err := json.Marshal(artifacts) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize container artifacts") - } - return call.ReplyContainerArtifacts(string(b)) -} - -// ContainerInspectData returns the inspect data of a container in string format -func (i *VarlinkAPI) ContainerInspectData(call iopodman.VarlinkCall, name string, size bool) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - data, err := ctr.Inspect(size) - if err != nil { - return call.ReplyErrorOccurred("unable to inspect container") - } - b, err := json.Marshal(data) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize container inspect data") - } - return call.ReplyContainerInspectData(string(b)) - -} - -// ContainerStateData returns a container's state data in string format -func (i *VarlinkAPI) ContainerStateData(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - data, err := ctr.ContainerState() - if err != nil { - return call.ReplyErrorOccurred("unable to obtain container state") - } - b, err := json.Marshal(data) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize container inspect data") - } - return call.ReplyContainerStateData(string(b)) -} - -// GetContainerStatsWithHistory is a varlink endpoint that returns container stats based on current and -// previous statistics -func (i *VarlinkAPI) GetContainerStatsWithHistory(call iopodman.VarlinkCall, prevStats iopodman.ContainerStats) error { - con, err := i.Runtime.LookupContainer(prevStats.Id) - if err != nil { - return call.ReplyContainerNotFound(prevStats.Id, err.Error()) - } - previousStats := ContainerStatsToLibpodContainerStats(prevStats) - stats, err := con.GetContainerStats(&previousStats) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - cStats := iopodman.ContainerStats{ - Id: stats.ContainerID, - Name: stats.Name, - Cpu: stats.CPU, - Cpu_nano: int64(stats.CPUNano), - System_nano: int64(stats.SystemNano), - Mem_usage: int64(stats.MemUsage), - Mem_limit: int64(stats.MemLimit), - Mem_perc: stats.MemPerc, - Net_input: int64(stats.NetInput), - Net_output: int64(stats.NetOutput), - Block_input: int64(stats.BlockInput), - Block_output: int64(stats.BlockOutput), - Pids: int64(stats.PIDs), - } - return call.ReplyGetContainerStatsWithHistory(cStats) -} - -// Spec ... -func (i *VarlinkAPI) Spec(call iopodman.VarlinkCall, name string) error { - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - spec := ctr.Spec() - b, err := json.Marshal(spec) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - return call.ReplySpec(string(b)) -} - -// GetContainersLogs is the varlink endpoint to obtain one or more container logs -func (i *VarlinkAPI) GetContainersLogs(call iopodman.VarlinkCall, names []string, follow, latest bool, since string, tail int64, timestamps bool) error { - var wg sync.WaitGroup - if call.WantsMore() { - call.Continues = true - } - sinceTime, err := time.Parse(time.RFC3339Nano, since) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - options := logs.LogOptions{ - Follow: follow, - Since: sinceTime, - Tail: tail, - Timestamps: timestamps, - } - - options.WaitGroup = &wg - if len(names) > 1 { - options.Multi = true - } - tailLen := int(tail) - if tailLen < 0 { - tailLen = 0 - } - logChannel := make(chan *logs.LogLine, tailLen*len(names)+1) - containers, err := getContainersByContext(false, latest, names, i.Runtime) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := i.Runtime.Log(getContext(), containers, &options, logChannel); err != nil { - return err - } - go func() { - wg.Wait() - close(logChannel) - }() - for line := range logChannel { - call.ReplyGetContainersLogs(newPodmanLogLine(line)) - if !call.Continues { - break - } - - } - return call.ReplyGetContainersLogs(iopodman.LogLine{}) -} - -func newPodmanLogLine(line *logs.LogLine) iopodman.LogLine { - return iopodman.LogLine{ - Device: line.Device, - ParseLogType: line.ParseLogType, - Time: line.Time.Format(time.RFC3339Nano), - Msg: line.Msg, - Cid: line.CID, - } -} - -// Top displays information about a container's running processes -func (i *VarlinkAPI) Top(call iopodman.VarlinkCall, nameOrID string, descriptors []string) error { - ctr, err := i.Runtime.LookupContainer(nameOrID) - if err != nil { - return call.ReplyContainerNotFound(ctr.ID(), err.Error()) - } - topInfo, err := ctr.Top(descriptors) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyTop(topInfo) -} - -// ExecContainer is the varlink endpoint to execute a command in a container -func (i *VarlinkAPI) ExecContainer(call iopodman.VarlinkCall, opts iopodman.ExecOpts) error { - if !call.WantsUpgrade() { - return call.ReplyErrorOccurred("client must use upgraded connection to exec") - } - - ctr, err := i.Runtime.LookupContainer(opts.Name) - if err != nil { - return call.ReplyContainerNotFound(opts.Name, err.Error()) - } - - state, err := ctr.State() - if err != nil { - return call.ReplyErrorOccurred( - fmt.Sprintf("exec failed to obtain container %s state: %s", ctr.ID(), err.Error())) - } - - if state != define.ContainerStateRunning { - return call.ReplyErrorOccurred( - fmt.Sprintf("exec requires a running container, %s is %s", ctr.ID(), state.String())) - } - - // ACK the client upgrade request - call.ReplyExecContainer() - - envs := make(map[string]string) - if opts.Env != nil { - // HACK: The Varlink API uses the old []string format for env, - // storage as "k=v". Split on the = and turn into the new map - // format. - for _, env := range *opts.Env { - splitEnv := strings.SplitN(env, "=", 2) - if len(splitEnv) == 1 { - logrus.Errorf("Got badly-formatted environment variable %q in exec", env) - continue - } - envs[splitEnv[0]] = splitEnv[1] - } - } - - var user string - if opts.User != nil { - user = *opts.User - } - - var workDir string - if opts.Workdir != nil { - workDir = *opts.Workdir - } - - resizeChan := make(chan remotecommand.TerminalSize) - - reader, writer, _, pipeWriter, streams := setupStreams(call) - - type ExitCodeError struct { - ExitCode uint32 - Error error - } - ecErrChan := make(chan ExitCodeError, 1) - - go func() { - if err := virtwriter.Reader(reader, nil, nil, pipeWriter, resizeChan, nil); err != nil { - ecErrChan <- ExitCodeError{ - define.ExecErrorCodeGeneric, - err, - } - } - }() - - execConfig := new(libpod.ExecConfig) - execConfig.Command = opts.Cmd - execConfig.Terminal = opts.Tty - execConfig.Privileged = opts.Privileged - execConfig.Environment = envs - execConfig.User = user - execConfig.WorkDir = workDir - execConfig.DetachKeys = opts.DetachKeys - - go func() { - ec, err := ctr.Exec(execConfig, streams, resizeChan) - if err != nil { - logrus.Errorf(err.Error()) - } - ecErrChan <- ExitCodeError{ - uint32(ec), - err, - } - }() - - ecErr := <-ecErrChan - - exitCode := define.TranslateExecErrorToExitCode(int(ecErr.ExitCode), ecErr.Error) - - if err = virtwriter.HangUp(writer, uint32(exitCode)); err != nil { - logrus.Errorf("ExecContainer failed to HANG-UP on %s: %s", ctr.ID(), err.Error()) - } - - if err := call.Writer.Flush(); err != nil { - logrus.Errorf("Exec Container err: %s", err.Error()) - } - - return ecErr.Error -} - -// HealthCheckRun executes defined container's healthcheck command and returns the container's health status. -func (i *VarlinkAPI) HealthCheckRun(call iopodman.VarlinkCall, nameOrID string) error { - hcStatus, err := i.Runtime.HealthCheck(nameOrID) - if err != nil && hcStatus != define.HealthCheckFailure { - return call.ReplyErrorOccurred(err.Error()) - } - status := define.HealthCheckUnhealthy - if hcStatus == define.HealthCheckSuccess { - status = define.HealthCheckHealthy - } - return call.ReplyHealthCheckRun(status) -} diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go deleted file mode 100644 index 771e58089..000000000 --- a/pkg/varlinkapi/containers_create.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - iopodman "github.com/containers/podman/v2/pkg/varlink" -) - -// CreateContainer ... -func (i *VarlinkAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error { - generic := VarlinkCreateToGeneric(config) - ctr, _, err := CreateContainer(getContext(), &generic, i.Runtime) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyCreateContainer(ctr.ID()) -} diff --git a/pkg/varlinkapi/create.go b/pkg/varlinkapi/create.go deleted file mode 100644 index e9309a2d4..000000000 --- a/pkg/varlinkapi/create.go +++ /dev/null @@ -1,1155 +0,0 @@ -package varlinkapi - -import ( - "context" - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - goruntime "runtime" - "strconv" - "strings" - "syscall" - "time" - - "github.com/containers/common/pkg/sysinfo" - "github.com/containers/image/v5/manifest" - "github.com/containers/podman/v2/cmd/podman/parse" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/image" - ann "github.com/containers/podman/v2/pkg/annotations" - "github.com/containers/podman/v2/pkg/autoupdate" - "github.com/containers/podman/v2/pkg/cgroups" - envLib "github.com/containers/podman/v2/pkg/env" - "github.com/containers/podman/v2/pkg/errorhandling" - "github.com/containers/podman/v2/pkg/inspect" - ns "github.com/containers/podman/v2/pkg/namespaces" - "github.com/containers/podman/v2/pkg/rootless" - "github.com/containers/podman/v2/pkg/seccomp" - cc "github.com/containers/podman/v2/pkg/spec" - systemdGen "github.com/containers/podman/v2/pkg/systemd/generate" - "github.com/containers/podman/v2/pkg/util" - "github.com/docker/go-connections/nat" - "github.com/docker/go-units" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -var DefaultKernelNamespaces = "cgroup,ipc,net,uts" - -func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) { - var ( - healthCheck *manifest.Schema2HealthConfig - err error - cidFile *os.File - ) - if c.Bool("trace") { - span, _ := opentracing.StartSpanFromContext(ctx, "createContainer") - defer span.Finish() - } - if c.Bool("rm") && c.String("restart") != "" && c.String("restart") != "no" { - return nil, nil, errors.Errorf("the --rm option conflicts with --restart") - } - - rtc, err := runtime.GetConfig() - if err != nil { - return nil, nil, err - } - rootfs := "" - if c.Bool("rootfs") { - rootfs = c.InputArgs[0] - } - - if c.IsSet("cidfile") { - cidFile, err = util.OpenExclusiveFile(c.String("cidfile")) - if err != nil && os.IsExist(err) { - return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile")) - } - if err != nil { - return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile")) - } - defer errorhandling.CloseQuiet(cidFile) - defer errorhandling.SyncQuiet(cidFile) - } - - imageName := "" - rawImageName := "" - var imageData *inspect.ImageData = nil - - // Set the storage if there is no rootfs specified - if rootfs == "" { - var writer io.Writer - if !c.Bool("quiet") { - writer = os.Stderr - } - - if len(c.InputArgs) != 0 { - rawImageName = c.InputArgs[0] - } else { - return nil, nil, errors.Errorf("error, image name not provided") - } - - pullType, err := util.ValidatePullType(c.String("pull")) - if err != nil { - return nil, nil, err - } - - overrideOS := c.String("override-os") - overrideArch := c.String("override-arch") - dockerRegistryOptions := image.DockerRegistryOptions{ - OSChoice: overrideOS, - ArchitectureChoice: overrideArch, - } - - newImage, err := runtime.ImageRuntime().New(ctx, rawImageName, rtc.Engine.SignaturePolicyPath, c.String("authfile"), writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullType) - if err != nil { - return nil, nil, err - } - imageData, err = newImage.InspectNoSize(ctx) - if err != nil { - return nil, nil, err - } - - if overrideOS == "" && imageData.Os != goruntime.GOOS { - logrus.Infof("Using %q (OS) image on %q host", imageData.Os, goruntime.GOOS) - } - - if overrideArch == "" && imageData.Architecture != goruntime.GOARCH { - logrus.Infof("Using %q (architecture) on %q host", imageData.Architecture, goruntime.GOARCH) - } - - names := newImage.Names() - if len(names) > 0 { - imageName = names[0] - } else { - imageName = newImage.ID() - } - - // if the user disabled the healthcheck with "none" or the no-healthcheck - // options is provided, we skip adding it - healthCheckCommandInput := c.String("healthcheck-command") - - // the user didn't disable the healthcheck but did pass in a healthcheck command - // now we need to make a healthcheck from the commandline input - if healthCheckCommandInput != "none" && !c.Bool("no-healthcheck") { - if len(healthCheckCommandInput) > 0 { - healthCheck, err = makeHealthCheckFromCli(c) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to create healthcheck") - } - } else { - // the user did not disable the health check and did not pass in a healthcheck - // command as input. so now we add healthcheck if it exists AND is correct mediatype - _, mediaType, err := newImage.Manifest(ctx) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to determine mediatype of image %s", newImage.ID()) - } - if mediaType == manifest.DockerV2Schema2MediaType { - healthCheck, err = newImage.GetHealthCheck(ctx) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0]) - } - - if healthCheck != nil { - hcCommand := healthCheck.Test - if len(hcCommand) < 1 || hcCommand[0] == "" || hcCommand[0] == "NONE" { - // disable health check - healthCheck = nil - } else { - // apply defaults if image doesn't override them - if healthCheck.Interval == 0 { - healthCheck.Interval = 30 * time.Second - } - if healthCheck.Timeout == 0 { - healthCheck.Timeout = 30 * time.Second - } - /* Docker default is 0s, so the following would be a no-op - if healthCheck.StartPeriod == 0 { - healthCheck.StartPeriod = 0 * time.Second - } - */ - if healthCheck.Retries == 0 { - healthCheck.Retries = 3 - } - } - } - } - } - } - } - - createConfig, err := ParseCreateOpts(ctx, c, runtime, imageName, rawImageName, imageData) - if err != nil { - return nil, nil, err - } - - // (VR): Ideally we perform the checks _before_ pulling the image but that - // would require some bigger code refactoring of `ParseCreateOpts` and the - // logic here. But as the creation code will be consolidated in the future - // and given auto updates are experimental, we can live with that for now. - // In the end, the user may only need to correct the policy or the raw image - // name. - autoUpdatePolicy, autoUpdatePolicySpecified := createConfig.Labels[autoupdate.Label] - if autoUpdatePolicySpecified { - if _, err := autoupdate.LookupPolicy(autoUpdatePolicy); err != nil { - return nil, nil, err - } - // Now we need to make sure we're having a fully-qualified image reference. - if rootfs != "" { - return nil, nil, errors.Errorf("auto updates do not work with --rootfs") - } - // Make sure the input image is a docker. - if err := autoupdate.ValidateImageReference(rawImageName); err != nil { - return nil, nil, err - } - } - - // Because parseCreateOpts does derive anything from the image, we add health check - // at this point. The rest is done by WithOptions. - createConfig.HealthCheck = healthCheck - - // TODO: Should be able to return this from ParseCreateOpts - var pod *libpod.Pod - if createConfig.Pod != "" { - pod, err = runtime.LookupPod(createConfig.Pod) - if err != nil { - return nil, nil, errors.Wrapf(err, "error looking up pod to join") - } - } - - ctr, err := CreateContainerFromCreateConfig(ctx, runtime, createConfig, pod) - if err != nil { - return nil, nil, err - } - if cidFile != nil { - _, err = cidFile.WriteString(ctr.ID()) - if err != nil { - logrus.Error(err) - } - - } - - logrus.Debugf("New container created %q", ctr.ID()) - return ctr, createConfig, nil -} - -func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string { - entrypoint := []string{} - if c.IsSet("entrypoint") { - // Force entrypoint to "" - if c.String("entrypoint") == "" { - return entrypoint - } - // Check if entrypoint specified is json - if err := json.Unmarshal([]byte(c.String("entrypoint")), &entrypoint); err == nil { - return entrypoint - } - // Return entrypoint as a single command - return []string{c.String("entrypoint")} - } - if data != nil { - return data.Config.Entrypoint - } - return entrypoint -} - -func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[string]string, podName string) (map[string]string, string, error) { - pod, err := runtime.LookupPod(podName) - if err != nil { - return namespaces, "", err - } - podInfraID, err := pod.InfraContainerID() - if err != nil { - return namespaces, "", err - } - hasUserns := false - if podInfraID != "" { - podCtr, err := runtime.GetContainer(podInfraID) - if err != nil { - return namespaces, "", err - } - mappings, err := podCtr.IDMappings() - if err != nil { - return namespaces, "", err - } - hasUserns = len(mappings.UIDMap) > 0 - } - - if (namespaces["pid"] == cc.Pod) || (!c.IsSet("pid") && pod.SharesPID()) { - namespaces["pid"] = fmt.Sprintf("container:%s", podInfraID) - } - if (namespaces["net"] == cc.Pod) || (!c.IsSet("net") && !c.IsSet("network") && pod.SharesNet()) { - namespaces["net"] = fmt.Sprintf("container:%s", podInfraID) - } - if hasUserns && (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) { - namespaces["user"] = fmt.Sprintf("container:%s", podInfraID) - } - if (namespaces["ipc"] == cc.Pod) || (!c.IsSet("ipc") && pod.SharesIPC()) { - namespaces["ipc"] = fmt.Sprintf("container:%s", podInfraID) - } - if (namespaces["uts"] == cc.Pod) || (!c.IsSet("uts") && pod.SharesUTS()) { - namespaces["uts"] = fmt.Sprintf("container:%s", podInfraID) - } - return namespaces, podInfraID, 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 *GenericCLIResults, runtime *libpod.Runtime, imageName string, rawImageName string, data *inspect.ImageData) (*cc.CreateConfig, error) { - var ( - inputCommand, command []string - memoryLimit, memoryReservation, memorySwap, memoryKernel int64 - blkioWeight uint16 - namespaces map[string]string - ) - - idmappings, err := util.ParseIDMapping(ns.UsernsMode(c.String("userns")), c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidname"), c.String("subgidname")) - if err != nil { - return nil, err - } - - imageID := "" - - inputCommand = c.InputArgs[1:] - if data != nil { - imageID = data.ID - } - - rootfs := "" - if c.Bool("rootfs") { - rootfs = c.InputArgs[0] - } - - if c.String("memory") != "" { - memoryLimit, err = units.RAMInBytes(c.String("memory")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory") - } - } - if c.String("memory-reservation") != "" { - memoryReservation, err = units.RAMInBytes(c.String("memory-reservation")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory-reservation") - } - } - if c.String("memory-swap") != "" { - if c.String("memory-swap") == "-1" { - memorySwap = -1 - } else { - memorySwap, err = units.RAMInBytes(c.String("memory-swap")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory-swap") - } - } - } - if c.String("kernel-memory") != "" { - memoryKernel, err = units.RAMInBytes(c.String("kernel-memory")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for kernel-memory") - } - } - if c.String("blkio-weight") != "" { - u, err := strconv.ParseUint(c.String("blkio-weight"), 10, 16) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for blkio-weight") - } - blkioWeight = uint16(u) - } - - tty := c.Bool("tty") - - if c.Changed("cpu-period") && c.Changed("cpus") { - return nil, errors.Errorf("--cpu-period and --cpus cannot be set together") - } - if c.Changed("cpu-quota") && c.Changed("cpus") { - return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together") - } - - if c.Bool("no-hosts") && c.Changed("add-host") { - return nil, errors.Errorf("--no-hosts and --add-host cannot be set together") - } - - // EXPOSED PORTS - var portBindings map[nat.Port][]nat.PortBinding - if data != nil { - portBindings, err = cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.Config.ExposedPorts) - if err != nil { - return nil, err - } - } - - // Kernel Namespaces - // TODO Fix handling of namespace from pod - // Instead of integrating here, should be done in libpod - // However, that also involves setting up security opts - // when the pod's namespace is integrated - namespaces = map[string]string{ - "cgroup": c.String("cgroupns"), - "pid": c.String("pid"), - "net": c.String("network"), - "ipc": c.String("ipc"), - "user": c.String("userns"), - "uts": c.String("uts"), - } - - originalPodName := c.String("pod") - podName := strings.Replace(originalPodName, "new:", "", 1) - // after we strip out :new, make sure there is something left for a pod name - if len(podName) < 1 && c.IsSet("pod") { - return nil, errors.Errorf("new pod name must be at least one character") - } - - // If we are adding a container to a pod, we would like to add an annotation for the infra ID - // so kata containers can share VMs inside the pod - var podInfraID string - if c.IsSet("pod") { - if strings.HasPrefix(originalPodName, "new:") { - // pod does not exist; lets make it - var podOptions []libpod.PodCreateOption - podOptions = append(podOptions, libpod.WithPodName(podName), libpod.WithInfraContainer(), libpod.WithPodCgroups()) - if len(portBindings) > 0 { - ociPortBindings, err := cc.NatToOCIPortBindings(portBindings) - if err != nil { - return nil, err - } - podOptions = append(podOptions, libpod.WithInfraContainerPorts(ociPortBindings)) - } - - podNsOptions, err := GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ",")) - if err != nil { - return nil, err - } - podOptions = append(podOptions, podNsOptions...) - // make pod - pod, err := runtime.NewPod(ctx, podOptions...) - if err != nil { - return nil, err - } - logrus.Debugf("pod %s created by new container request", pod.ID()) - - // The container now cannot have port bindings; so we reset the map - portBindings = make(map[nat.Port][]nat.PortBinding) - } - namespaces, podInfraID, err = configurePod(c, runtime, namespaces, podName) - if err != nil { - return nil, err - } - } - - pidMode := ns.PidMode(namespaces["pid"]) - if !cc.Valid(string(pidMode), pidMode) { - return nil, errors.Errorf("--pid %q is not valid", c.String("pid")) - } - - usernsMode := ns.UsernsMode(namespaces["user"]) - if !cc.Valid(string(usernsMode), usernsMode) { - return nil, errors.Errorf("--userns %q is not valid", namespaces["user"]) - } - - utsMode := ns.UTSMode(namespaces["uts"]) - if !cc.Valid(string(utsMode), utsMode) { - return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"]) - } - - cgroupMode := ns.CgroupMode(namespaces["cgroup"]) - if !cgroupMode.Valid() { - return nil, errors.Errorf("--cgroup %q is not valid", namespaces["cgroup"]) - } - - ipcMode := ns.IpcMode(namespaces["ipc"]) - if !cc.Valid(string(ipcMode), ipcMode) { - return nil, errors.Errorf("--ipc %q is not valid", ipcMode) - } - - // Make sure if network is set to container namespace, port binding is not also being asked for - netMode := ns.NetworkMode(namespaces["net"]) - if netMode.IsContainer() { - if len(portBindings) > 0 { - return nil, errors.Errorf("cannot set port bindings on an existing container network namespace") - } - } - - // USER - user := c.String("user") - if user == "" { - switch { - case usernsMode.IsKeepID(): - user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID()) - case data == nil: - user = "0" - default: - user = data.Config.User - } - } - - // STOP SIGNAL - stopSignal := syscall.SIGTERM - signalString := "" - if data != nil { - signalString = data.Config.StopSignal - } - if c.IsSet("stop-signal") { - signalString = c.String("stop-signal") - } - if signalString != "" { - stopSignal, err = util.ParseSignal(signalString) - if err != nil { - return nil, err - } - } - - // ENVIRONMENT VARIABLES - // - // Precedence order (higher index wins): - // 1) env-host, 2) image data, 3) env-file, 4) env - env := map[string]string{ - "container": "podman", - } - - // First transform the os env into a map. We need it for the labels later in - // any case. - osEnv, err := envLib.ParseSlice(os.Environ()) - if err != nil { - return nil, errors.Wrap(err, "error parsing host environment variables") - } - - // Start with env-host - - if c.Bool("env-host") { - env = envLib.Join(env, osEnv) - } - - // Image data overrides any previous variables - if data != nil { - configEnv, err := envLib.ParseSlice(data.Config.Env) - if err != nil { - return nil, errors.Wrap(err, "error passing image environment variables") - } - env = envLib.Join(env, configEnv) - } - - // env-file overrides any previous variables - if c.IsSet("env-file") { - for _, f := range c.StringSlice("env-file") { - fileEnv, err := envLib.ParseFile(f) - if err != nil { - return nil, err - } - // File env is overridden by env. - env = envLib.Join(env, fileEnv) - } - } - - if c.IsSet("env") { - // env overrides any previous variables - cmdlineEnv := c.StringSlice("env") - if len(cmdlineEnv) > 0 { - parsedEnv, err := envLib.ParseSlice(cmdlineEnv) - if err != nil { - return nil, err - } - env = envLib.Join(env, parsedEnv) - } - } - - // LABEL VARIABLES - labels, err := parse.GetAllLabels(c.StringSlice("label-file"), c.StringArray("label")) - if err != nil { - return nil, errors.Wrapf(err, "unable to process labels") - } - if data != nil { - for key, val := range data.Config.Labels { - if _, ok := labels[key]; !ok { - labels[key] = val - } - } - } - - if systemdUnit, exists := osEnv[systemdGen.EnvVariable]; exists { - labels[systemdGen.EnvVariable] = systemdUnit - } - - // ANNOTATIONS - annotations := make(map[string]string) - - // First, add our default annotations - annotations[ann.TTY] = "false" - if tty { - annotations[ann.TTY] = "true" - } - - // in the event this container is in a pod, and the pod has an infra container - // we will want to configure it as a type "container" instead defaulting to - // the behavior of a "sandbox" container - // In Kata containers: - // - "sandbox" is the annotation that denotes the container should use its own - // VM, which is the default behavior - // - "container" denotes the container should join the VM of the SandboxID - // (the infra container) - if podInfraID != "" { - annotations[ann.SandboxID] = podInfraID - annotations[ann.ContainerType] = ann.ContainerTypeContainer - } - - if data != nil { - // Next, add annotations from the image - for key, value := range data.Annotations { - annotations[key] = value - } - } - // Last, add user annotations - for _, annotation := range c.StringSlice("annotation") { - splitAnnotation := strings.SplitN(annotation, "=", 2) - if len(splitAnnotation) < 2 { - return nil, errors.Errorf("Annotations must be formatted KEY=VALUE") - } - annotations[splitAnnotation[0]] = splitAnnotation[1] - } - - // WORKING DIRECTORY - workDir := "/" - if c.IsSet("workdir") { - workDir = c.String("workdir") - } else if data != nil && data.Config.WorkingDir != "" { - workDir = data.Config.WorkingDir - } - - userCommand := []string{} - entrypoint := configureEntrypoint(c, data) - // 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...) - userCommand = append(userCommand, inputCommand...) - } else if data != nil && len(data.Config.Cmd) > 0 && !c.IsSet("entrypoint") { - // If not user command, add CMD - command = append(command, data.Config.Cmd...) - userCommand = append(userCommand, data.Config.Cmd...) - } - - if data != nil && len(command) == 0 { - return nil, errors.Errorf("No command specified on command line or as CMD or ENTRYPOINT in this image") - } - - // SHM Size - shmSize, err := units.FromHumanSize(c.String("shm-size")) - if err != nil { - return nil, errors.Wrapf(err, "unable to translate --shm-size") - } - - if c.IsSet("add-host") { - // Verify the additional hosts are in correct format - for _, host := range c.StringSlice("add-host") { - if _, err := parse.ValidateExtraHost(host); err != nil { - return nil, err - } - } - } - - var ( - dnsSearches []string - dnsServers []string - dnsOptions []string - ) - if c.Changed("dns-search") { - dnsSearches = c.StringSlice("dns-search") - // Check for explicit dns-search domain of '' - if len(dnsSearches) == 0 { - return nil, errors.Errorf("'' is not a valid domain") - } - // Validate domains are good - for _, dom := range dnsSearches { - if dom == "." { - if len(dnsSearches) > 1 { - return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'") - } - continue - } - if _, err := parse.ValidateDomain(dom); err != nil { - return nil, err - } - } - } - if c.IsSet("dns") { - dnsServers = append(dnsServers, c.StringSlice("dns")...) - } - if c.IsSet("dns-opt") { - dnsOptions = c.StringSlice("dns-opt") - } - - var ImageVolumes map[string]struct{} - if data != nil && c.String("image-volume") != "ignore" { - ImageVolumes = data.Config.Volumes - } - - var imageVolType = map[string]string{ - "bind": "", - "tmpfs": "", - "ignore": "", - } - if _, ok := imageVolType[c.String("image-volume")]; !ok { - return nil, errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.String("image-volume")) - } - - systemd := c.String("systemd") == "always" - if !systemd && command != nil { - x, err := strconv.ParseBool(c.String("systemd")) - if err != nil { - return nil, errors.Wrapf(err, "cannot parse bool %s", c.String("systemd")) - } - useSystemdCommands := map[string]bool{ - "/sbin/init": true, - "/usr/sbin/init": true, - "/usr/local/sbin/init": true, - } - if x && (useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd")) { - systemd = true - } - } - if systemd { - if signalString == "" { - stopSignal, err = util.ParseSignal("RTMIN+3") - if err != nil { - return nil, errors.Wrapf(err, "error parsing systemd signal") - } - } - } - // This is done because cobra cannot have two aliased flags. So we have to check - // both - memorySwappiness := c.Int64("memory-swappiness") - - logDriver := define.KubernetesLogging - if c.Changed("log-driver") { - logDriver = c.String("log-driver") - } - - pidsLimit := c.Int64("pids-limit") - if c.String("cgroups") == "disabled" && !c.Changed("pids-limit") { - pidsLimit = -1 - } - - pid := &cc.PidConfig{ - PidMode: pidMode, - } - ipc := &cc.IpcConfig{ - IpcMode: ipcMode, - } - - cgroup := &cc.CgroupConfig{ - Cgroups: c.String("cgroups"), - Cgroupns: c.String("cgroupns"), - CgroupParent: c.String("cgroup-parent"), - CgroupMode: cgroupMode, - } - - userns := &cc.UserConfig{ - GroupAdd: c.StringSlice("group-add"), - IDMappings: idmappings, - UsernsMode: usernsMode, - User: user, - } - - uts := &cc.UtsConfig{ - UtsMode: utsMode, - NoHosts: c.Bool("no-hosts"), - HostAdd: c.StringSlice("add-host"), - Hostname: c.String("hostname"), - } - net := &cc.NetworkConfig{ - DNSOpt: dnsOptions, - DNSSearch: dnsSearches, - DNSServers: dnsServers, - HTTPProxy: c.Bool("http-proxy"), - MacAddress: c.String("mac-address"), - Network: c.String("network"), - NetMode: netMode, - IPAddress: c.String("ip"), - Publish: c.StringSlice("publish"), - PublishAll: c.Bool("publish-all"), - PortBindings: portBindings, - } - - sysctl := map[string]string{} - if c.Changed("sysctl") { - sysctl, err = util.ValidateSysctls(c.StringSlice("sysctl")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for sysctl") - } - } - - secConfig := &cc.SecurityConfig{ - CapAdd: c.StringSlice("cap-add"), - CapDrop: c.StringSlice("cap-drop"), - Privileged: c.Bool("privileged"), - ReadOnlyRootfs: c.Bool("read-only"), - ReadOnlyTmpfs: c.Bool("read-only-tmpfs"), - Sysctl: sysctl, - } - - var securityOpt []string - if c.Changed("security-opt") { - securityOpt = c.StringArray("security-opt") - } - if err := secConfig.SetSecurityOpts(runtime, securityOpt); err != nil { - return nil, err - } - - // SECCOMP - if data != nil { - if value, exists := labels[seccomp.ContainerImageLabel]; exists { - secConfig.SeccompProfileFromImage = value - } - } - if policy, err := seccomp.LookupPolicy(c.String("seccomp-policy")); err != nil { - return nil, err - } else { - secConfig.SeccompPolicy = policy - } - rtc, err := runtime.GetConfig() - if err != nil { - return nil, err - } - volumes := rtc.Containers.Volumes - if c.Changed("volume") { - volumes = append(volumes, c.StringSlice("volume")...) - } - - devices := rtc.Containers.Devices - if c.Changed("device") { - devices = append(devices, c.StringSlice("device")...) - } - - config := &cc.CreateConfig{ - Annotations: annotations, - BuiltinImgVolumes: ImageVolumes, - ConmonPidFile: c.String("conmon-pidfile"), - ImageVolumeType: c.String("image-volume"), - CidFile: c.String("cidfile"), - Command: command, - UserCommand: userCommand, - Detach: c.Bool("detach"), - Devices: devices, - Entrypoint: entrypoint, - Env: env, - // ExposedPorts: ports, - Init: c.Bool("init"), - InitPath: c.String("init-path"), - Image: imageName, - RawImageName: rawImageName, - ImageID: imageID, - Interactive: c.Bool("interactive"), - // IP6Address: c.String("ipv6"), // Not implemented yet - needs CNI support for static v6 - Labels: labels, - // LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet - LogDriver: logDriver, - LogDriverOpt: c.StringSlice("log-opt"), - Name: c.String("name"), - // NetworkAlias: c.StringSlice("network-alias"), // Not implemented - does this make sense in Podman? - Pod: podName, - Quiet: c.Bool("quiet"), - Resources: cc.CreateResourceConfig{ - BlkioWeight: blkioWeight, - BlkioWeightDevice: c.StringSlice("blkio-weight-device"), - CPUShares: c.Uint64("cpu-shares"), - CPUPeriod: c.Uint64("cpu-period"), - CPUsetCPUs: c.String("cpuset-cpus"), - CPUsetMems: c.String("cpuset-mems"), - CPUQuota: c.Int64("cpu-quota"), - CPURtPeriod: c.Uint64("cpu-rt-period"), - CPURtRuntime: c.Int64("cpu-rt-runtime"), - CPUs: c.Float64("cpus"), - DeviceCgroupRules: c.StringSlice("device-cgroup-rule"), - DeviceReadBps: c.StringSlice("device-read-bps"), - DeviceReadIOps: c.StringSlice("device-read-iops"), - DeviceWriteBps: c.StringSlice("device-write-bps"), - DeviceWriteIOps: c.StringSlice("device-write-iops"), - DisableOomKiller: c.Bool("oom-kill-disable"), - ShmSize: shmSize, - Memory: memoryLimit, - MemoryReservation: memoryReservation, - MemorySwap: memorySwap, - MemorySwappiness: int(memorySwappiness), - KernelMemory: memoryKernel, - OomScoreAdj: c.Int("oom-score-adj"), - PidsLimit: pidsLimit, - Ulimit: c.StringSlice("ulimit"), - }, - RestartPolicy: c.String("restart"), - Rm: c.Bool("rm"), - Security: *secConfig, - StopSignal: stopSignal, - StopTimeout: c.Uint("stop-timeout"), - Systemd: systemd, - Tmpfs: c.StringArray("tmpfs"), - Tty: tty, - MountsFlag: c.StringArray("mount"), - Volumes: volumes, - WorkDir: workDir, - Rootfs: rootfs, - VolumesFrom: c.StringSlice("volumes-from"), - Syslog: c.Bool("syslog"), - - Pid: *pid, - Ipc: *ipc, - Cgroup: *cgroup, - User: *userns, - Uts: *uts, - Network: *net, - } - - warnings, err := verifyContainerResources(config, false) - if err != nil { - return nil, err - } - for _, warning := range warnings { - fmt.Fprintln(os.Stderr, warning) - } - return config, nil -} - -func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *cc.CreateConfig, pod *libpod.Pod) (*libpod.Container, error) { - runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod) - if err != nil { - return nil, err - } - - ctr, err := r.NewContainer(ctx, runtimeSpec, options...) - if err != nil { - return nil, err - } - return ctr, nil -} - -func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig, error) { - inCommand := c.String("healthcheck-command") - inInterval := c.String("healthcheck-interval") - inRetries := c.Uint("healthcheck-retries") - inTimeout := c.String("healthcheck-timeout") - inStartPeriod := c.String("healthcheck-start-period") - - // Every healthcheck requires a command - if len(inCommand) == 0 { - return nil, errors.New("Must define a healthcheck command for all healthchecks") - } - - // first try to parse option value as JSON array of strings... - cmd := []string{} - err := json.Unmarshal([]byte(inCommand), &cmd) - if err != nil { - // ...otherwise pass it to "/bin/sh -c" inside the container - cmd = []string{"CMD-SHELL", inCommand} - } - hc := manifest.Schema2HealthConfig{ - Test: cmd, - } - - if inInterval == "disable" { - inInterval = "0" - } - intervalDuration, err := time.ParseDuration(inInterval) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-interval %s ", inInterval) - } - - hc.Interval = intervalDuration - - if inRetries < 1 { - return nil, errors.New("healthcheck-retries must be greater than 0.") - } - hc.Retries = int(inRetries) - timeoutDuration, err := time.ParseDuration(inTimeout) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout) - } - if timeoutDuration < time.Duration(1) { - return nil, errors.New("healthcheck-timeout must be at least 1 second") - } - hc.Timeout = timeoutDuration - - startPeriodDuration, err := time.ParseDuration(inStartPeriod) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", inStartPeriod) - } - if startPeriodDuration < time.Duration(0) { - return nil, errors.New("healthcheck-start-period must be 0 seconds or greater") - } - hc.StartPeriod = startPeriodDuration - - return &hc, nil -} - -// GetNamespaceOptions transforms a slice of kernel namespaces -// into a slice of pod create options. Currently, not all -// kernel namespaces are supported, and they will be returned in an error -func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) { - var options []libpod.PodCreateOption - var erroredOptions []libpod.PodCreateOption - for _, toShare := range ns { - switch toShare { - case "cgroup": - options = append(options, libpod.WithPodCgroups()) - case "net": - options = append(options, libpod.WithPodNet()) - case "mnt": - return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level") - case "pid": - options = append(options, libpod.WithPodPID()) - case "user": - return erroredOptions, errors.Errorf("User sharing functionality not supported on pod level") - case "ipc": - options = append(options, libpod.WithPodIPC()) - case "uts": - options = append(options, libpod.WithPodUTS()) - case "": - case "none": - return erroredOptions, nil - default: - return erroredOptions, errors.Errorf("Invalid kernel namespace to share: %s. Options are: net, pid, ipc, uts or none", toShare) - } - } - return options, nil -} - -func addWarning(warnings []string, msg string) []string { - logrus.Warn(msg) - return append(warnings, msg) -} - -func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) { - warnings := []string{} - - cgroup2, err := cgroups.IsCgroup2UnifiedMode() - if err != nil || cgroup2 { - return warnings, err - } - - sysInfo := sysinfo.New(true) - - // memory subsystem checks and adjustments - if config.Resources.Memory > 0 && !sysInfo.MemoryLimit { - warnings = addWarning(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.") - config.Resources.Memory = 0 - config.Resources.MemorySwap = -1 - } - if config.Resources.Memory > 0 && config.Resources.MemorySwap != -1 && !sysInfo.SwapLimit { - warnings = addWarning(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.") - config.Resources.MemorySwap = -1 - } - if config.Resources.Memory > 0 && config.Resources.MemorySwap > 0 && config.Resources.MemorySwap < config.Resources.Memory { - return warnings, fmt.Errorf("minimum memoryswap limit should be larger than memory limit, see usage") - } - if config.Resources.Memory == 0 && config.Resources.MemorySwap > 0 && !update { - return warnings, fmt.Errorf("you should always set the memory limit when using memoryswap limit, see usage") - } - if config.Resources.MemorySwappiness != -1 { - if !sysInfo.MemorySwappiness { - msg := "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded." - warnings = addWarning(warnings, msg) - config.Resources.MemorySwappiness = -1 - } else { - swappiness := config.Resources.MemorySwappiness - if swappiness < -1 || swappiness > 100 { - return warnings, fmt.Errorf("invalid value: %v, valid memory swappiness range is 0-100", swappiness) - } - } - } - if config.Resources.MemoryReservation > 0 && !sysInfo.MemoryReservation { - warnings = addWarning(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.") - config.Resources.MemoryReservation = 0 - } - if config.Resources.Memory > 0 && config.Resources.MemoryReservation > 0 && config.Resources.Memory < config.Resources.MemoryReservation { - return warnings, fmt.Errorf("minimum memory limit cannot be less than memory reservation limit, see usage") - } - if config.Resources.KernelMemory > 0 && !sysInfo.KernelMemory { - warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.") - config.Resources.KernelMemory = 0 - } - if config.Resources.DisableOomKiller && !sysInfo.OomKillDisable { - // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point - // warning the caller if they already wanted the feature to be off - warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.") - config.Resources.DisableOomKiller = false - } - - if config.Resources.PidsLimit != 0 && !sysInfo.PidsLimit { - warnings = addWarning(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") - config.Resources.PidsLimit = 0 - } - - if config.Resources.CPUShares > 0 && !sysInfo.CPUShares { - warnings = addWarning(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.") - config.Resources.CPUShares = 0 - } - if config.Resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod { - warnings = addWarning(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.") - config.Resources.CPUPeriod = 0 - } - if config.Resources.CPUPeriod != 0 && (config.Resources.CPUPeriod < 1000 || config.Resources.CPUPeriod > 1000000) { - return warnings, fmt.Errorf("CPU cfs period cannot be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)") - } - if config.Resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota { - warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.") - config.Resources.CPUQuota = 0 - } - if config.Resources.CPUQuota > 0 && config.Resources.CPUQuota < 1000 { - return warnings, fmt.Errorf("CPU cfs quota cannot be less than 1ms (i.e. 1000)") - } - // cpuset subsystem checks and adjustments - if (config.Resources.CPUsetCPUs != "" || config.Resources.CPUsetMems != "") && !sysInfo.Cpuset { - warnings = addWarning(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. CPUset discarded.") - config.Resources.CPUsetCPUs = "" - config.Resources.CPUsetMems = "" - } - cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(config.Resources.CPUsetCPUs) - if err != nil { - return warnings, fmt.Errorf("invalid value %s for cpuset cpus", config.Resources.CPUsetCPUs) - } - if !cpusAvailable { - return warnings, fmt.Errorf("requested CPUs are not available - requested %s, available: %s", config.Resources.CPUsetCPUs, sysInfo.Cpus) - } - memsAvailable, err := sysInfo.IsCpusetMemsAvailable(config.Resources.CPUsetMems) - if err != nil { - return warnings, fmt.Errorf("invalid value %s for cpuset mems", config.Resources.CPUsetMems) - } - if !memsAvailable { - return warnings, fmt.Errorf("requested memory nodes are not available - requested %s, available: %s", config.Resources.CPUsetMems, sysInfo.Mems) - } - - // blkio subsystem checks and adjustments - if config.Resources.BlkioWeight > 0 && !sysInfo.BlkioWeight { - warnings = addWarning(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.") - config.Resources.BlkioWeight = 0 - } - if config.Resources.BlkioWeight > 0 && (config.Resources.BlkioWeight < 10 || config.Resources.BlkioWeight > 1000) { - return warnings, fmt.Errorf("range of blkio weight is from 10 to 1000") - } - if len(config.Resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice { - warnings = addWarning(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.") - config.Resources.BlkioWeightDevice = []string{} - } - if len(config.Resources.DeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice { - warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded") - config.Resources.DeviceReadBps = []string{} - } - if len(config.Resources.DeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice { - warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.") - config.Resources.DeviceWriteBps = []string{} - } - if len(config.Resources.DeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice { - warnings = addWarning(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.") - config.Resources.DeviceReadIOps = []string{} - } - if len(config.Resources.DeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice { - warnings = addWarning(warnings, "Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.") - config.Resources.DeviceWriteIOps = []string{} - } - - return warnings, nil -} diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go deleted file mode 100644 index 8628b1ce6..000000000 --- a/pkg/varlinkapi/events.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "context" - "time" - - "github.com/containers/podman/v2/libpod/events" - iopodman "github.com/containers/podman/v2/pkg/varlink" -) - -// GetEvents is a remote endpoint to get events from the event log -func (i *VarlinkAPI) GetEvents(call iopodman.VarlinkCall, filter []string, since string, until string) error { - var ( - fromStart bool - eventsError error - event *events.Event - stream bool - ) - if call.WantsMore() { - stream = true - call.Continues = true - } - if len(since) > 0 || len(until) > 0 { - fromStart = true - } - eventChannel := make(chan *events.Event) - go func() { - readOpts := events.ReadOptions{FromStart: fromStart, Stream: stream, Filters: filter, EventChannel: eventChannel} - eventsError = i.Runtime.Events(context.Background(), readOpts) - }() - if eventsError != nil { - return call.ReplyErrorOccurred(eventsError.Error()) - } - for { - event = <-eventChannel - if event == nil { - call.Continues = false - break - } - call.ReplyGetEvents(iopodman.Event{ - Id: event.ID, - Image: event.Image, - Name: event.Name, - Status: string(event.Status), - Time: event.Time.Format(time.RFC3339Nano), - Type: string(event.Type), - }) - if !call.Continues { - // For a one-shot on events, we break out here - break - } - } - return nil -} diff --git a/pkg/varlinkapi/funcs.go b/pkg/varlinkapi/funcs.go deleted file mode 100644 index 8fb8a7ea0..000000000 --- a/pkg/varlinkapi/funcs.go +++ /dev/null @@ -1,121 +0,0 @@ -package varlinkapi - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/containers/image/v5/types" - "github.com/containers/podman/v2/libpod/image" - "github.com/google/shlex" - "github.com/pkg/errors" -) - -func GetSystemContext(authfile string) (*types.SystemContext, error) { - if authfile != "" { - if _, err := os.Stat(authfile); err != nil { - return nil, errors.Wrapf(err, "error checking authfile path %s", authfile) - } - } - return image.GetSystemContext("", authfile, false), nil -} - -func substituteCommand(cmd string) (string, error) { - var ( - newCommand string - ) - - // Replace cmd with "/proc/self/exe" if "podman" or "docker" is being - // used. If "/usr/bin/docker" is provided, we also sub in podman. - // Otherwise, leave the command unchanged. - if cmd == "podman" || filepath.Base(cmd) == "docker" { - newCommand = "/proc/self/exe" - } else { - newCommand = cmd - } - - // If cmd is an absolute or relative path, check if the file exists. - // Throw an error if it doesn't exist. - if strings.Contains(newCommand, "/") || strings.HasPrefix(newCommand, ".") { - res, err := filepath.Abs(newCommand) - if err != nil { - return "", err - } - if _, err := os.Stat(res); !os.IsNotExist(err) { - return res, nil - } else if err != nil { - return "", err - } - } - - return newCommand, nil -} - -// GenerateCommand takes a label (string) and converts it to an executable command -func GenerateCommand(command, imageName, name, globalOpts string) ([]string, error) { - var ( - newCommand []string - ) - if name == "" { - name = imageName - } - - cmd, err := shlex.Split(command) - if err != nil { - return nil, err - } - - prog, err := substituteCommand(cmd[0]) - if err != nil { - return nil, err - } - newCommand = append(newCommand, prog) - - for _, arg := range cmd[1:] { - var newArg string - switch arg { - case "IMAGE": - newArg = imageName - case "$IMAGE": - newArg = imageName - case "IMAGE=IMAGE": - newArg = fmt.Sprintf("IMAGE=%s", imageName) - case "IMAGE=$IMAGE": - newArg = fmt.Sprintf("IMAGE=%s", imageName) - case "NAME": - newArg = name - case "NAME=NAME": - newArg = fmt.Sprintf("NAME=%s", name) - case "NAME=$NAME": - newArg = fmt.Sprintf("NAME=%s", name) - case "$NAME": - newArg = name - case "$GLOBAL_OPTS": - newArg = globalOpts - default: - newArg = arg - } - newCommand = append(newCommand, newArg) - } - return newCommand, nil -} - -// GenerateRunEnvironment merges the current environment variables with optional -// environment variables provided by the user -func GenerateRunEnvironment(name, imageName string, opts map[string]string) []string { - newEnv := os.Environ() - newEnv = append(newEnv, fmt.Sprintf("NAME=%s", name)) - newEnv = append(newEnv, fmt.Sprintf("IMAGE=%s", imageName)) - - if opts["opt1"] != "" { - newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", opts["opt1"])) - } - if opts["opt2"] != "" { - newEnv = append(newEnv, fmt.Sprintf("OPT2=%s", opts["opt2"])) - } - if opts["opt3"] != "" { - newEnv = append(newEnv, fmt.Sprintf("OPT3=%s", opts["opt3"])) - } - return newEnv -} diff --git a/pkg/varlinkapi/generate.go b/pkg/varlinkapi/generate.go deleted file mode 100644 index bbc16dae5..000000000 --- a/pkg/varlinkapi/generate.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "encoding/json" - - iopodman "github.com/containers/podman/v2/pkg/varlink" -) - -// GenerateKube ... -func (i *VarlinkAPI) GenerateKube(call iopodman.VarlinkCall, name string, service bool) error { - pod, serv, err := GenerateKube(name, service, i.Runtime) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - podB, err := json.Marshal(pod) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - servB, err := json.Marshal(serv) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - return call.ReplyGenerateKube(iopodman.KubePodService{ - Pod: string(podB), - Service: string(servB), - }) -} diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go deleted file mode 100644 index af6c43fec..000000000 --- a/pkg/varlinkapi/images.go +++ /dev/null @@ -1,1037 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - "github.com/containers/buildah" - "github.com/containers/buildah/imagebuildah" - dockerarchive "github.com/containers/image/v5/docker/archive" - "github.com/containers/image/v5/manifest" - "github.com/containers/image/v5/transports/alltransports" - "github.com/containers/image/v5/types" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/image" - "github.com/containers/podman/v2/pkg/channel" - "github.com/containers/podman/v2/pkg/util" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/podman/v2/utils" - "github.com/containers/storage/pkg/archive" - v1 "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// ListImagesWithFilters returns a list of images that have been filtered -func (i *VarlinkAPI) ListImagesWithFilters(call iopodman.VarlinkCall, filters []string) error { - images, err := i.Runtime.ImageRuntime().GetImagesWithFilters(filters) - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err)) - } - imageList, err := imagesToImageList(images) - if err != nil { - return call.ReplyErrorOccurred("unable to parse response " + err.Error()) - } - return call.ReplyListImagesWithFilters(imageList) -} - -// imagesToImageList converts a slice of Images to an imagelist for varlink responses -func imagesToImageList(images []*image.Image) ([]iopodman.Image, error) { - var imageList []iopodman.Image - for _, img := range images { - labels, _ := img.Labels(getContext()) - containers, _ := img.Containers() - repoDigests, err := img.RepoDigests() - if err != nil { - return nil, err - } - - size, _ := img.Size(getContext()) - isParent, err := img.IsParent(context.TODO()) - if err != nil { - return nil, err - } - - i := iopodman.Image{ - Id: img.ID(), - Digest: string(img.Digest()), - ParentId: img.Parent, - RepoTags: img.Names(), - RepoDigests: repoDigests, - Created: img.Created().Format(time.RFC3339), - Size: int64(*size), - VirtualSize: img.VirtualSize, - Containers: int64(len(containers)), - Labels: labels, - IsParent: isParent, - ReadOnly: img.IsReadOnly(), - History: img.NamesHistory(), - } - imageList = append(imageList, i) - } - return imageList, nil -} - -// ListImages lists all the images in the store -// It requires no inputs. -func (i *VarlinkAPI) ListImages(call iopodman.VarlinkCall) error { - images, err := i.Runtime.ImageRuntime().GetImages() - if err != nil { - return call.ReplyErrorOccurred("unable to get list of images " + err.Error()) - } - imageList, err := imagesToImageList(images) - if err != nil { - return call.ReplyErrorOccurred("unable to parse response " + err.Error()) - } - return call.ReplyListImages(imageList) -} - -// GetImage returns a single image in the form of a Image -func (i *VarlinkAPI) GetImage(call iopodman.VarlinkCall, id string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id) - if err != nil { - return call.ReplyImageNotFound(id, err.Error()) - } - labels, err := newImage.Labels(getContext()) - if err != nil { - return err - } - containers, err := newImage.Containers() - if err != nil { - return err - } - repoDigests, err := newImage.RepoDigests() - if err != nil { - return err - } - size, err := newImage.Size(getContext()) - if err != nil { - return err - } - - il := iopodman.Image{ - Id: newImage.ID(), - ParentId: newImage.Parent, - RepoTags: newImage.Names(), - RepoDigests: repoDigests, - Created: newImage.Created().Format(time.RFC3339), - Size: int64(*size), - VirtualSize: newImage.VirtualSize, - Containers: int64(len(containers)), - Labels: labels, - TopLayer: newImage.TopLayer(), - ReadOnly: newImage.IsReadOnly(), - History: newImage.NamesHistory(), - } - return call.ReplyGetImage(il) -} - -// BuildImage ... -func (i *VarlinkAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error { - var ( - namespace []buildah.NamespaceOption - imageID string - err error - ) - - contextDir := config.ContextDir - - newContextDir, err := ioutil.TempDir("", "buildTarball") - if err != nil { - call.ReplyErrorOccurred("unable to create tempdir") - } - logrus.Debugf("created new context dir at %s", newContextDir) - - reader, err := os.Open(contextDir) - if err != nil { - logrus.Errorf("failed to open the context dir tar file") - return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir)) - } - defer reader.Close() - if err := archive.Untar(reader, newContextDir, &archive.TarOptions{}); err != nil { - logrus.Errorf("fail to untar the context dir tarball (%s) to the context dir (%s)", contextDir, newContextDir) - return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir)) - } - logrus.Debugf("untar of %s successful", contextDir) - defer func() { - if err := os.Remove(contextDir); err != nil { - logrus.Error(err) - } - if err := os.RemoveAll(newContextDir); err != nil { - logrus.Errorf("unable to delete directory '%s': %q", newContextDir, err) - } - }() - - systemContext := types.SystemContext{} - // All output (stdout, stderr) is captured in output as well - var output bytes.Buffer - - commonOpts := &buildah.CommonBuildOptions{ - AddHost: config.BuildOptions.AddHosts, - CgroupParent: config.BuildOptions.CgroupParent, - CPUPeriod: uint64(config.BuildOptions.CpuPeriod), - CPUQuota: config.BuildOptions.CpuQuota, - CPUSetCPUs: config.BuildOptions.CpusetCpus, - CPUSetMems: config.BuildOptions.CpusetMems, - Memory: config.BuildOptions.Memory, - MemorySwap: config.BuildOptions.MemorySwap, - ShmSize: config.BuildOptions.ShmSize, - Ulimit: config.BuildOptions.Ulimit, - Volumes: config.BuildOptions.Volume, - } - - options := imagebuildah.BuildOptions{ - AddCapabilities: config.AddCapabilities, - AdditionalTags: config.AdditionalTags, - Annotations: config.Annotations, - Architecture: config.Architecture, - Args: config.BuildArgs, - CNIConfigDir: config.CniConfigDir, - CNIPluginPath: config.CniPluginDir, - CommonBuildOpts: commonOpts, - Compression: stringCompressionToArchiveType(config.Compression), - ContextDirectory: newContextDir, - DefaultMountsFilePath: config.DefaultsMountFilePath, - Devices: config.Devices, - Err: &output, - ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs, - IIDFile: config.Iidfile, - Labels: config.Label, - Layers: config.Layers, - NamespaceOptions: namespace, - NoCache: config.Nocache, - OS: config.Os, - Out: &output, - Output: config.Output, - OutputFormat: config.OutputFormat, - PullPolicy: stringPullPolicyToType(config.PullPolicy), - Quiet: config.Quiet, - RemoveIntermediateCtrs: config.RemoteIntermediateCtrs, - ReportWriter: &output, - RuntimeArgs: config.RuntimeArgs, - SignBy: config.SignBy, - Squash: config.Squash, - SystemContext: &systemContext, - Target: config.Target, - TransientMounts: config.TransientMounts, - } - - if call.WantsMore() { - call.Continues = true - } else { - return call.ReplyErrorOccurred("endpoint requires a more connection") - } - - var newPathDockerFiles []string - - for _, d := range config.Dockerfiles { - if strings.HasPrefix(d, "http://") || - strings.HasPrefix(d, "https://") || - strings.HasPrefix(d, "git://") || - strings.HasPrefix(d, "github.com/") { - newPathDockerFiles = append(newPathDockerFiles, d) - continue - } - base := filepath.Base(d) - newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base)) - } - - c := make(chan error) - go func() { - iid, _, err := i.Runtime.Build(getContext(), options, newPathDockerFiles...) - imageID = iid - c <- err - close(c) - }() - - var log []string - done := false - for { - outputLine, err := output.ReadString('\n') - if err == nil { - log = append(log, outputLine) - if call.WantsMore() { - // we want to reply with what we have - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyBuildImage(br) - log = []string{} - } - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if call.WantsMore() { - time.Sleep(1 * time.Second) - break - } - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: imageID, - } - return call.ReplyBuildImage(br) -} - -// InspectImage returns an image's inspect information as a string that can be serialized. -// Requires an image ID or name -func (i *VarlinkAPI) InspectImage(call iopodman.VarlinkCall, name string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - inspectInfo, err := newImage.Inspect(getContext()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(inspectInfo) - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize")) - } - return call.ReplyInspectImage(string(b)) -} - -// HistoryImage returns the history of the image's layers -// Requires an image or name -func (i *VarlinkAPI) HistoryImage(call iopodman.VarlinkCall, name string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - history, err := newImage.History(getContext()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - var histories []iopodman.ImageHistory - for _, hist := range history { - imageHistory := iopodman.ImageHistory{ - Id: hist.ID, - Created: hist.Created.Format(time.RFC3339), - CreatedBy: hist.CreatedBy, - Tags: newImage.Names(), - Size: hist.Size, - Comment: hist.Comment, - } - histories = append(histories, imageHistory) - } - return call.ReplyHistoryImage(histories) -} - -// PushImage pushes an local image to registry -func (i *VarlinkAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compress bool, format string, removeSignatures bool, signBy string) error { - var ( - manifestType string - ) - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - destname := name - if tag != "" { - destname = tag - } - dockerRegistryOptions := image.DockerRegistryOptions{} - if format != "" { - switch format { - case "oci": // nolint - manifestType = v1.MediaTypeImageManifest - case "v2s1": - manifestType = manifest.DockerV2Schema1SignedMediaType - case "v2s2", "docker": - manifestType = manifest.DockerV2Schema2MediaType - default: - return call.ReplyErrorOccurred(fmt.Sprintf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", format)) - } - } - so := image.SigningOptions{ - RemoveSignatures: removeSignatures, - SignBy: signBy, - } - - if call.WantsMore() { - call.Continues = true - } - - output := bytes.NewBuffer([]byte{}) - c := make(chan error) - go func() { - writer := bytes.NewBuffer([]byte{}) - err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", "", writer, compress, so, &dockerRegistryOptions, nil) - if err != nil { - c <- err - } - _, err = io.CopyBuffer(output, writer, nil) - c <- err - close(c) - }() - - // TODO When pull output gets fixed for the remote client, we need to look into how we can turn below - // into something re-usable. it is in build too - var log []string - done := false - for { - line, err := output.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Errorf("reading of output during push failed for %s", newImage.ID()) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - call.ReplyPushImage(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - return call.ReplyPushImage(br) -} - -// TagImage accepts an image name and tag as strings and tags an image in the local store. -func (i *VarlinkAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - if err := newImage.TagImage(tag); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyTagImage(newImage.ID()) -} - -// UntagImage accepts an image name and tag as strings and removes the tag from the local store. -func (i *VarlinkAPI) UntagImage(call iopodman.VarlinkCall, name, tag string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - if err := newImage.UntagImage(tag); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyUntagImage(newImage.ID()) -} - -// RemoveImage accepts a image name or ID as a string and force bool to determine if it should -// remove the image even if being used by stopped containers -func (i *VarlinkAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bool) error { - ctx := getContext() - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - _, err = i.Runtime.RemoveImage(ctx, newImage, force) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyRemoveImage(newImage.ID()) -} - -// RemoveImageWithResponse accepts an image name and force bool. It returns details about what -// was done in removeimageresponse struct. -func (i *VarlinkAPI) RemoveImageWithResponse(call iopodman.VarlinkCall, name string, force bool) error { - ir := iopodman.RemoveImageResponse{} - ctx := getContext() - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - response, err := i.Runtime.RemoveImage(ctx, newImage, force) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - ir.Untagged = append(ir.Untagged, response.Untagged...) - ir.Deleted = response.Deleted - return call.ReplyRemoveImageWithResponse(ir) -} - -// SearchImages searches all registries configured in /etc/containers/registries.conf for an image -// Requires an image name and a search limit as int -func (i *VarlinkAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, filter iopodman.ImageSearchFilter) error { - // Transform all arguments to proper types first - argLimit := 0 - argIsOfficial := types.OptionalBoolUndefined - argIsAutomated := types.OptionalBoolUndefined - if limit != nil { - argLimit = int(*limit) - } - if filter.Is_official != nil { - argIsOfficial = types.NewOptionalBool(*filter.Is_official) - } - if filter.Is_automated != nil { - argIsAutomated = types.NewOptionalBool(*filter.Is_automated) - } - - // Transform a SearchFilter the backend can deal with - sFilter := image.SearchFilter{ - IsOfficial: argIsOfficial, - IsAutomated: argIsAutomated, - Stars: int(filter.Star_count), - } - - searchOptions := image.SearchOptions{ - Limit: argLimit, - Filter: sFilter, - } - results, err := image.SearchImages(query, searchOptions) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - var imageResults []iopodman.ImageSearchResult - for _, result := range results { - i := iopodman.ImageSearchResult{ - Registry: result.Index, - Description: result.Description, - Is_official: result.Official == "[OK]", - Is_automated: result.Automated == "[OK]", - Name: result.Name, - Star_count: int64(result.Stars), - } - imageResults = append(imageResults, i) - } - return call.ReplySearchImages(imageResults) -} - -// DeleteUnusedImages deletes any images that do not have containers associated with it. -// TODO Filters are not implemented -func (i *VarlinkAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error { - images, err := i.Runtime.ImageRuntime().GetImages() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - var deletedImages []string - for _, img := range images { - containers, err := img.Containers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if len(containers) == 0 { - if err := img.Remove(context.TODO(), false); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - deletedImages = append(deletedImages, img.ID()) - } - } - return call.ReplyDeleteUnusedImages(deletedImages) -} - -// Commit ... -func (i *VarlinkAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error { - var ( - newImage *image.Image - log []string - mimeType string - ) - output := channel.NewWriter(make(chan []byte)) - channelClose := func() { - if err := output.Close(); err != nil { - logrus.Errorf("failed to close channel writer: %q", err) - } - } - defer channelClose() - - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - rtc, err := i.Runtime.GetConfig() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false) - switch manifestType { - case "oci", "": // nolint - mimeType = buildah.OCIv1ImageManifest - case "docker": - mimeType = manifest.DockerV2Schema2MediaType - default: - return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image format %q", manifestType)) - } - coptions := buildah.CommitOptions{ - SignaturePolicyPath: rtc.Engine.SignaturePolicyPath, - ReportWriter: output, - SystemContext: sc, - PreferredManifestType: mimeType, - } - options := libpod.ContainerCommitOptions{ - CommitOptions: coptions, - Pause: pause, - Message: message, - Changes: changes, - Author: author, - } - - if call.WantsMore() { - call.Continues = true - } - - c := make(chan error) - - go func() { - newImage, err = ctr.Commit(getContext(), imageName, options) - if err != nil { - c <- err - } - c <- nil - close(c) - }() - - // reply is the func being sent to the output forwarder. in this case it is replying - // with a more response struct - reply := func(br iopodman.MoreResponse) error { - return call.ReplyCommit(br) - } - log, err = forwardOutput(log, c, call.WantsMore(), output, reply) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - call.Continues = false - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - return call.ReplyCommit(br) -} - -// ImportImage imports an image from a tarball to the image store -func (i *VarlinkAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error { - configChanges, err := util.GetImageConfig(changes) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - history := []v1.History{ - {Comment: message}, - } - config := v1.Image{ - Config: configChanges.ImageConfig, - History: history, - } - newImage, err := i.Runtime.ImageRuntime().Import(getContext(), source, reference, nil, image.SigningOptions{}, config) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if delete { - if err := os.Remove(source); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - } - - return call.ReplyImportImage(newImage.ID()) -} - -// ExportImage exports an image to the provided destination -// destination must have the transport type!! -func (i *VarlinkAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - - additionalTags, err := image.GetAdditionalTags(tags) - if err != nil { - return err - } - - if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyExportImage(newImage.ID()) -} - -// PullImage pulls an image from a registry to the image store. -func (i *VarlinkAPI) PullImage(call iopodman.VarlinkCall, name string, creds iopodman.AuthConfig) error { - var ( - imageID string - err error - ) - dockerRegistryOptions := image.DockerRegistryOptions{ - DockerRegistryCreds: &types.DockerAuthConfig{ - Username: creds.Username, - Password: creds.Password, - }, - } - - so := image.SigningOptions{} - - if call.WantsMore() { - call.Continues = true - } - output := channel.NewWriter(make(chan []byte)) - channelClose := func() { - if err := output.Close(); err != nil { - logrus.Errorf("failed to close channel writer: %q", err) - } - } - defer channelClose() - c := make(chan error) - defer close(c) - - go func() { - var foundError bool - if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") { - srcRef, err := alltransports.ParseImageName(name) - if err != nil { - c <- errors.Wrapf(err, "error parsing %q", name) - } - newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, "", output) - if err != nil { - foundError = true - c <- errors.Wrapf(err, "error pulling image from %q", name) - } else { - imageID = newImage[0].ID() - } - } else { - newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", output, &dockerRegistryOptions, so, nil, util.PullImageMissing) - if err != nil { - foundError = true - c <- errors.Wrapf(err, "unable to pull %s", name) - } else { - imageID = newImage.ID() - } - } - if !foundError { - c <- nil - } - }() - - var log []string - reply := func(br iopodman.MoreResponse) error { - return call.ReplyPullImage(br) - } - log, err = forwardOutput(log, c, call.WantsMore(), output, reply) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - call.Continues = false - br := iopodman.MoreResponse{ - Logs: log, - Id: imageID, - } - return call.ReplyPullImage(br) -} - -// ImageExists returns bool as to whether the input image exists in local storage -func (i *VarlinkAPI) ImageExists(call iopodman.VarlinkCall, name string) error { - _, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if errors.Cause(err) == image.ErrNoSuchImage { - return call.ReplyImageExists(1) - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImageExists(0) -} - -// ContainerRunlabel ... -func (i *VarlinkAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.Runlabel) error { - ctx := getContext() - dockerRegistryOptions := image.DockerRegistryOptions{} - stdErr := os.Stderr - stdOut := os.Stdout - stdIn := os.Stdin - - runLabel, imageName, err := GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, "", dockerRegistryOptions, input.Authfile, "", nil) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if runLabel == "" { - return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label)) - } - - cmd, env, err := GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs, "") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyContainerRunlabel() -} - -// ImagesPrune .... -func (i *VarlinkAPI) ImagesPrune(call iopodman.VarlinkCall, all bool, filter []string) error { - prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all, []string{}) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImagesPrune(prunedImages) -} - -// ImageSave .... -func (i *VarlinkAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name) - if err != nil { - if errors.Cause(err) == define.ErrNoSuchImage { - return call.ReplyImageNotFound(options.Name, err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - - // Determine if we are dealing with a tarball or dir - var output string - outputToDir := false - if options.Format == "oci-archive" || options.Format == "docker-archive" { - tempfile, err := ioutil.TempFile("", "varlink_send") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - output = tempfile.Name() - tempfile.Close() - } else { - var err error - outputToDir = true - output, err = ioutil.TempDir("", "varlink_send") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if call.WantsMore() { - call.Continues = true - } - - saveOutput := bytes.NewBuffer([]byte{}) - c := make(chan error) - go func() { - err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress, true) - c <- err - close(c) - }() - var log []string - done := false - for { - line, err := saveOutput.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Errorf("reading of output during save failed for %s", newImage.ID()) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyImageSave(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - sendfile := output - // Image has been saved to `output` - if outputToDir { - // If the output is a directory, we need to tar up the directory to send it back - // Create a tempfile for the directory tarball - outputFile, err := ioutil.TempFile("", "varlink_save_dir") - if err != nil { - return err - } - defer outputFile.Close() - if err := utils.TarToFilesystem(output, outputFile); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - sendfile = outputFile.Name() - } - br := iopodman.MoreResponse{ - Logs: log, - Id: sendfile, - } - return call.ReplyPushImage(br) -} - -// LoadImage ... -func (i *VarlinkAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error { - var ( - names string - writer io.Writer - err error - ) - if !quiet { - writer = os.Stderr - } - - if call.WantsMore() { - call.Continues = true - } - output := bytes.NewBuffer([]byte{}) - - c := make(chan error) - go func() { - names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "") - c <- err - close(c) - }() - - var log []string - done := false - for { - line, err := output.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Error(err) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyLoadImage(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: names, - } - if deleteInputFile { - if err := os.Remove(inputFile); err != nil { - logrus.Errorf("unable to delete input file %s", inputFile) - } - } - return call.ReplyLoadImage(br) -} - -// Diff ... -func (i *VarlinkAPI) Diff(call iopodman.VarlinkCall, name string) error { - var response []iopodman.DiffInfo - changes, err := i.Runtime.GetDiff("", name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - for _, change := range changes { - response = append(response, iopodman.DiffInfo{Path: change.Path, ChangeType: change.Kind.String()}) - } - return call.ReplyDiff(response) -} - -// GetLayersMapWithImageInfo is a development only endpoint to obtain layer information for an image. -func (i *VarlinkAPI) GetLayersMapWithImageInfo(call iopodman.VarlinkCall) error { - layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(layerInfo) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyGetLayersMapWithImageInfo(string(b)) -} - -// BuildImageHierarchyMap ... -func (i *VarlinkAPI) BuildImageHierarchyMap(call iopodman.VarlinkCall, name string) error { - img, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - imageInfo := &image.InfoImage{ - ID: img.ID(), - Tags: img.Names(), - } - layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := image.BuildImageHierarchyMap(imageInfo, layerInfo, img.TopLayer()); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(imageInfo) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyBuildImageHierarchyMap(string(b)) -} - -// ImageTree returns the image tree string for the provided image name or ID -func (i *VarlinkAPI) ImageTree(call iopodman.VarlinkCall, nameOrID string, whatRequires bool) error { - img, err := i.Runtime.ImageRuntime().NewFromLocal(nameOrID) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - tree, err := img.GenerateTree(whatRequires) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImageTree(tree) -} diff --git a/pkg/varlinkapi/intermediate.go b/pkg/varlinkapi/intermediate.go deleted file mode 100644 index f04665a86..000000000 --- a/pkg/varlinkapi/intermediate.go +++ /dev/null @@ -1,289 +0,0 @@ -package varlinkapi - -import ( - "github.com/sirupsen/logrus" -) - -/* -attention - -in this file you will see a lot of struct duplication. this was done because people wanted a strongly typed -varlink mechanism. this resulted in us creating this intermediate layer that allows us to take the input -from the cli and make an intermediate layer which can be transferred as strongly typed structures over a varlink -interface. - -we intentionally avoided heavy use of reflection here because we were concerned about performance impacts to the -non-varlink intermediate layer generation. -*/ - -// GenericCLIResult describes the overall interface for dealing with -// the create command cli in both local and remote uses -type GenericCLIResult interface { - IsSet() bool - Name() string - Value() interface{} -} - -// CRStringSlice describes a string slice cli struct -type CRStringSlice struct { - Val []string - createResult -} - -// CRString describes a string cli struct -type CRString struct { - Val string - createResult -} - -// CRUint64 describes a uint64 cli struct -type CRUint64 struct { - Val uint64 - createResult -} - -// CRFloat64 describes a float64 cli struct -type CRFloat64 struct { - Val float64 - createResult -} - -//CRBool describes a bool cli struct -type CRBool struct { - Val bool - createResult -} - -// CRInt64 describes an int64 cli struct -type CRInt64 struct { - Val int64 - createResult -} - -// CRUint describes a uint cli struct -type CRUint struct { - Val uint - createResult -} - -// CRInt describes an int cli struct -type CRInt struct { - Val int - createResult -} - -// CRStringArray describes a stringarray cli struct -type CRStringArray struct { - Val []string - createResult -} - -type createResult struct { - Flag string - Changed bool -} - -// GenericCLIResults in the intermediate object between the cobra cli -// and createconfig -type GenericCLIResults struct { - results map[string]GenericCLIResult - InputArgs []string -} - -// IsSet returns a bool if the flag was changed -func (f GenericCLIResults) IsSet(flag string) bool { - r := f.findResult(flag) - if r == nil { - return false - } - return r.IsSet() -} - -// Value returns the value of the cli flag -func (f GenericCLIResults) Value(flag string) interface{} { - r := f.findResult(flag) - if r == nil { - return "" - } - return r.Value() -} - -func (f GenericCLIResults) findResult(flag string) GenericCLIResult { - val, ok := f.results[flag] - if ok { - return val - } - logrus.Debugf("unable to find flag %s", flag) - return nil -} - -// Bool is a wrapper to get a bool value from GenericCLIResults -func (f GenericCLIResults) Bool(flag string) bool { - r := f.findResult(flag) - if r == nil { - return false - } - return r.Value().(bool) -} - -// String is a wrapper to get a string value from GenericCLIResults -func (f GenericCLIResults) String(flag string) string { - r := f.findResult(flag) - if r == nil { - return "" - } - return r.Value().(string) -} - -// Uint is a wrapper to get an uint value from GenericCLIResults -func (f GenericCLIResults) Uint(flag string) uint { - r := f.findResult(flag) - if r == nil { - return 0 - } - return r.Value().(uint) -} - -// StringSlice is a wrapper to get a stringslice value from GenericCLIResults -func (f GenericCLIResults) StringSlice(flag string) []string { - r := f.findResult(flag) - if r == nil { - return []string{} - } - return r.Value().([]string) -} - -// StringArray is a wrapper to get a stringslice value from GenericCLIResults -func (f GenericCLIResults) StringArray(flag string) []string { - r := f.findResult(flag) - if r == nil { - return []string{} - } - return r.Value().([]string) -} - -// Uint64 is a wrapper to get an uint64 value from GenericCLIResults -func (f GenericCLIResults) Uint64(flag string) uint64 { - r := f.findResult(flag) - if r == nil { - return 0 - } - return r.Value().(uint64) -} - -// Int64 is a wrapper to get an int64 value from GenericCLIResults -func (f GenericCLIResults) Int64(flag string) int64 { - r := f.findResult(flag) - if r == nil { - return 0 - } - return r.Value().(int64) -} - -// Int is a wrapper to get an int value from GenericCLIResults -func (f GenericCLIResults) Int(flag string) int { - r := f.findResult(flag) - if r == nil { - return 0 - } - return r.Value().(int) -} - -// Float64 is a wrapper to get an float64 value from GenericCLIResults -func (f GenericCLIResults) Float64(flag string) float64 { - r := f.findResult(flag) - if r == nil { - return 0 - } - return r.Value().(float64) -} - -// Float64 is a wrapper to get an float64 value from GenericCLIResults -func (f GenericCLIResults) Changed(flag string) bool { - r := f.findResult(flag) - if r == nil { - return false - } - return r.IsSet() -} - -// IsSet ... -func (c CRStringSlice) IsSet() bool { return c.Changed } - -// Name ... -func (c CRStringSlice) Name() string { return c.Flag } - -// Value ... -func (c CRStringSlice) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRString) IsSet() bool { return c.Changed } - -// Name ... -func (c CRString) Name() string { return c.Flag } - -// Value ... -func (c CRString) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRUint64) IsSet() bool { return c.Changed } - -// Name ... -func (c CRUint64) Name() string { return c.Flag } - -// Value ... -func (c CRUint64) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRFloat64) IsSet() bool { return c.Changed } - -// Name ... -func (c CRFloat64) Name() string { return c.Flag } - -// Value ... -func (c CRFloat64) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRBool) IsSet() bool { return c.Changed } - -// Name ... -func (c CRBool) Name() string { return c.Flag } - -// Value ... -func (c CRBool) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRInt64) IsSet() bool { return c.Changed } - -// Name ... -func (c CRInt64) Name() string { return c.Flag } - -// Value ... -func (c CRInt64) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRUint) IsSet() bool { return c.Changed } - -// Name ... -func (c CRUint) Name() string { return c.Flag } - -// Value ... -func (c CRUint) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRInt) IsSet() bool { return c.Changed } - -// Name ... -func (c CRInt) Name() string { return c.Flag } - -// Value ... -func (c CRInt) Value() interface{} { return c.Val } - -// IsSet ... -func (c CRStringArray) IsSet() bool { return c.Changed } - -// Name ... -func (c CRStringArray) Name() string { return c.Flag } - -// Value ... -func (c CRStringArray) Value() interface{} { return c.Val } diff --git a/pkg/varlinkapi/intermediate_varlink.go b/pkg/varlinkapi/intermediate_varlink.go deleted file mode 100644 index 0d74f1a95..000000000 --- a/pkg/varlinkapi/intermediate_varlink.go +++ /dev/null @@ -1,457 +0,0 @@ -// +build varlink remoteclient - -package varlinkapi - -import ( - "github.com/containers/common/pkg/config" - "github.com/containers/podman/v2/pkg/rootless" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/pkg/errors" -) - -//FIXME these are duplicated here to resolve a circular -//import with cmd/podman/common. -var ( - // DefaultHealthCheckInterval default value - DefaultHealthCheckInterval = "30s" - // DefaultHealthCheckRetries default value - DefaultHealthCheckRetries uint = 3 - // DefaultHealthCheckStartPeriod default value - DefaultHealthCheckStartPeriod = "0s" - // DefaultHealthCheckTimeout default value - DefaultHealthCheckTimeout = "30s" - // DefaultImageVolume default value - DefaultImageVolume = "bind" -) - -// StringSliceToPtr converts a genericcliresult value into a *[]string -func StringSliceToPtr(g GenericCLIResult) *[]string { - if !g.IsSet() { - return nil - } - newT := g.Value().([]string) - return &newT -} - -// StringToPtr converts a genericcliresult value into a *string -func StringToPtr(g GenericCLIResult) *string { - if !g.IsSet() { - return nil - } - newT := g.Value().(string) - return &newT -} - -// BoolToPtr converts a genericcliresult value into a *bool -func BoolToPtr(g GenericCLIResult) *bool { - if !g.IsSet() { - return nil - } - newT := g.Value().(bool) - return &newT -} - -// AnyIntToInt64Ptr converts a genericcliresult value into an *int64 -func AnyIntToInt64Ptr(g GenericCLIResult) *int64 { - if !g.IsSet() { - return nil - } - var newT int64 - switch g.Value().(type) { - case int: - newT = int64(g.Value().(int)) - case int64: - newT = g.Value().(int64) - case uint64: - newT = int64(g.Value().(uint64)) - case uint: - newT = int64(g.Value().(uint)) - default: - panic(errors.Errorf("invalid int type")) - } - return &newT -} - -// Float64ToPtr converts a genericcliresult into a *float64 -func Float64ToPtr(g GenericCLIResult) *float64 { - if !g.IsSet() { - return nil - } - newT := g.Value().(float64) - return &newT -} - -// MakeVarlink creates a varlink transportable struct from GenericCLIResults -func (g GenericCLIResults) MakeVarlink() iopodman.Create { - v := iopodman.Create{ - Args: g.InputArgs, - AddHost: StringSliceToPtr(g.Find("add-host")), - Annotation: StringSliceToPtr(g.Find("annotation")), - Attach: StringSliceToPtr(g.Find("attach")), - BlkioWeight: StringToPtr(g.Find("blkio-weight")), - BlkioWeightDevice: StringSliceToPtr(g.Find("blkio-weight-device")), - CapAdd: StringSliceToPtr(g.Find("cap-add")), - CapDrop: StringSliceToPtr(g.Find("cap-drop")), - CgroupParent: StringToPtr(g.Find("cgroup-parent")), - CidFile: StringToPtr(g.Find("cidfile")), - ConmonPidfile: StringToPtr(g.Find("conmon-pidfile")), - CpuPeriod: AnyIntToInt64Ptr(g.Find("cpu-period")), - CpuQuota: AnyIntToInt64Ptr(g.Find("cpu-quota")), - CpuRtPeriod: AnyIntToInt64Ptr(g.Find("cpu-rt-period")), - CpuRtRuntime: AnyIntToInt64Ptr(g.Find("cpu-rt-runtime")), - CpuShares: AnyIntToInt64Ptr(g.Find("cpu-shares")), - Cpus: Float64ToPtr(g.Find("cpus")), - CpuSetCpus: StringToPtr(g.Find("cpuset-cpus")), - CpuSetMems: StringToPtr(g.Find("cpuset-mems")), - Detach: BoolToPtr(g.Find("detach")), - DetachKeys: StringToPtr(g.Find("detach-keys")), - Device: StringSliceToPtr(g.Find("device")), - DeviceReadBps: StringSliceToPtr(g.Find("device-read-bps")), - DeviceReadIops: StringSliceToPtr(g.Find("device-read-iops")), - DeviceWriteBps: StringSliceToPtr(g.Find("device-write-bps")), - DeviceWriteIops: StringSliceToPtr(g.Find("device-write-iops")), - Dns: StringSliceToPtr(g.Find("dns")), - DnsOpt: StringSliceToPtr(g.Find("dns-opt")), - DnsSearch: StringSliceToPtr(g.Find("dns-search")), - Entrypoint: StringToPtr(g.Find("entrypoint")), - Env: StringSliceToPtr(g.Find("env")), - EnvFile: StringSliceToPtr(g.Find("env-file")), - Expose: StringSliceToPtr(g.Find("expose")), - Gidmap: StringSliceToPtr(g.Find("gidmap")), - Groupadd: StringSliceToPtr(g.Find("group-add")), - HealthcheckCommand: StringToPtr(g.Find("healthcheck-command")), - HealthcheckInterval: StringToPtr(g.Find("healthcheck-interval")), - HealthcheckRetries: AnyIntToInt64Ptr(g.Find("healthcheck-retries")), - HealthcheckStartPeriod: StringToPtr(g.Find("healthcheck-start-period")), - HealthcheckTimeout: StringToPtr(g.Find("healthcheck-timeout")), - Hostname: StringToPtr(g.Find("hostname")), - ImageVolume: StringToPtr(g.Find("image-volume")), - Init: BoolToPtr(g.Find("init")), - InitPath: StringToPtr(g.Find("init-path")), - Interactive: BoolToPtr(g.Find("interactive")), - Ip: StringToPtr(g.Find("ip")), - Ipc: StringToPtr(g.Find("ipc")), - KernelMemory: StringToPtr(g.Find("kernel-memory")), - Label: StringSliceToPtr(g.Find("label")), - LabelFile: StringSliceToPtr(g.Find("label-file")), - LogDriver: StringToPtr(g.Find("log-driver")), - LogOpt: StringSliceToPtr(g.Find("log-opt")), - MacAddress: StringToPtr(g.Find("mac-address")), - Memory: StringToPtr(g.Find("memory")), - MemoryReservation: StringToPtr(g.Find("memory-reservation")), - MemorySwap: StringToPtr(g.Find("memory-swap")), - MemorySwappiness: AnyIntToInt64Ptr(g.Find("memory-swappiness")), - Name: StringToPtr(g.Find("name")), - Network: StringToPtr(g.Find("network")), - OomKillDisable: BoolToPtr(g.Find("oom-kill-disable")), - OomScoreAdj: AnyIntToInt64Ptr(g.Find("oom-score-adj")), - OverrideOS: StringToPtr(g.Find("override-os")), - OverrideArch: StringToPtr(g.Find("override-arch")), - Pid: StringToPtr(g.Find("pid")), - PidsLimit: AnyIntToInt64Ptr(g.Find("pids-limit")), - Pod: StringToPtr(g.Find("pod")), - Privileged: BoolToPtr(g.Find("privileged")), - Publish: StringSliceToPtr(g.Find("publish")), - PublishAll: BoolToPtr(g.Find("publish-all")), - Pull: StringToPtr(g.Find("pull")), - Quiet: BoolToPtr(g.Find("quiet")), - Readonly: BoolToPtr(g.Find("read-only")), - Readonlytmpfs: BoolToPtr(g.Find("read-only-tmpfs")), - Restart: StringToPtr(g.Find("restart")), - Rm: BoolToPtr(g.Find("rm")), - Rootfs: BoolToPtr(g.Find("rootfs")), - SecurityOpt: StringSliceToPtr(g.Find("security-opt")), - ShmSize: StringToPtr(g.Find("shm-size")), - StopSignal: StringToPtr(g.Find("stop-signal")), - StopTimeout: AnyIntToInt64Ptr(g.Find("stop-timeout")), - StorageOpt: StringSliceToPtr(g.Find("storage-opt")), - Subuidname: StringToPtr(g.Find("subuidname")), - Subgidname: StringToPtr(g.Find("subgidname")), - Sysctl: StringSliceToPtr(g.Find("sysctl")), - Systemd: StringToPtr(g.Find("systemd")), - Tmpfs: StringSliceToPtr(g.Find("tmpfs")), - Tty: BoolToPtr(g.Find("tty")), - Uidmap: StringSliceToPtr(g.Find("uidmap")), - Ulimit: StringSliceToPtr(g.Find("ulimit")), - User: StringToPtr(g.Find("user")), - Userns: StringToPtr(g.Find("userns")), - Uts: StringToPtr(g.Find("uts")), - Mount: StringSliceToPtr(g.Find("mount")), - Volume: StringSliceToPtr(g.Find("volume")), - VolumesFrom: StringSliceToPtr(g.Find("volumes-from")), - WorkDir: StringToPtr(g.Find("workdir")), - } - - return v -} - -func stringSliceFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringSlice { - cr := CRStringSlice{} - if v == nil { - cr.Val = []string{} - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func stringFromVarlink(v *string, flagName string, defaultValue *string) CRString { - cr := CRString{} - if v == nil { - cr.Val = "" - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool { - cr := CRBool{} - if v == nil { - // In case a cli bool default value is true - cr.Val = defaultValue - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func uint64FromVarlink(v *int64, flagName string, defaultValue *uint64) CRUint64 { - cr := CRUint64{} - if v == nil { - cr.Val = 0 - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = uint64(*v) - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func int64FromVarlink(v *int64, flagName string, defaultValue *int64) CRInt64 { - cr := CRInt64{} - if v == nil { - cr.Val = 0 - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func float64FromVarlink(v *float64, flagName string, defaultValue *float64) CRFloat64 { - cr := CRFloat64{} - if v == nil { - cr.Val = 0 - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func uintFromVarlink(v *int64, flagName string, defaultValue *uint) CRUint { - cr := CRUint{} - if v == nil { - cr.Val = 0 - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = uint(*v) - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func stringArrayFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringArray { - cr := CRStringArray{} - if v == nil { - cr.Val = []string{} - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Changed = false - } else { - cr.Val = *v - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt { - cr := CRInt{} - if v == nil { - if defaultValue != nil { - cr.Val = *defaultValue - } - cr.Val = 0 - cr.Changed = false - } else { - cr.Val = int(*v) - cr.Changed = true - } - cr.Flag = flagName - return cr -} - -// VarlinkCreateToGeneric creates a GenericCLIResults from the varlink create -// structure. -func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults { - // FIXME this will need to be fixed!!!!! With containers conf - //containerConfig := cliconfig.GetDefaultConfig() - // TODO | WARN - // We do not get a default network over varlink. Unlike the other default values for some cli - // elements, it seems it gets set to the default anyway. - - var memSwapDefault int64 = -1 - netModeDefault := "bridge" - systemdDefault := "true" - if rootless.IsRootless() { - netModeDefault = "slirp4netns" - } - - shmSize := config.DefaultShmSize - - m := make(map[string]GenericCLIResult) - m["add-host"] = stringSliceFromVarlink(opts.AddHost, "add-host", nil) - m["annotation"] = stringSliceFromVarlink(opts.Annotation, "annotation", nil) - m["attach"] = stringSliceFromVarlink(opts.Attach, "attach", nil) - m["blkio-weight"] = stringFromVarlink(opts.BlkioWeight, "blkio-weight", nil) - m["blkio-weight-device"] = stringSliceFromVarlink(opts.BlkioWeightDevice, "blkio-weight-device", nil) - m["cap-add"] = stringSliceFromVarlink(opts.CapAdd, "cap-add", nil) - m["cap-drop"] = stringSliceFromVarlink(opts.CapDrop, "cap-drop", nil) - m["cgroup-parent"] = stringFromVarlink(opts.CgroupParent, "cgroup-parent", nil) - m["cidfile"] = stringFromVarlink(opts.CidFile, "cidfile", nil) - m["conmon-pidfile"] = stringFromVarlink(opts.ConmonPidfile, "conmon-file", nil) - m["cpu-period"] = uint64FromVarlink(opts.CpuPeriod, "cpu-period", nil) - m["cpu-quota"] = int64FromVarlink(opts.CpuQuota, "quota", nil) - m["cpu-rt-period"] = uint64FromVarlink(opts.CpuRtPeriod, "cpu-rt-period", nil) - m["cpu-rt-runtime"] = int64FromVarlink(opts.CpuRtRuntime, "cpu-rt-quota", nil) - m["cpu-shares"] = uint64FromVarlink(opts.CpuShares, "cpu-shares", nil) - m["cpus"] = float64FromVarlink(opts.Cpus, "cpus", nil) - m["cpuset-cpus"] = stringFromVarlink(opts.CpuSetCpus, "cpuset-cpus", nil) - m["cpuset-mems"] = stringFromVarlink(opts.CpuSetMems, "cpuset-mems", nil) - m["detach"] = boolFromVarlink(opts.Detach, "detach", false) - m["detach-keys"] = stringFromVarlink(opts.DetachKeys, "detach-keys", nil) - m["device"] = stringSliceFromVarlink(opts.Device, "device", nil) - m["device-read-bps"] = stringSliceFromVarlink(opts.DeviceReadBps, "device-read-bps", nil) - m["device-read-iops"] = stringSliceFromVarlink(opts.DeviceReadIops, "device-read-iops", nil) - m["device-write-bps"] = stringSliceFromVarlink(opts.DeviceWriteBps, "write-device-bps", nil) - m["device-write-iops"] = stringSliceFromVarlink(opts.DeviceWriteIops, "write-device-iops", nil) - m["dns"] = stringSliceFromVarlink(opts.Dns, "dns", nil) - m["dns-opt"] = stringSliceFromVarlink(opts.DnsOpt, "dns-opt", nil) - m["dns-search"] = stringSliceFromVarlink(opts.DnsSearch, "dns-search", nil) - m["entrypoint"] = stringFromVarlink(opts.Entrypoint, "entrypoint", nil) - m["env"] = stringArrayFromVarlink(opts.Env, "env", nil) - m["env-file"] = stringSliceFromVarlink(opts.EnvFile, "env-file", nil) - m["expose"] = stringSliceFromVarlink(opts.Expose, "expose", nil) - m["gidmap"] = stringSliceFromVarlink(opts.Gidmap, "gidmap", nil) - m["group-add"] = stringSliceFromVarlink(opts.Groupadd, "group-add", nil) - m["healthcheck-command"] = stringFromVarlink(opts.HealthcheckCommand, "healthcheck-command", nil) - m["healthcheck-interval"] = stringFromVarlink(opts.HealthcheckInterval, "healthcheck-interval", &DefaultHealthCheckInterval) - m["healthcheck-retries"] = uintFromVarlink(opts.HealthcheckRetries, "healthcheck-retries", &DefaultHealthCheckRetries) - m["healthcheck-start-period"] = stringFromVarlink(opts.HealthcheckStartPeriod, "healthcheck-start-period", &DefaultHealthCheckStartPeriod) - m["healthcheck-timeout"] = stringFromVarlink(opts.HealthcheckTimeout, "healthcheck-timeout", &DefaultHealthCheckTimeout) - m["hostname"] = stringFromVarlink(opts.Hostname, "hostname", nil) - m["image-volume"] = stringFromVarlink(opts.ImageVolume, "image-volume", &DefaultImageVolume) - m["init"] = boolFromVarlink(opts.Init, "init", false) - m["init-path"] = stringFromVarlink(opts.InitPath, "init-path", nil) - m["interactive"] = boolFromVarlink(opts.Interactive, "interactive", false) - m["ip"] = stringFromVarlink(opts.Ip, "ip", nil) - m["ipc"] = stringFromVarlink(opts.Ipc, "ipc", nil) - m["kernel-memory"] = stringFromVarlink(opts.KernelMemory, "kernel-memory", nil) - m["label"] = stringArrayFromVarlink(opts.Label, "label", nil) - m["label-file"] = stringSliceFromVarlink(opts.LabelFile, "label-file", nil) - m["log-driver"] = stringFromVarlink(opts.LogDriver, "log-driver", nil) - m["log-opt"] = stringSliceFromVarlink(opts.LogOpt, "log-opt", nil) - m["mac-address"] = stringFromVarlink(opts.MacAddress, "mac-address", nil) - m["memory"] = stringFromVarlink(opts.Memory, "memory", nil) - m["memory-reservation"] = stringFromVarlink(opts.MemoryReservation, "memory-reservation", nil) - m["memory-swap"] = stringFromVarlink(opts.MemorySwap, "memory-swap", nil) - m["memory-swappiness"] = int64FromVarlink(opts.MemorySwappiness, "memory-swappiness", &memSwapDefault) - m["name"] = stringFromVarlink(opts.Name, "name", nil) - m["network"] = stringFromVarlink(opts.Network, "network", &netModeDefault) - m["no-hosts"] = boolFromVarlink(opts.NoHosts, "no-hosts", false) - m["oom-kill-disable"] = boolFromVarlink(opts.OomKillDisable, "oon-kill-disable", false) - m["oom-score-adj"] = intFromVarlink(opts.OomScoreAdj, "oom-score-adj", nil) - m["override-os"] = stringFromVarlink(opts.OverrideOS, "override-os", nil) - m["override-arch"] = stringFromVarlink(opts.OverrideArch, "override-arch", nil) - m["pid"] = stringFromVarlink(opts.Pid, "pid", nil) - m["pids-limit"] = int64FromVarlink(opts.PidsLimit, "pids-limit", nil) - m["pod"] = stringFromVarlink(opts.Pod, "pod", nil) - m["privileged"] = boolFromVarlink(opts.Privileged, "privileged", false) - m["publish"] = stringSliceFromVarlink(opts.Publish, "publish", nil) - m["publish-all"] = boolFromVarlink(opts.PublishAll, "publish-all", false) - m["pull"] = stringFromVarlink(opts.Pull, "missing", nil) - m["quiet"] = boolFromVarlink(opts.Quiet, "quiet", false) - m["read-only"] = boolFromVarlink(opts.Readonly, "read-only", false) - m["read-only-tmpfs"] = boolFromVarlink(opts.Readonlytmpfs, "read-only-tmpfs", true) - m["restart"] = stringFromVarlink(opts.Restart, "restart", nil) - m["rm"] = boolFromVarlink(opts.Rm, "rm", false) - m["rootfs"] = boolFromVarlink(opts.Rootfs, "rootfs", false) - m["security-opt"] = stringArrayFromVarlink(opts.SecurityOpt, "security-opt", nil) - m["shm-size"] = stringFromVarlink(opts.ShmSize, "shm-size", &shmSize) - m["stop-signal"] = stringFromVarlink(opts.StopSignal, "stop-signal", nil) - m["stop-timeout"] = uintFromVarlink(opts.StopTimeout, "stop-timeout", nil) - m["storage-opt"] = stringSliceFromVarlink(opts.StorageOpt, "storage-opt", nil) - m["subgidname"] = stringFromVarlink(opts.Subgidname, "subgidname", nil) - m["subuidname"] = stringFromVarlink(opts.Subuidname, "subuidname", nil) - m["sysctl"] = stringSliceFromVarlink(opts.Sysctl, "sysctl", nil) - m["systemd"] = stringFromVarlink(opts.Systemd, "systemd", &systemdDefault) - m["tmpfs"] = stringSliceFromVarlink(opts.Tmpfs, "tmpfs", nil) - m["tty"] = boolFromVarlink(opts.Tty, "tty", false) - m["uidmap"] = stringSliceFromVarlink(opts.Uidmap, "uidmap", nil) - m["ulimit"] = stringSliceFromVarlink(opts.Ulimit, "ulimit", nil) - m["user"] = stringFromVarlink(opts.User, "user", nil) - m["userns"] = stringFromVarlink(opts.Userns, "userns", nil) - m["uts"] = stringFromVarlink(opts.Uts, "uts", nil) - m["mount"] = stringArrayFromVarlink(opts.Mount, "mount", nil) - m["volume"] = stringArrayFromVarlink(opts.Volume, "volume", nil) - m["volumes-from"] = stringSliceFromVarlink(opts.VolumesFrom, "volumes-from", nil) - m["workdir"] = stringFromVarlink(opts.WorkDir, "workdir", nil) - - gcli := GenericCLIResults{m, opts.Args} - return gcli -} - -// Find returns a flag from a GenericCLIResults by name -func (g GenericCLIResults) Find(name string) GenericCLIResult { - result, ok := g.results[name] - if ok { - return result - } - panic(errors.Errorf("unable to find generic flag for varlink %s", name)) -} diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go deleted file mode 100644 index 6fd4de709..000000000 --- a/pkg/varlinkapi/mount.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build varlink - -package varlinkapi - -import iopodman "github.com/containers/podman/v2/pkg/varlink" - -// ListContainerMounts ... -func (i *VarlinkAPI) ListContainerMounts(call iopodman.VarlinkCall) error { - mounts := make(map[string]string) - allContainers, err := i.Runtime.GetAllContainers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - for _, container := range allContainers { - mounted, mountPoint, err := container.Mounted() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if mounted { - mounts[container.ID()] = mountPoint - } - } - return call.ReplyListContainerMounts(mounts) -} - -// MountContainer ... -func (i *VarlinkAPI) MountContainer(call iopodman.VarlinkCall, name string) error { - container, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - path, err := container.Mount() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyMountContainer(path) -} - -// UnmountContainer ... -func (i *VarlinkAPI) UnmountContainer(call iopodman.VarlinkCall, name string, force bool) error { - container, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := container.Unmount(force); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyUnmountContainer() -} diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go deleted file mode 100644 index 6d03afb7a..000000000 --- a/pkg/varlinkapi/pods.go +++ /dev/null @@ -1,389 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "syscall" - - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/docker/go-connections/nat" - "github.com/pkg/errors" -) - -// CreatePod ... -func (i *VarlinkAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error { - var options []libpod.PodCreateOption - if create.Infra { - options = append(options, libpod.WithInfraContainer()) - nsOptions, err := GetNamespaceOptions(create.Share) - if err != nil { - return err - } - options = append(options, nsOptions...) - } - if create.CgroupParent != "" { - options = append(options, libpod.WithPodCgroupParent(create.CgroupParent)) - } - if len(create.Labels) > 0 { - options = append(options, libpod.WithPodLabels(create.Labels)) - } - if create.Name != "" { - options = append(options, libpod.WithPodName(create.Name)) - } - if len(create.Share) > 0 && !create.Infra { - return call.ReplyErrorOccurred("You cannot share kernel namespaces on the pod level without an infra container") - } - if len(create.Share) == 0 && create.Infra { - return call.ReplyErrorOccurred("You must share kernel namespaces to run an infra container") - } - - if len(create.Publish) > 0 { - if !create.Infra { - return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host") - } - portBindings, err := CreatePortBindings(create.Publish) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - options = append(options, libpod.WithInfraContainerPorts(portBindings)) - - } - options = append(options, libpod.WithPodCgroups()) - - pod, err := i.Runtime.NewPod(getContext(), options...) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyCreatePod(pod.ID()) -} - -// ListPods ... -func (i *VarlinkAPI) ListPods(call iopodman.VarlinkCall) error { - var ( - listPods []iopodman.ListPodData - ) - - pods, err := i.Runtime.GetAllPods() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - opts := PsOptions{} - for _, pod := range pods { - listPod, err := makeListPod(pod, opts) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - listPods = append(listPods, listPod) - } - return call.ReplyListPods(listPods) -} - -// GetPod ... -func (i *VarlinkAPI) GetPod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - opts := PsOptions{} - - listPod, err := makeListPod(pod, opts) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - return call.ReplyGetPod(listPod) -} - -// GetPodsByStatus returns a slice of pods filtered by a libpod status -func (i *VarlinkAPI) GetPodsByStatus(call iopodman.VarlinkCall, statuses []string) error { - filterFuncs := func(p *libpod.Pod) bool { - state, _ := p.GetPodStatus() - for _, status := range statuses { - if state == status { - return true - } - } - return false - } - filteredPods, err := i.Runtime.Pods(filterFuncs) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - podIDs := make([]string, 0, len(filteredPods)) - for _, p := range filteredPods { - podIDs = append(podIDs, p.ID()) - } - return call.ReplyGetPodsByStatus(podIDs) -} - -// InspectPod ... -func (i *VarlinkAPI) InspectPod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - inspectData, err := pod.Inspect() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(&inspectData) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize") - } - return call.ReplyInspectPod(string(b)) -} - -// StartPod ... -func (i *VarlinkAPI) StartPod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctnrs, err := pod.AllContainers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if 0 == len(ctnrs) { - return call.ReplyNoContainersInPod(name) - } - ctrErrs, err := pod.Start(getContext()) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyStartPod(pod.ID()) -} - -// StopPod ... -func (i *VarlinkAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout)) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyStopPod(pod.ID()) -} - -// RestartPod ... -func (i *VarlinkAPI) RestartPod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctnrs, err := pod.AllContainers() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if 0 == len(ctnrs) { - return call.ReplyNoContainersInPod(name) - } - ctrErrs, err := pod.Restart(getContext()) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyRestartPod(pod.ID()) -} - -// KillPod kills the running containers in a pod. If you want to use the default SIGTERM signal, -// just send a -1 for the signal arg. -func (i *VarlinkAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64) error { - killSignal := uint(syscall.SIGTERM) - if signal != -1 { - killSignal = uint(signal) - } - - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctrErrs, err := pod.Kill(context.TODO(), killSignal) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyKillPod(pod.ID()) -} - -// PausePod ... -func (i *VarlinkAPI) PausePod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctrErrs, err := pod.Pause(context.TODO()) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyPausePod(pod.ID()) -} - -// UnpausePod ... -func (i *VarlinkAPI) UnpausePod(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - ctrErrs, err := pod.Unpause(context.TODO()) - callErr := handlePodCall(call, pod, ctrErrs, err) - if callErr != nil { - return err - } - return call.ReplyUnpausePod(pod.ID()) -} - -// RemovePod ... -func (i *VarlinkAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool) error { - ctx := getContext() - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - if err = i.Runtime.RemovePod(ctx, pod, true, force); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - return call.ReplyRemovePod(pod.ID()) -} - -// GetPodStats ... -func (i *VarlinkAPI) GetPodStats(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - prevStats := make(map[string]*define.ContainerStats) - podStats, err := pod.GetPodStats(prevStats) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if len(podStats) == 0 { - return call.ReplyNoContainerRunning() - } - containersStats := make([]iopodman.ContainerStats, 0) - for ctrID, containerStats := range podStats { - cs := iopodman.ContainerStats{ - Id: ctrID, - Name: containerStats.Name, - Cpu: containerStats.CPU, - Cpu_nano: int64(containerStats.CPUNano), - System_nano: int64(containerStats.SystemNano), - Mem_usage: int64(containerStats.MemUsage), - Mem_limit: int64(containerStats.MemLimit), - Mem_perc: containerStats.MemPerc, - Net_input: int64(containerStats.NetInput), - Net_output: int64(containerStats.NetOutput), - Block_input: int64(containerStats.BlockInput), - Block_output: int64(containerStats.BlockOutput), - Pids: int64(containerStats.PIDs), - } - containersStats = append(containersStats, cs) - } - return call.ReplyGetPodStats(pod.ID(), containersStats) -} - -// getPodsByContext returns a slice of pod ids based on all, latest, or a list -func (i *VarlinkAPI) GetPodsByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error { - var podids []string - - pods, err := getPodsByContext(all, latest, input, i.Runtime) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - for _, p := range pods { - podids = append(podids, p.ID()) - } - return call.ReplyGetPodsByContext(podids) -} - -// PodStateData returns a container's state data in string format -func (i *VarlinkAPI) PodStateData(call iopodman.VarlinkCall, name string) error { - pod, err := i.Runtime.LookupPod(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - data, err := pod.Inspect() - if err != nil { - return call.ReplyErrorOccurred("unable to obtain pod state") - } - b, err := json.Marshal(data) - if err != nil { - return call.ReplyErrorOccurred("unable to serialize pod inspect data") - } - return call.ReplyPodStateData(string(b)) -} - -// TopPod provides the top stats for a given or latest pod -func (i *VarlinkAPI) TopPod(call iopodman.VarlinkCall, name string, latest bool, descriptors []string) error { - var ( - pod *libpod.Pod - err error - ) - if latest { - name = "latest" - pod, err = i.Runtime.GetLatestPod() - } else { - pod, err = i.Runtime.LookupPod(name) - } - if err != nil { - return call.ReplyPodNotFound(name, err.Error()) - } - - podStatus, err := pod.GetPodStatus() - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to get status for pod %s", pod.ID())) - } - if podStatus != "Running" { - return call.ReplyErrorOccurred("pod top can only be used on pods with at least one running container") - } - reply, err := pod.GetPodPidInformation(descriptors) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyTopPod(reply) -} - -// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands -func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) { - var portBindings []ocicni.PortMapping - // The conversion from []string to natBindings is temporary while mheon reworks the port - // deduplication code. Eventually that step will not be required. - _, natBindings, err := nat.ParsePortSpecs(ports) - if err != nil { - return nil, err - } - for containerPb, hostPb := range natBindings { - 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) - pm.Protocol = containerPb.Proto() - portBindings = append(portBindings, pm) - } - } - return portBindings, nil -} diff --git a/pkg/varlinkapi/remote_client.go b/pkg/varlinkapi/remote_client.go deleted file mode 100644 index 88c11c126..000000000 --- a/pkg/varlinkapi/remote_client.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build varlink remoteclient - -package varlinkapi - -import ( - "github.com/containers/podman/v2/libpod/define" - iopodman "github.com/containers/podman/v2/pkg/varlink" -) - -// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod -// container stats -func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) define.ContainerStats { - cstats := define.ContainerStats{ - ContainerID: stats.Id, - Name: stats.Name, - CPU: stats.Cpu, - CPUNano: uint64(stats.Cpu_nano), - SystemNano: uint64(stats.System_nano), - MemUsage: uint64(stats.Mem_usage), - MemLimit: uint64(stats.Mem_limit), - MemPerc: stats.Mem_perc, - NetInput: uint64(stats.Net_input), - NetOutput: uint64(stats.Net_output), - BlockInput: uint64(stats.Block_input), - BlockOutput: uint64(stats.Block_output), - PIDs: uint64(stats.Pids), - } - return cstats -} diff --git a/pkg/varlinkapi/shortcuts.go b/pkg/varlinkapi/shortcuts.go deleted file mode 100644 index bfb05c0e3..000000000 --- a/pkg/varlinkapi/shortcuts.go +++ /dev/null @@ -1,66 +0,0 @@ -package varlinkapi - -import ( - "github.com/containers/podman/v2/libpod" - "github.com/sirupsen/logrus" -) - -// getPodsByContext returns a slice of pods. Note that all, latest and pods are -// mutually exclusive arguments. -func getPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) { - var outpods []*libpod.Pod - if all { - return runtime.GetAllPods() - } - if latest { - p, err := runtime.GetLatestPod() - if err != nil { - return nil, err - } - outpods = append(outpods, p) - return outpods, nil - } - var err error - for _, p := range pods { - pod, e := runtime.LookupPod(p) - if e != nil { - // Log all errors here, so callers don't need to. - logrus.Debugf("Error looking up pod %q: %v", p, e) - if err == nil { - err = e - } - } else { - outpods = append(outpods, pod) - } - } - return outpods, err -} - -// getContainersByContext gets pods whether all, latest, or a slice of names/ids -// is specified. -func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) { - var ctr *libpod.Container - ctrs = []*libpod.Container{} - - switch { - case all: - ctrs, err = runtime.GetAllContainers() - case latest: - ctr, err = runtime.GetLatestContainer() - ctrs = append(ctrs, ctr) - default: - for _, n := range names { - ctr, e := runtime.LookupContainer(n) - if e != nil { - // Log all errors here, so callers don't need to. - logrus.Debugf("Error looking up container %q: %v", n, e) - if err == nil { - err = e - } - } else { - ctrs = append(ctrs, ctr) - } - } - } - return -} diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go deleted file mode 100644 index e5c766a6d..000000000 --- a/pkg/varlinkapi/system.go +++ /dev/null @@ -1,129 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "context" - "fmt" - "os" - goruntime "runtime" - "strconv" - "time" - - "github.com/containers/image/v5/pkg/sysregistriesv2" - "github.com/containers/podman/v2/libpod/define" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/sirupsen/logrus" -) - -// GetVersion ... -func (i *VarlinkAPI) GetVersion(call iopodman.VarlinkCall) error { - versionInfo, err := define.GetVersion() - if err != nil { - return err - } - - int64APIVersion, err := strconv.ParseInt(versionInfo.APIVersion, 10, 64) - if err != nil { - return err - } - - return call.ReplyGetVersion( - versionInfo.Version, - versionInfo.GoVersion, - versionInfo.GitCommit, - time.Unix(versionInfo.Built, 0).Format(time.RFC3339), - versionInfo.OsArch, - int64APIVersion, - ) -} - -// GetInfo returns details about the podman host and its stores -func (i *VarlinkAPI) GetInfo(call iopodman.VarlinkCall) error { - versionInfo, err := define.GetVersion() - if err != nil { - return err - } - podmanInfo := iopodman.PodmanInfo{} - info, err := i.Runtime.Info() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - distribution := iopodman.InfoDistribution{ - Distribution: info.Host.Distribution.Distribution, - Version: info.Host.Distribution.Version, - } - infoHost := iopodman.InfoHost{ - Buildah_version: info.Host.BuildahVersion, - Distribution: distribution, - Mem_free: info.Host.MemFree, - Mem_total: info.Host.MemTotal, - Swap_free: info.Host.SwapFree, - Swap_total: info.Host.SwapTotal, - Arch: info.Host.Arch, - Cpus: int64(info.Host.CPUs), - Hostname: info.Host.Hostname, - Kernel: info.Host.Kernel, - Os: info.Host.OS, - Uptime: info.Host.Uptime, - Eventlogger: info.Host.EventLogger, - } - podmanInfo.Host = infoHost - pmaninfo := iopodman.InfoPodmanBinary{ - Compiler: goruntime.Compiler, - Go_version: goruntime.Version(), - Podman_version: versionInfo.Version, - Git_commit: versionInfo.GitCommit, - } - - graphStatus := iopodman.InfoGraphStatus{ - Backing_filesystem: info.Store.GraphStatus["Backing Filesystem"], - Native_overlay_diff: info.Store.GraphStatus["Native Overlay Diff"], - Supports_d_type: info.Store.GraphStatus["Supports d_type"], - } - infoStore := iopodman.InfoStore{ - Graph_driver_name: info.Store.GraphDriverName, - Containers: int64(info.Store.ContainerStore.Number), - Images: int64(info.Store.ImageStore.Number), - Run_root: info.Store.RunRoot, - Graph_root: info.Store.GraphRoot, - Graph_driver_options: fmt.Sprintf("%v", info.Store.GraphOptions), - Graph_status: graphStatus, - } - - // Registry information if any is stored as the second list item - for key, val := range info.Registries { - if key == "search" { - podmanInfo.Registries.Search = val.([]string) - continue - } - regData := val.(sysregistriesv2.Registry) - if regData.Insecure { - podmanInfo.Registries.Insecure = append(podmanInfo.Registries.Insecure, key) - } - if regData.Blocked { - podmanInfo.Registries.Blocked = append(podmanInfo.Registries.Blocked, key) - } - } - podmanInfo.Store = infoStore - podmanInfo.Podman = pmaninfo - return call.ReplyGetInfo(podmanInfo) -} - -// GetVersion ... -func (i *VarlinkAPI) Reset(call iopodman.VarlinkCall) error { - if err := i.Runtime.Reset(context.TODO()); err != nil { - logrus.Errorf("Reset Failed: %v", err) - if err := call.ReplyErrorOccurred(err.Error()); err != nil { - logrus.Errorf("Failed to send ReplyErrorOccurred: %v", err) - } - os.Exit(define.ExecErrorCodeGeneric) - } - if err := call.ReplyReset(); err != nil { - logrus.Errorf("Failed to send ReplyReset: %v", err) - os.Exit(define.ExecErrorCodeGeneric) - } - os.Exit(0) - return nil -} diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go deleted file mode 100644 index a4550a417..000000000 --- a/pkg/varlinkapi/transfers.go +++ /dev/null @@ -1,80 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "bufio" - "io" - "io/ioutil" - "os" - - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/sirupsen/logrus" -) - -// SendFile allows a client to send a file to the varlink server -func (i *VarlinkAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int64) error { - if !call.WantsUpgrade() { - return call.ReplyErrorOccurred("client must use upgraded connection to send files") - } - - outputFile, err := ioutil.TempFile("", "varlink_send") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - defer outputFile.Close() - - if err = call.ReplySendFile(outputFile.Name()); err != nil { - // If an error occurs while sending the reply, return the error - return err - } - - writer := bufio.NewWriter(outputFile) - defer writer.Flush() - - reader := call.Call.Reader - if _, err := io.CopyN(writer, reader, length); err != nil { - return err - } - - logrus.Debugf("successfully received %s", outputFile.Name()) - // Send an ACK to the client - call.Call.Writer.WriteString(outputFile.Name() + ":") - call.Call.Writer.Flush() - return nil - -} - -// ReceiveFile allows the varlink server to send a file to a client -func (i *VarlinkAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, delete bool) error { - if !call.WantsUpgrade() { - return call.ReplyErrorOccurred("client must use upgraded connection to send files") - } - fs, err := os.Open(filepath) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - fileInfo, err := fs.Stat() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - // Send the file length down to client - // Varlink connection upgraded - if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil { - // If an error occurs while sending the reply, return the error - return err - } - - reader := bufio.NewReader(fs) - _, err = reader.WriteTo(call.Writer) - if err != nil { - return err - } - if delete { - if err := os.Remove(filepath); err != nil { - return err - } - } - return call.Writer.Flush() -} diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go deleted file mode 100644 index 7f96965f0..000000000 --- a/pkg/varlinkapi/util.go +++ /dev/null @@ -1,237 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "context" - "strconv" - "strings" - "time" - - "github.com/containers/buildah" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/pkg/channel" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/storage/pkg/archive" -) - -// getContext returns a non-nil, empty context -func getContext() context.Context { - return context.TODO() -} - -func makeListContainer(containerID string, batchInfo BatchContainerStruct) iopodman.Container { - var ( - mounts []iopodman.ContainerMount - ports []iopodman.ContainerPortMappings - ) - ns := GetNamespaces(batchInfo.Pid) - - for _, mount := range batchInfo.ConConfig.Spec.Mounts { - m := iopodman.ContainerMount{ - Destination: mount.Destination, - Type: mount.Type, - Source: mount.Source, - Options: mount.Options, - } - mounts = append(mounts, m) - } - - for _, pm := range batchInfo.ConConfig.PortMappings { - p := iopodman.ContainerPortMappings{ - Host_port: strconv.Itoa(int(pm.HostPort)), - Host_ip: pm.HostIP, - Protocol: pm.Protocol, - Container_port: strconv.Itoa(int(pm.ContainerPort)), - } - ports = append(ports, p) - - } - - // If we find this needs to be done for other container endpoints, we should - // convert this to a separate function or a generic map from struct function. - namespace := iopodman.ContainerNameSpace{ - User: ns.User, - Uts: ns.UTS, - Pidns: ns.PIDNS, - Pid: ns.PID, - Cgroup: ns.Cgroup, - Net: ns.NET, - Mnt: ns.MNT, - Ipc: ns.IPC, - } - - lc := iopodman.Container{ - Id: containerID, - Image: batchInfo.ConConfig.RootfsImageName, - Imageid: batchInfo.ConConfig.RootfsImageID, - Command: batchInfo.ConConfig.Spec.Process.Args, - Createdat: batchInfo.ConConfig.CreatedTime.Format(time.RFC3339), - Runningfor: time.Since(batchInfo.ConConfig.CreatedTime).String(), - Status: batchInfo.ConState.String(), - Ports: ports, - Names: batchInfo.ConConfig.Name, - Labels: batchInfo.ConConfig.Labels, - Mounts: mounts, - Containerrunning: batchInfo.ConState == define.ContainerStateRunning, - Namespaces: namespace, - } - if batchInfo.Size != nil { - lc.Rootfssize = batchInfo.Size.RootFsSize - lc.Rwsize = batchInfo.Size.RwSize - } - return lc -} - -func makeListPodContainers(containerID string, batchInfo BatchContainerStruct) iopodman.ListPodContainerInfo { - lc := iopodman.ListPodContainerInfo{ - Id: containerID, - Status: batchInfo.ConState.String(), - Name: batchInfo.ConConfig.Name, - } - return lc -} - -func makeListPod(pod *libpod.Pod, batchInfo PsOptions) (iopodman.ListPodData, error) { - var listPodsContainers []iopodman.ListPodContainerInfo - var errPodData = iopodman.ListPodData{} - status, err := pod.GetPodStatus() - if err != nil { - return errPodData, err - } - containers, err := pod.AllContainers() - if err != nil { - return errPodData, err - } - for _, ctr := range containers { - batchInfo, err := BatchContainerOp(ctr, batchInfo) - if err != nil { - return errPodData, err - } - - listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo)) - } - listPod := iopodman.ListPodData{ - Createdat: pod.CreatedTime().Format(time.RFC3339), - Id: pod.ID(), - Name: pod.Name(), - Status: status, - Cgroup: pod.CgroupParent(), - Numberofcontainers: strconv.Itoa(len(listPodsContainers)), - Containersinfo: listPodsContainers, - } - return listPod, nil -} - -func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[string]error, err error) error { - if err != nil && ctrErrs == nil { - return call.ReplyErrorOccurred(err.Error()) - } - if ctrErrs != nil { - containerErrs := make([]iopodman.PodContainerErrorData, len(ctrErrs)) - for ctr, reason := range ctrErrs { - ctrErr := iopodman.PodContainerErrorData{Containerid: ctr, Reason: reason.Error()} - containerErrs = append(containerErrs, ctrErr) - } - return call.ReplyPodContainerError(pod.ID(), containerErrs) - } - - return nil -} - -func stringCompressionToArchiveType(s string) archive.Compression { - switch strings.ToUpper(s) { - case "BZIP2": - return archive.Bzip2 - case "GZIP": - return archive.Gzip - case "XZ": - return archive.Xz - } - return archive.Uncompressed -} - -func stringPullPolicyToType(s string) buildah.PullPolicy { - switch strings.ToUpper(s) { - case "PULLIFMISSING": - return buildah.PullIfMissing - case "PULLALWAYS": - return buildah.PullAlways - case "PULLNEVER": - return buildah.PullNever - } - return buildah.PullIfMissing -} - -func derefBool(inBool *bool) bool { - if inBool == nil { - return false - } - return *inBool -} - -func derefString(in *string) string { - if in == nil { - return "" - } - return *in -} - -func makePsOpts(inOpts iopodman.PsOpts) PsOptions { - last := 0 - if inOpts.Last != nil { - lastT := *inOpts.Last - last = int(lastT) - } - return PsOptions{ - All: inOpts.All, - Last: last, - Latest: derefBool(inOpts.Latest), - NoTrunc: derefBool(inOpts.NoTrunc), - Pod: derefBool(inOpts.Pod), - Size: derefBool(inOpts.Size), - Sort: derefString(inOpts.Sort), - Namespace: true, - Sync: derefBool(inOpts.Sync), - } -} - -// forwardOutput is a helper method for varlink endpoints that employ both more and without -// more. it is capable of sending updates as the output writer gets them or append them -// all to a log. the chan error is the error from the libpod call so we can honor -// and error event in that case. -func forwardOutput(log []string, c chan error, wantsMore bool, output channel.WriteCloser, reply func(br iopodman.MoreResponse) error) ([]string, error) { - done := false - for { - select { - // We need to check if the libpod func being called has returned an - // error yet - case err := <-c: - if err != nil { - return nil, err - } - done = true - // if no error is found, we pull what we can from the log writer and - // append it to log string slice - case line := <-output.Chan(): - log = append(log, string(line)) - // If the end point is being used in more mode, send what we have - if wantsMore { - br := iopodman.MoreResponse{ - Logs: log, - } - if err := reply(br); err != nil { - return nil, err - } - // "reset" the log to empty because we are sending what we - // get as we get it - log = []string{} - } - } - if done { - break - } - } - return log, nil -} diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go deleted file mode 100644 index d96e82a3f..000000000 --- a/pkg/varlinkapi/virtwriter/virtwriter.go +++ /dev/null @@ -1,204 +0,0 @@ -package virtwriter - -import ( - "bufio" - "encoding/binary" - "encoding/json" - "io" - "time" - - "github.com/pkg/errors" - "k8s.io/client-go/tools/remotecommand" -) - -// SocketDest is the "key" to where IO should go on the varlink -// multiplexed socket -type SocketDest int - -const ( - // ToStdout indicates traffic should go stdout - ToStdout SocketDest = iota - // ToStdin indicates traffic came from stdin - ToStdin SocketDest = iota - // ToStderr indicates traffuc should go to stderr - ToStderr SocketDest = iota - // TerminalResize indicates a terminal resize event has occurred - // and data should be passed to resizer - TerminalResize SocketDest = iota - // Quit and detach - Quit SocketDest = iota - // HangUpFromClient hangs up from the client - HangUpFromClient SocketDest = iota -) - -// ErrClientHangup signifies that the client wants to drop its connection from -// the server. -var ErrClientHangup = errors.New("client hangup") - -// IntToSocketDest returns a socketdest based on integer input -func IntToSocketDest(i int) SocketDest { - switch i { - case ToStdout.Int(): - return ToStdout - case ToStderr.Int(): - return ToStderr - case ToStdin.Int(): - return ToStdin - case TerminalResize.Int(): - return TerminalResize - case Quit.Int(): - return Quit - case HangUpFromClient.Int(): - return HangUpFromClient - default: - return ToStderr - } -} - -// Int returns the integer representation of the socket dest -func (sd SocketDest) Int() int { - return int(sd) -} - -// VirtWriteCloser are writers for attach which include the dest -// of the data -type VirtWriteCloser struct { - writer *bufio.Writer - dest SocketDest -} - -// NewVirtWriteCloser is a constructor -func NewVirtWriteCloser(w *bufio.Writer, dest SocketDest) VirtWriteCloser { - return VirtWriteCloser{w, dest} -} - -// Close is a required method for a writecloser -func (v VirtWriteCloser) Close() error { - return v.writer.Flush() -} - -// Write prepends a header to the input message. The header is -// 8bytes. Position one contains the destination. Positions -// 5,6,7,8 are a big-endian encoded uint32 for len of the message. -func (v VirtWriteCloser) Write(input []byte) (int, error) { - header := []byte{byte(v.dest), 0, 0, 0} - // Go makes us define the byte for big endian - mlen := make([]byte, 4) - binary.BigEndian.PutUint32(mlen, uint32(len(input))) - // append the message len to the header - msg := append(header, mlen...) - // append the message to the header - msg = append(msg, input...) - _, err := v.writer.Write(msg) - if err != nil { - return 0, err - } - err = v.writer.Flush() - return len(input), err -} - -// Reader decodes the content that comes over the wire and directs it to the proper destination. -func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remotecommand.TerminalSize, execEcChan chan int) error { - var messageSize int64 - headerBytes := make([]byte, 8) - - if r == nil { - return errors.Errorf("Reader must not be nil") - } - for { - n, err := io.ReadFull(r, headerBytes) - if err != nil { - return errors.Wrapf(err, "Virtual Read failed, %d", n) - } - if n < 8 { - return errors.New("short read and no full header read") - } - - messageSize = int64(binary.BigEndian.Uint32(headerBytes[4:8])) - switch IntToSocketDest(int(headerBytes[0])) { - case ToStdout: - if output != nil { - _, err := io.CopyN(output, r, messageSize) - if err != nil { - return err - } - } - case ToStderr: - if errput != nil { - _, err := io.CopyN(errput, r, messageSize) - if err != nil { - return err - } - } - case ToStdin: - if input != nil { - _, err := io.CopyN(input, r, messageSize) - if err != nil { - return err - } - } - case TerminalResize: - if resize != nil { - out := make([]byte, messageSize) - if messageSize > 0 { - _, err = io.ReadFull(r, out) - - if err != nil { - return err - } - } - // Resize events come over in bytes, need to be reserialized - resizeEvent := remotecommand.TerminalSize{} - if err := json.Unmarshal(out, &resizeEvent); err != nil { - return err - } - resize <- resizeEvent - } - case Quit: - out := make([]byte, messageSize) - if messageSize > 0 { - _, err = io.ReadFull(r, out) - - if err != nil { - return err - } - } - if execEcChan != nil { - ecInt := binary.BigEndian.Uint32(out) - execEcChan <- int(ecInt) - } - return nil - case HangUpFromClient: - // This sleep allows the pipes to flush themselves before tearing everything down. - // It makes me sick to do it but after a full day I cannot put my finger on the race - // that occurs when closing things up. It would require a significant rewrite of code - // to make the pipes close down properly. Given that we are currently discussing a - // rewrite of all things remote, this hardly seems worth resolving. - // - // reproducer: echo hello | (podman-remote run -i alpine cat) - time.Sleep(1 * time.Second) - return ErrClientHangup - default: - // Something really went wrong - return errors.New("unknown multiplex destination") - } - } -} - -// HangUp sends message to peer to close connection -func HangUp(writer *bufio.Writer, ec uint32) (err error) { - n := 0 - msg := make([]byte, 4) - - binary.BigEndian.PutUint32(msg, ec) - - writeQuit := NewVirtWriteCloser(writer, Quit) - if n, err = writeQuit.Write(msg); err != nil { - return - } - - if n != len(msg) { - return errors.Errorf("Failed to send complete %s message", string(msg)) - } - return -} diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go deleted file mode 100644 index 7cc714ea4..000000000 --- a/pkg/varlinkapi/volumes.go +++ /dev/null @@ -1,165 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "context" - "encoding/json" - - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/pkg/domain/infra/abi/parse" - iopodman "github.com/containers/podman/v2/pkg/varlink" -) - -// VolumeCreate creates a libpod volume based on input from a varlink connection -func (i *VarlinkAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.VolumeCreateOpts) error { - var volumeOptions []libpod.VolumeCreateOption - - if len(options.VolumeName) > 0 { - volumeOptions = append(volumeOptions, libpod.WithVolumeName(options.VolumeName)) - } - if len(options.Driver) > 0 { - volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(options.Driver)) - } - if len(options.Labels) > 0 { - volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels)) - } - if len(options.Options) > 0 { - parsedOptions, err := parse.VolumeOptions(options.Options) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - volumeOptions = append(volumeOptions, parsedOptions...) - } - newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyVolumeCreate(newVolume.Name()) -} - -// VolumeRemove removes volumes by options.All or options.Volumes -func (i *VarlinkAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.VolumeRemoveOpts) error { - success, failed, err := SharedRemoveVolumes(getContext(), i.Runtime, options.Volumes, options.All, options.Force) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - // Convert map[string]string to map[string]error - errStrings := make(map[string]string) - for k, v := range failed { - errStrings[k] = v.Error() - } - return call.ReplyVolumeRemove(success, errStrings) -} - -// GetVolumes returns all the volumes known to the remote system -func (i *VarlinkAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error { - var ( - err error - reply []*libpod.Volume - volumes []iopodman.Volume - ) - if all { - reply, err = i.Runtime.GetAllVolumes() - } else { - for _, v := range args { - vol, err := i.Runtime.GetVolume(v) - if err != nil { - return err - } - reply = append(reply, vol) - } - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - // Build the iopodman.volume struct for the return - for _, v := range reply { - newVol := iopodman.Volume{ - Driver: v.Driver(), - Labels: v.Labels(), - MountPoint: v.MountPoint(), - Name: v.Name(), - Options: v.Options(), - } - volumes = append(volumes, newVol) - } - return call.ReplyGetVolumes(volumes) -} - -// InspectVolume inspects a single volume, returning its JSON as a string. -func (i *VarlinkAPI) InspectVolume(call iopodman.VarlinkCall, name string) error { - vol, err := i.Runtime.LookupVolume(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - inspectOut, err := vol.Inspect() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - inspectJSON, err := json.Marshal(inspectOut) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyInspectVolume(string(inspectJSON)) -} - -// VolumesPrune removes unused images via a varlink call -func (i *VarlinkAPI) VolumesPrune(call iopodman.VarlinkCall) error { - var ( - prunedErrors []string - prunedNames []string - ) - responses, err := i.Runtime.PruneVolumes(getContext()) - if err != nil { - return call.ReplyVolumesPrune([]string{}, []string{err.Error()}) - } - for k, v := range responses { - if v == nil { - prunedNames = append(prunedNames, k) - } else { - prunedErrors = append(prunedErrors, v.Error()) - } - } - return call.ReplyVolumesPrune(prunedNames, prunedErrors) -} - -// Remove given set of volumes -func SharedRemoveVolumes(ctx context.Context, runtime *libpod.Runtime, vols []string, all, force bool) ([]string, map[string]error, error) { - var ( - toRemove []*libpod.Volume - success []string - failed map[string]error - ) - - failed = make(map[string]error) - - if all { - vols, err := runtime.Volumes() - if err != nil { - return nil, nil, err - } - toRemove = vols - } else { - for _, v := range vols { - vol, err := runtime.LookupVolume(v) - if err != nil { - failed[v] = err - continue - } - toRemove = append(toRemove, vol) - } - } - - // We could parallelize this, but I haven't heard anyone complain about - // performance here yet, so hold off. - for _, vol := range toRemove { - if err := runtime.RemoveVolume(ctx, vol, force); err != nil { - failed[vol.Name()] = err - continue - } - success = append(success, vol.Name()) - } - - return success, failed, nil -} diff --git a/test/apiv2/23-containersArchive.at b/test/apiv2/23-containersArchive.at new file mode 100644 index 000000000..459800196 --- /dev/null +++ b/test/apiv2/23-containersArchive.at @@ -0,0 +1,81 @@ +# -*- sh -*- +# +# test more container-related endpoints +# + +red='\e[31m' +nc='\e[0m' + +podman pull $IMAGE &>/dev/null + +# Ensure clean slate +podman rm -a -f &>/dev/null + +CTR="ArchiveTestingCtr" + +TMPD=$(mktemp -d) +pushd "${TMPD}" +echo "Hello" > "hello.txt" +tar --format=posix -cvf "hello.tar" "hello.txt" &> /dev/null +popd + +HELLO_TAR="${TMPD}/hello.tar" + +podman run -d --name "${CTR}" "${IMAGE}" top + +function cleanUpArchiveTest() { + podman container stop "${CTR}" &> /dev/null + podman container rm "${CTR}" &> /dev/null + rm -fr "${TMPD}" &> /dev/null +} + +t HEAD "containers/nonExistentCtr/archive?path=%2F" 404 +t HEAD "containers/${CTR}/archive?path=%2Fnon%2Fexistent%2Fpath" 404 +t HEAD "containers/${CTR}/archive?path=%2Fetc%2Fpasswd" 200 + +curl "http://$HOST:$PORT/containers/${CTR}/archive?path=%2Ftmp%2F" \ + -X PUT \ + -H "Content-Type: application/x-tar" \ + --upload-file "${HELLO_TAR}" &> /dev/null + +if ! podman exec -it "${CTR}" "grep" "Hello" "/tmp/hello.txt" &> /dev/null ; then + echo -e "${red}NOK: The hello.txt file has not been uploaded.${nc}" 1>&2; + cleanUpArchiveTest + exit 1 +fi + +t HEAD "containers/${CTR}/archive?path=%2Ftmp%2Fhello.txt" 200 + +curl "http://$HOST:$PORT/containers/${CTR}/archive?path=%2Ftmp%2Fhello.txt" \ + --dump-header "${TMPD}/headers.txt" \ + -o "${TMPD}/body.tar" \ + -X GET &> /dev/null + +PATH_STAT="$(grep X-Docker-Container-Path-Stat "${TMPD}/headers.txt" | cut -d " " -f 2 | base64 -d --ignore-garbage)" + +ARCHIVE_TEST_ERROR="" + +if [ "$(echo "${PATH_STAT}" | jq ".name")" != '"hello.txt"' ]; then + echo -e "${red}NOK: Wrong name in X-Docker-Container-Path-Stat header.${nc}" 1>&2; + ARCHIVE_TEST_ERROR="1" +fi + +if [ "$(echo "${PATH_STAT}" | jq ".size")" != "6" ]; then + echo -e "${red}NOK: Wrong size in X-Docker-Container-Path-Stat header.${nc}" 1>&2; + ARCHIVE_TEST_ERROR="1" +fi + +if ! tar -tf "${TMPD}/body.tar" | grep "hello.txt" &> /dev/null; then + echo -e "${red}NOK: Body doesn't contain expected file.${nc}" 1>&2; + ARCHIVE_TEST_ERROR="1" +fi + +if [ "$(tar -xf "${TMPD}/body.tar" hello.txt --to-stdout)" != "Hello" ]; then + echo -e "${red}NOK: Content of file doesn't match.${nc}" 1>&2; + ARCHIVE_TEST_ERROR="1" +fi + +cleanUpArchiveTest +if [[ "${ARCHIVE_TEST_ERROR}" ]] ; then + exit 1; +fi diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index facafcb77..16d8bb770 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -661,7 +661,7 @@ func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd return &PodmanSessionIntegration{podmanSession} } -// We don't support running Varlink when local +// RestartRemoteService stop and start API Server, usually to change config func (p *PodmanTestIntegration) RestartRemoteService() { p.StopRemoteService() p.StartRemoteService() @@ -788,3 +788,9 @@ func generateNetworkConfig(p *PodmanTestIntegration) (string, string) { return name, path } + +func (p *PodmanTestIntegration) removeCNINetwork(name string) { + session := p.Podman([]string{"network", "rm", "-f", name}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeNumerically("<=", 1)) +} diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index fe8b8fe56..da57bb4c0 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -107,7 +107,6 @@ func (p *PodmanTestIntegration) StopRemoteService() { } } else { - //p.ResetVarlinkAddress() parentPid := fmt.Sprintf("%d", p.RemoteSession.Pid) pgrep := exec.Command("pgrep", "-P", parentPid) fmt.Printf("running: pgrep %s\n", parentPid) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index c37b24ab6..0ae30ca10 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -59,13 +59,12 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error { } func (p *PodmanTestIntegration) StopRemoteService() {} -func (p *PodmanTestIntegration) DelayForVarlink() {} // SeedImages is a no-op for localized testing func (p *PodmanTestIntegration) SeedImages() error { return nil } -// We don't support running Varlink when local +// We don't support running API service when local func (p *PodmanTestIntegration) StartRemoteService() { } diff --git a/test/e2e/libpod_suite_varlink_test.go b/test/e2e/libpod_suite_varlink_test.go deleted file mode 100644 index 275a1115e..000000000 --- a/test/e2e/libpod_suite_varlink_test.go +++ /dev/null @@ -1,207 +0,0 @@ -// +build remoteclientvarlink - -package integration - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "syscall" - "time" - - "github.com/containers/podman/v2/pkg/rootless" - - "github.com/onsi/ginkgo" -) - -func IsRemote() bool { - return true -} - -func SkipIfRemote(reason string) { - ginkgo.Skip("[remote]: " + reason) -} - -// Podman is the exec call to podman on the filesystem -func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { - podmanSession := p.PodmanBase(args, false, false) - return &PodmanSessionIntegration{podmanSession} -} - -// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files -func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles) - return &PodmanSessionIntegration{podmanSession} -} - -// PodmanNoCache calls podman with out adding the imagecache -func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration { - podmanSession := p.PodmanBase(args, false, true) - return &PodmanSessionIntegration{podmanSession} -} - -// PodmanNoEvents calls the Podman command without an imagecache and without an -// events backend. It is used mostly for caching and uncaching images. -func (p *PodmanTestIntegration) PodmanNoEvents(args []string) *PodmanSessionIntegration { - podmanSession := p.PodmanBase(args, true, true) - return &PodmanSessionIntegration{podmanSession} -} - -func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() { - defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf") - os.Setenv("REGISTRIES_CONFIG_PATH", defaultFile) -} - -func (p *PodmanTestIntegration) setRegistriesConfigEnv(b []byte) { - outfile := filepath.Join(p.TempDir, "registries.conf") - os.Setenv("REGISTRIES_CONFIG_PATH", outfile) - ioutil.WriteFile(outfile, b, 0644) -} - -func resetRegistriesConfigEnv() { - os.Setenv("REGISTRIES_CONFIG_PATH", "") -} -func PodmanTestCreate(tempDir string) *PodmanTestIntegration { - pti := PodmanTestCreateUtil(tempDir, true) - pti.StartRemoteService() - return pti -} - -func (p *PodmanTestIntegration) ResetVarlinkAddress() { - //os.Unsetenv("PODMAN_VARLINK_ADDRESS") -} - -func (p *PodmanTestIntegration) SetVarlinkAddress(addr string) { - //os.Setenv("PODMAN_VARLINK_ADDRESS", addr) -} - -func (p *PodmanTestIntegration) StartVarlink() { - if os.Geteuid() == 0 { - os.MkdirAll("/run/podman", 0755) - } - varlinkEndpoint := p.RemoteSocket - p.SetVarlinkAddress(p.RemoteSocket) - - args := []string{"varlink", "--time", "0", varlinkEndpoint} - podmanOptions := getVarlinkOptions(p, args) - command := exec.Command(p.PodmanBinary, podmanOptions...) - fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) - command.Start() - command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - p.RemoteCommand = command - p.RemoteSession = command.Process - p.DelayForService() -} - -func (p *PodmanTestIntegration) StopVarlink() { - var out bytes.Buffer - var pids []int - varlinkSession := p.RemoteSession - - if !rootless.IsRootless() { - if err := varlinkSession.Kill(); err != nil { - fmt.Fprintf(os.Stderr, "error on varlink stop-kill %q", err) - } - if _, err := varlinkSession.Wait(); err != nil { - fmt.Fprintf(os.Stderr, "error on varlink stop-wait %q", err) - } - - } else { - p.ResetVarlinkAddress() - parentPid := fmt.Sprintf("%d", p.RemoteSession.Pid) - pgrep := exec.Command("pgrep", "-P", parentPid) - fmt.Printf("running: pgrep %s\n", parentPid) - pgrep.Stdout = &out - err := pgrep.Run() - if err != nil { - fmt.Fprint(os.Stderr, "unable to find varlink pid") - } - - for _, s := range strings.Split(out.String(), "\n") { - if len(s) == 0 { - continue - } - p, err := strconv.Atoi(s) - if err != nil { - fmt.Fprintf(os.Stderr, "unable to convert %s to int", s) - } - if p != 0 { - pids = append(pids, p) - } - } - - pids = append(pids, p.RemoteSession.Pid) - for _, pid := range pids { - syscall.Kill(pid, syscall.SIGKILL) - } - } - socket := strings.Split(p.RemoteSocket, ":")[1] - if err := os.Remove(socket); err != nil { - fmt.Println(err) - } -} - -//MakeOptions assembles all the podman main options -func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache bool) []string { - return args -} - -//MakeOptions assembles all the podman main options -func getVarlinkOptions(p *PodmanTestIntegration, args []string) []string { - podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s", - p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ") - if os.Getenv("HOOK_OPTION") != "" { - podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) - } - podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) - podmanOptions = append(podmanOptions, args...) - return podmanOptions -} - -func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - p.CrioRoot = p.ImageCacheDir - restore := p.PodmanNoEvents([]string{"load", "-q", "-i", destName}) - restore.WaitWithDefaultTimeout() - return nil -} - -// SeedImages restores all the artifacts into the main store for remote tests -func (p *PodmanTestIntegration) SeedImages() error { - return p.RestoreAllArtifacts() -} - -// RestoreArtifact puts the cached image into our test store -func (p *PodmanTestIntegration) RestoreArtifact(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - args := []string{"load", "-q", "-i", destName} - podmanOptions := getVarlinkOptions(p, args) - command := exec.Command(p.PodmanBinary, podmanOptions...) - fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) - command.Start() - command.Wait() - return nil -} - -func (p *PodmanTestIntegration) DelayForVarlink() { - for i := 0; i < 5; i++ { - session := p.Podman([]string{"info"}) - session.WaitWithDefaultTimeout() - if session.ExitCode() == 0 || i == 4 { - break - } - time.Sleep(1 * time.Second) - } -} - -func populateCache(podman *PodmanTestIntegration) {} -func removeCache() {} diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go new file mode 100644 index 000000000..7cdad9bf2 --- /dev/null +++ b/test/e2e/network_connect_disconnect_test.go @@ -0,0 +1,217 @@ +package integration + +import ( + "os" + + . "github.com/containers/podman/v2/test/utils" + "github.com/containers/storage/pkg/stringid" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman network connect and disconnect", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("bad network name in disconnect should result in error", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + dis := podmanTest.Podman([]string{"network", "disconnect", "foobar", "test"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).ToNot(BeZero()) + + }) + + It("bad container name in network disconnect should result in error", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + dis := podmanTest.Podman([]string{"network", "disconnect", netName, "foobar"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).ToNot(BeZero()) + + }) + + It("podman network disconnect", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(BeZero()) + + exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + + dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).To(BeZero()) + + exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).ToNot(BeZero()) + }) + + It("bad network name in connect should result in error", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + dis := podmanTest.Podman([]string{"network", "connect", "foobar", "test"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).ToNot(BeZero()) + + }) + + It("bad container name in network connect should result in error", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + dis := podmanTest.Podman([]string{"network", "connect", netName, "foobar"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).ToNot(BeZero()) + + }) + + It("podman connect on a container that already is connected to the network should error", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(BeZero()) + + con := podmanTest.Podman([]string{"network", "connect", netName, "test"}) + con.WaitWithDefaultTimeout() + Expect(con.ExitCode()).ToNot(BeZero()) + }) + + It("podman network connect", func() { + SkipIfRemote("This requires a pending PR to be merged before it will work") + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(BeZero()) + + exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + + // Create a second network + newNetName := "aliasTest" + stringid.GenerateNonCryptoID() + session = podmanTest.Podman([]string{"network", "create", newNetName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(newNetName) + + connect := podmanTest.Podman([]string{"network", "connect", newNetName, "test"}) + connect.WaitWithDefaultTimeout() + Expect(connect.ExitCode()).To(BeZero()) + + exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + }) + + It("podman network connect when not running", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + ctr := podmanTest.Podman([]string{"create", "--name", "test", ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(BeZero()) + + dis := podmanTest.Podman([]string{"network", "connect", netName, "test"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).To(BeZero()) + + start := podmanTest.Podman([]string{"start", "test"}) + start.WaitWithDefaultTimeout() + Expect(start.ExitCode()).To(BeZero()) + + exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + + exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + }) + + It("podman network disconnect when not running", func() { + SkipIfRootless("network connect and disconnect are only rootfull") + netName1 := "aliasTest" + stringid.GenerateNonCryptoID() + session := podmanTest.Podman([]string{"network", "create", netName1}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName1) + + netName2 := "aliasTest" + stringid.GenerateNonCryptoID() + session2 := podmanTest.Podman([]string{"network", "create", netName2}) + session2.WaitWithDefaultTimeout() + Expect(session2.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName2) + + ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName1 + "," + netName2, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(BeZero()) + + dis := podmanTest.Podman([]string{"network", "disconnect", netName1, "test"}) + dis.WaitWithDefaultTimeout() + Expect(dis.ExitCode()).To(BeZero()) + + start := podmanTest.Podman([]string{"start", "test"}) + start.WaitWithDefaultTimeout() + Expect(start.ExitCode()).To(BeZero()) + + exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(BeZero()) + + exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).ToNot(BeZero()) + }) +}) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index cb997d10a..043046c33 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -55,12 +55,6 @@ func genericPluginsToPortMap(plugins interface{}, pluginType string) (network.Po return portMap, err } -func (p *PodmanTestIntegration) removeCNINetwork(name string) { - session := p.Podman([]string{"network", "rm", "-f", name}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeNumerically("<=", 1)) -} - func removeNetworkDevice(name string) { session := SystemExec("ip", []string{"link", "delete", name}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index adcf74f7e..20e1d5b6b 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -347,159 +347,6 @@ var _ = Describe("Podman network", func() { Expect(c3.ExitCode()).To(BeZero()) }) - It("bad network name in disconnect should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - dis := podmanTest.Podman([]string{"network", "disconnect", "foobar", "test"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - - }) - - It("bad container name in network disconnect should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - dis := podmanTest.Podman([]string{"network", "disconnect", netName, "foobar"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - - }) - - It("podman network disconnect with invalid container state should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"}) - ctr.WaitWithDefaultTimeout() - Expect(ctr.ExitCode()).To(BeZero()) - - dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - }) - - It("podman network disconnect", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"}) - ctr.WaitWithDefaultTimeout() - Expect(ctr.ExitCode()).To(BeZero()) - - exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) - exec.WaitWithDefaultTimeout() - Expect(exec.ExitCode()).To(BeZero()) - - dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).To(BeZero()) - - exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) - exec.WaitWithDefaultTimeout() - Expect(exec.ExitCode()).ToNot(BeZero()) - }) - - It("bad network name in connect should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - dis := podmanTest.Podman([]string{"network", "connect", "foobar", "test"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - - }) - - It("bad container name in network connect should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - dis := podmanTest.Podman([]string{"network", "connect", netName, "foobar"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - - }) - - It("podman connect on a container that already is connected to the network should error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"}) - ctr.WaitWithDefaultTimeout() - Expect(ctr.ExitCode()).To(BeZero()) - - con := podmanTest.Podman([]string{"network", "connect", netName, "test"}) - con.WaitWithDefaultTimeout() - Expect(con.ExitCode()).ToNot(BeZero()) - }) - - It("podman network connect with invalid container state should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"}) - ctr.WaitWithDefaultTimeout() - Expect(ctr.ExitCode()).To(BeZero()) - - dis := podmanTest.Podman([]string{"network", "connect", netName, "test"}) - dis.WaitWithDefaultTimeout() - Expect(dis.ExitCode()).ToNot(BeZero()) - }) - - It("podman network connect", func() { - SkipIfRemote("This requires a pending PR to be merged before it will work") - SkipIfRootless("network connect and disconnect are only rootfull") - netName := "aliasTest" + stringid.GenerateNonCryptoID() - session := podmanTest.Podman([]string{"network", "create", netName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(netName) - - ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"}) - ctr.WaitWithDefaultTimeout() - Expect(ctr.ExitCode()).To(BeZero()) - - exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) - exec.WaitWithDefaultTimeout() - Expect(exec.ExitCode()).To(BeZero()) - - // Create a second network - newNetName := "aliasTest" + stringid.GenerateNonCryptoID() - session = podmanTest.Podman([]string{"network", "create", newNetName}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork(newNetName) - - connect := podmanTest.Podman([]string{"network", "connect", newNetName, "test"}) - connect.WaitWithDefaultTimeout() - Expect(connect.ExitCode()).To(BeZero()) - - exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) - exec.WaitWithDefaultTimeout() - Expect(exec.ExitCode()).To(BeZero()) - }) - It("podman network create/remove macvlan", func() { net := "macvlan" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--macvlan", "lo", net}) diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go index b2d350436..e716ce4f3 100644 --- a/test/e2e/system_reset_test.go +++ b/test/e2e/system_reset_test.go @@ -59,7 +59,7 @@ var _ = Describe("podman system reset", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - // If remote then the varlink service should have exited + // If remote then the API service should have exited // On local tests this is a noop podmanTest.StartRemoteService() diff --git a/test/endpoint/commit.go b/test/endpoint/commit.go deleted file mode 100644 index 97e10efb0..000000000 --- a/test/endpoint/commit.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "encoding/json" - "os" - - . "github.com/containers/podman/v2/test/utils" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Podman commit", func() { - var ( - tempdir string - err error - endpointTest *EndpointTestIntegration - ) - - BeforeEach(func() { - tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } - endpointTest = Setup(tempdir) - endpointTest.StartVarlinkWithCache() - }) - - AfterEach(func() { - endpointTest.Cleanup() - - }) - - It("ensure commit with uppercase image name does not panic", func() { - body := make(map[string]string) - body["image_name"] = "FOO" - body["format"] = "oci" - body["name"] = "top" - b, err := json.Marshal(body) - Expect(err).To(BeNil()) - // run the container to be committed - _ = endpointTest.startTopContainer("top") - result := endpointTest.Varlink("Commit", string(b), false) - // This indicates an error occurred - Expect(len(result.StdErrToString())).To(BeNumerically(">", 0)) - }) - -}) diff --git a/test/endpoint/config.go b/test/endpoint/config.go deleted file mode 100644 index 9d2a5a239..000000000 --- a/test/endpoint/config.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build varlink - -package endpoint - -import "encoding/json" - -var ( - STORAGE_FS = "vfs" - STORAGE_OPTIONS = "--storage-driver vfs" - ROOTLESS_STORAGE_FS = "vfs" - ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" - CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra, labels} - nginx = "quay.io/libpod/alpine_nginx:latest" - BB_GLIBC = "docker.io/library/busybox:glibc" - registry = "docker.io/library/registry:2.6" - labels = "quay.io/libpod/alpine_labels:latest" -) - -func makeNameMessage(name string) string { - n := make(map[string]string) - n["name"] = name - b, _ := json.Marshal(n) - return string(b) -} diff --git a/test/endpoint/endpoint.go b/test/endpoint/endpoint.go deleted file mode 100644 index d2c143824..000000000 --- a/test/endpoint/endpoint.go +++ /dev/null @@ -1,225 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "os/exec" - "strconv" - "strings" - "syscall" - "time" - - "github.com/containers/podman/v2/pkg/rootless" - iopodman "github.com/containers/podman/v2/pkg/varlink" - . "github.com/onsi/ginkgo" - "github.com/onsi/gomega/gexec" -) - -var ( - ARTIFACT_DIR = "/tmp/.artifacts" - CGROUP_MANAGER = "systemd" - defaultWaitTimeout = 90 - //RESTORE_IMAGES = []string{ALPINE, BB} - INTEGRATION_ROOT string - ImageCacheDir = "/tmp/podman/imagecachedir" - VarlinkBinary = "/usr/bin/varlink" - ALPINE = "docker.io/library/alpine:latest" - infra = "k8s.gcr.io/pause:3.2" - BB = "docker.io/library/busybox:latest" - redis = "docker.io/library/redis:alpine" - fedoraMinimal = "quay.io/libpod/fedora-minimal:latest" -) - -type EndpointTestIntegration struct { - ArtifactPath string - CNIConfigDir string - CgroupManager string - ConmonBinary string - CrioRoot string - //Host HostOS - ImageCacheDir string - ImageCacheFS string - OCIRuntime string - PodmanBinary string - RemoteTest bool - RunRoot string - SignaturePolicyPath string - StorageOptions string - TmpDir string - Timings []string - VarlinkBinary string - VarlinkCommand *exec.Cmd - VarlinkEndpoint string - VarlinkSession *os.Process -} - -func (p *EndpointTestIntegration) StartVarlink() { - p.startVarlink(false) -} - -func (p *EndpointTestIntegration) StartVarlinkWithCache() { - p.startVarlink(true) -} - -func (p *EndpointTestIntegration) startVarlink(useImageCache bool) { - var ( - counter int - ) - if os.Geteuid() == 0 { - os.MkdirAll("/run/podman", 0755) - } - varlinkEndpoint := p.VarlinkEndpoint - //p.SetVarlinkAddress(p.RemoteSocket) - - args := []string{"varlink", "--time", "0", varlinkEndpoint} - podmanOptions := getVarlinkOptions(p, args) - if useImageCache { - cacheOptions := []string{"--storage-opt", fmt.Sprintf("%s.imagestore=%s", p.ImageCacheFS, p.ImageCacheDir)} - podmanOptions = append(cacheOptions, podmanOptions...) - } - command := exec.Command(p.PodmanBinary, podmanOptions...) - fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) - command.Start() - command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - p.VarlinkCommand = command - p.VarlinkSession = command.Process - for { - if result := p.endpointReady(); result == 0 { - break - } - fmt.Println("Waiting for varlink connection to become active", counter) - time.Sleep(250 * time.Millisecond) - counter++ - if counter > 40 { - Fail("varlink endpoint never became ready") - } - } -} - -func (p *EndpointTestIntegration) endpointReady() int { - session := p.Varlink("GetVersion", "", false) - return session.ExitCode() -} - -func (p *EndpointTestIntegration) StopVarlink() { - var out bytes.Buffer - var pids []int - varlinkSession := p.VarlinkSession - - if !rootless.IsRootless() { - if err := varlinkSession.Kill(); err != nil { - fmt.Fprintf(os.Stderr, "error on varlink stop-kill %q", err) - } - if _, err := varlinkSession.Wait(); err != nil { - fmt.Fprintf(os.Stderr, "error on varlink stop-wait %q", err) - } - - } else { - //p.ResetVarlinkAddress() - parentPid := fmt.Sprintf("%d", p.VarlinkSession.Pid) - pgrep := exec.Command("pgrep", "-P", parentPid) - fmt.Printf("running: pgrep %s\n", parentPid) - pgrep.Stdout = &out - err := pgrep.Run() - if err != nil { - fmt.Fprint(os.Stderr, "unable to find varlink pid") - } - - for _, s := range strings.Split(out.String(), "\n") { - if len(s) == 0 { - continue - } - p, err := strconv.Atoi(s) - if err != nil { - fmt.Fprintf(os.Stderr, "unable to convert %s to int", s) - } - if p != 0 { - pids = append(pids, p) - } - } - - pids = append(pids, p.VarlinkSession.Pid) - for _, pid := range pids { - syscall.Kill(pid, syscall.SIGKILL) - } - } - socket := strings.Split(p.VarlinkEndpoint, ":")[1] - if err := os.Remove(socket); err != nil { - fmt.Println(err) - } -} - -type EndpointSession struct { - *gexec.Session -} - -func getVarlinkOptions(p *EndpointTestIntegration, args []string) []string { - podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s", - p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ") - if os.Getenv("HOOK_OPTION") != "" { - podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) - } - podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) - podmanOptions = append(podmanOptions, args...) - return podmanOptions -} - -func (p *EndpointTestIntegration) Varlink(endpoint, message string, more bool) *EndpointSession { - //call unix:/run/user/1000/podman/io.podman/io.podman.GetContainerStats '{"name": "foobar" }' - var ( - command *exec.Cmd - ) - - args := []string{"call"} - if more { - args = append(args, "-m") - } - args = append(args, []string{fmt.Sprintf("%s/io.podman.%s", p.VarlinkEndpoint, endpoint)}...) - if len(message) > 0 { - args = append(args, message) - } - command = exec.Command(p.VarlinkBinary, args...) - session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) - if err != nil { - Fail(fmt.Sprintf("unable to run varlink command: %s\n%v", strings.Join(args, " "), err)) - } - session.Wait(defaultWaitTimeout) - return &EndpointSession{session} -} - -func (s *EndpointSession) StdErrToString() string { - fields := strings.Fields(string(s.Err.Contents())) - return strings.Join(fields, " ") -} - -func (s *EndpointSession) OutputToString() string { - fields := strings.Fields(string(s.Out.Contents())) - return strings.Join(fields, " ") -} - -func (s *EndpointSession) OutputToBytes() []byte { - out := s.OutputToString() - return []byte(out) -} - -func (s *EndpointSession) OutputToStringMap() map[string]string { - var out map[string]string - json.Unmarshal(s.OutputToBytes(), &out) - return out -} - -func (s *EndpointSession) OutputToMapToInt() map[string]int { - var out map[string]int - json.Unmarshal(s.OutputToBytes(), &out) - return out -} - -func (s *EndpointSession) OutputToMoreResponse() iopodman.MoreResponse { - out := make(map[string]iopodman.MoreResponse) - json.Unmarshal(s.OutputToBytes(), &out) - return out["reply"] -} diff --git a/test/endpoint/endpoint_suite_test.go b/test/endpoint/endpoint_suite_test.go deleted file mode 100644 index 1cd5c2b9d..000000000 --- a/test/endpoint/endpoint_suite_test.go +++ /dev/null @@ -1,72 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestEndpoint(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Endpoint Suite") -} - -var LockTmpDir string - -var _ = SynchronizedBeforeSuite(func() []byte { - // Cache images - cwd, _ := os.Getwd() - INTEGRATION_ROOT = filepath.Join(cwd, "../../") - podman := Setup("/tmp") - podman.ArtifactPath = ARTIFACT_DIR - if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) { - if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil { - fmt.Printf("%q\n", err) - os.Exit(1) - } - } - - // make cache dir - if err := os.MkdirAll(ImageCacheDir, 0777); err != nil { - fmt.Printf("%q\n", err) - os.Exit(1) - } - - podman.StartVarlink() - for _, image := range CACHE_IMAGES { - podman.createArtifact(image) - } - podman.StopVarlink() - // If running localized tests, the cache dir is created and populated. if the - // tests are remote, this is a no-op - populateCache(podman) - - path, err := ioutil.TempDir("", "libpodlock") - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return []byte(path) -}, func(data []byte) { - LockTmpDir = string(data) -}) - -var _ = SynchronizedAfterSuite(func() {}, - func() { - podman := Setup("/tmp") - if err := os.RemoveAll(podman.CrioRoot); err != nil { - fmt.Printf("%q\n", err) - os.Exit(1) - } - if err := os.RemoveAll(podman.ImageCacheDir); err != nil { - fmt.Printf("%q\n", err) - os.Exit(1) - } - }) diff --git a/test/endpoint/exists_test.go b/test/endpoint/exists_test.go deleted file mode 100644 index f7fa8eb44..000000000 --- a/test/endpoint/exists_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "os" - - . "github.com/containers/podman/v2/test/utils" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Podman exists", func() { - var ( - tempdir string - err error - endpointTest *EndpointTestIntegration - ) - - BeforeEach(func() { - tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } - endpointTest = Setup(tempdir) - endpointTest.StartVarlinkWithCache() - }) - - AfterEach(func() { - endpointTest.Cleanup() - //f := CurrentGinkgoTestDescription() - //processTestResult(f) - - }) - - It("image exists in local storage", func() { - result := endpointTest.Varlink("ImageExists", makeNameMessage(ALPINE), false) - Expect(result.ExitCode()).To(BeZero()) - - output := result.OutputToMapToInt() - Expect(output["exists"]).To(BeZero()) - }) - - It("image exists in local storage by shortname", func() { - result := endpointTest.Varlink("ImageExists", makeNameMessage("alpine"), false) - Expect(result.ExitCode()).To(BeZero()) - - output := result.OutputToMapToInt() - Expect(output["exists"]).To(BeZero()) - }) - - It("image does not exist in local storage", func() { - result := endpointTest.Varlink("ImageExists", makeNameMessage("alpineforest"), false) - Expect(result.ExitCode()).To(BeZero()) - - output := result.OutputToMapToInt() - Expect(output["exists"]).To(Equal(1)) - }) - - It("container exists in local storage by name", func() { - _ = endpointTest.startTopContainer("top") - result := endpointTest.Varlink("ContainerExists", makeNameMessage("top"), false) - Expect(result.ExitCode()).To(BeZero()) - output := result.OutputToMapToInt() - Expect(output["exists"]).To(BeZero()) - }) - -}) diff --git a/test/endpoint/pull_test.go b/test/endpoint/pull_test.go deleted file mode 100644 index b3683b7db..000000000 --- a/test/endpoint/pull_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "os" - - . "github.com/containers/podman/v2/test/utils" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Podman pull", func() { - var ( - tempdir string - err error - endpointTest *EndpointTestIntegration - ) - - BeforeEach(func() { - tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } - endpointTest = Setup(tempdir) - endpointTest.StartVarlink() - }) - - AfterEach(func() { - endpointTest.Cleanup() - //f := CurrentGinkgoTestDescription() - //processTestResult(f) - - }) - - It("podman pull", func() { - session := endpointTest.Varlink("PullImage", makeNameMessage(ALPINE), false) - Expect(session.ExitCode()).To(BeZero()) - - result := endpointTest.Varlink("ImageExists", makeNameMessage(ALPINE), false) - Expect(result.ExitCode()).To(BeZero()) - - output := result.OutputToMapToInt() - Expect(output["exists"]).To(BeZero()) - }) -}) diff --git a/test/endpoint/setup.go b/test/endpoint/setup.go deleted file mode 100644 index 6bbc8d2bc..000000000 --- a/test/endpoint/setup.go +++ /dev/null @@ -1,214 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/containers/podman/v2/pkg/rootless" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/storage/pkg/stringid" - "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/sirupsen/logrus" -) - -func Setup(tempDir string) *EndpointTestIntegration { - var ( - endpoint string - ) - cwd, _ := os.Getwd() - INTEGRATION_ROOT = filepath.Join(cwd, "../../") - - podmanBinary := filepath.Join(cwd, "../../bin/podman") - if os.Getenv("PODMAN_BINARY") != "" { - podmanBinary = os.Getenv("PODMAN_BINARY") - } - conmonBinary := filepath.Join("/usr/libexec/podman/conmon") - altConmonBinary := "/usr/bin/conmon" - if _, err := os.Stat(conmonBinary); os.IsNotExist(err) { - conmonBinary = altConmonBinary - } - if os.Getenv("CONMON_BINARY") != "" { - conmonBinary = os.Getenv("CONMON_BINARY") - } - storageOptions := STORAGE_OPTIONS - if os.Getenv("STORAGE_OPTIONS") != "" { - storageOptions = os.Getenv("STORAGE_OPTIONS") - } - cgroupManager := CGROUP_MANAGER - if rootless.IsRootless() { - cgroupManager = "cgroupfs" - } - if os.Getenv("CGROUP_MANAGER") != "" { - cgroupManager = os.Getenv("CGROUP_MANAGER") - } - - ociRuntime := os.Getenv("OCI_RUNTIME") - if ociRuntime == "" { - ociRuntime = "runc" - } - os.Setenv("DISABLE_HC_SYSTEMD", "true") - CNIConfigDir := "/etc/cni/net.d" - - storageFs := STORAGE_FS - if rootless.IsRootless() { - storageFs = ROOTLESS_STORAGE_FS - } - - uuid := stringid.GenerateNonCryptoID() - if !rootless.IsRootless() { - endpoint = fmt.Sprintf("unix:/run/podman/io.podman-%s", uuid) - } else { - runtimeDir := os.Getenv("XDG_RUNTIME_DIR") - socket := fmt.Sprintf("io.podman-%s", uuid) - fqpath := filepath.Join(runtimeDir, socket) - endpoint = fmt.Sprintf("unix:%s", fqpath) - } - - eti := EndpointTestIntegration{ - ArtifactPath: ARTIFACT_DIR, - CNIConfigDir: CNIConfigDir, - CgroupManager: cgroupManager, - ConmonBinary: conmonBinary, - CrioRoot: filepath.Join(tempDir, "crio"), - ImageCacheDir: ImageCacheDir, - ImageCacheFS: storageFs, - OCIRuntime: ociRuntime, - PodmanBinary: podmanBinary, - RunRoot: filepath.Join(tempDir, "crio-run"), - SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"), - StorageOptions: storageOptions, - TmpDir: tempDir, - // Timings: nil, - VarlinkBinary: VarlinkBinary, - VarlinkCommand: nil, - VarlinkEndpoint: endpoint, - VarlinkSession: nil, - } - return &eti -} - -func (p *EndpointTestIntegration) Cleanup() { - // Remove all containers - // TODO Make methods to do all this? - - p.stopAllContainers() - - // TODO need to make stop all pods - - p.StopVarlink() - // Nuke tempdir - if err := os.RemoveAll(p.TmpDir); err != nil { - fmt.Printf("%q\n", err) - } - - // Clean up the registries configuration file ENV variable set in Create - resetRegistriesConfigEnv() -} - -func (p *EndpointTestIntegration) listContainers() []iopodman.Container { - containers := p.Varlink("ListContainers", "", false) - var varlinkContainers map[string][]iopodman.Container - if err := json.Unmarshal(containers.OutputToBytes(), &varlinkContainers); err != nil { - logrus.Error("failed to unmarshal containers") - } - return varlinkContainers["containers"] -} - -func (p *EndpointTestIntegration) stopAllContainers() { - containers := p.listContainers() - for _, container := range containers { - p.stopContainer(container.Id) - } -} - -func (p *EndpointTestIntegration) stopContainer(cid string) { - p.Varlink("StopContainer", fmt.Sprintf("{\"name\":\"%s\", \"timeout\":0}", cid), false) -} - -func resetRegistriesConfigEnv() { - os.Setenv("REGISTRIES_CONFIG_PATH", "") -} - -func (p *EndpointTestIntegration) createArtifact(image string) { - if os.Getenv("NO_TEST_CACHE") != "" { - return - } - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - fmt.Printf("Caching %s at %s...", image, destName) - if _, err := os.Stat(destName); os.IsNotExist(err) { - pull := p.Varlink("PullImage", fmt.Sprintf("{\"name\":\"%s\"}", image), false) - Expect(pull.ExitCode()).To(Equal(0)) - - imageSave := iopodman.ImageSaveOptions{ - // Name:image, - // Output: destName, - // Format: "oci-archive", - } - imageSave.Name = image - imageSave.Output = destName - imageSave.Format = "oci-archive" - foo := make(map[string]iopodman.ImageSaveOptions) - foo["options"] = imageSave - f, _ := json.Marshal(foo) - save := p.Varlink("ImageSave", string(f), false) - result := save.OutputToMoreResponse() - Expect(save.ExitCode()).To(Equal(0)) - Expect(os.Rename(result.Id, destName)).To(BeNil()) - fmt.Printf("\n") - } else { - fmt.Printf(" already exists.\n") - } -} - -func populateCache(p *EndpointTestIntegration) { - p.CrioRoot = p.ImageCacheDir - p.StartVarlink() - for _, image := range CACHE_IMAGES { - p.RestoreArtifactToCache(image) - } - p.StopVarlink() -} - -func (p *EndpointTestIntegration) RestoreArtifactToCache(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - // fmt.Println(destName, p.ImageCacheDir) - load := p.Varlink("LoadImage", fmt.Sprintf("{\"name\": \"%s\", \"inputFile\": \"%s\"}", image, destName), false) - Expect(load.ExitCode()).To(BeZero()) - return nil -} - -func (p *EndpointTestIntegration) startTopContainer(name string) string { - t := true - args := iopodman.Create{ - Args: []string{"docker.io/library/alpine:latest", "top"}, - Tty: &t, - Detach: &t, - } - if len(name) > 0 { - args.Name = &name - } - b, err := json.Marshal(args) - if err != nil { - ginkgo.Fail("failed to marshal data for top container") - } - input := fmt.Sprintf("{\"create\":%s}", string(b)) - top := p.Varlink("CreateContainer", input, false) - if top.ExitCode() != 0 { - ginkgo.Fail("failed to start top container") - } - start := p.Varlink("StartContainer", fmt.Sprintf("{\"name\":\"%s\"}", name), false) - if start.ExitCode() != 0 { - ginkgo.Fail("failed to start top container") - } - return start.OutputToString() -} diff --git a/test/endpoint/version_test.go b/test/endpoint/version_test.go deleted file mode 100644 index b1c8ad867..000000000 --- a/test/endpoint/version_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// +build varlink - -package endpoint - -import ( - "os" - - . "github.com/containers/podman/v2/test/utils" - "github.com/containers/podman/v2/version" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Podman version", func() { - var ( - tempdir string - err error - endpointTest *EndpointTestIntegration - ) - - BeforeEach(func() { - tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } - endpointTest = Setup(tempdir) - endpointTest.StartVarlink() - }) - - AfterEach(func() { - endpointTest.Cleanup() - //f := CurrentGinkgoTestDescription() - //processTestResult(f) - - }) - - It("podman version", func() { - session := endpointTest.Varlink("GetVersion", "", false) - result := session.OutputToStringMap() - Expect(result["version"]).To(Equal(version.Version)) - Expect(session.ExitCode()).To(Equal(0)) - }) -}) diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 98bb0cc57..ee6da30ec 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -59,7 +59,8 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z @test "podman images - history output" { # podman history is persistent: it permanently alters our base image. # Create a dummy image here so we leave our setup as we found it. - run_podman run --name my-container $IMAGE true + # Multiple --name options confirm command-line override (last one wins) + run_podman run --name ignore-me --name my-container $IMAGE true run_podman commit my-container my-test-image run_podman images my-test-image --format '{{ .History }}' @@ -87,7 +88,8 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z } @test "podman images - filter" { - run_podman inspect --format '{{.ID}}' $IMAGE + # Multiple --format options confirm command-line override (last one wins) + run_podman inspect --format '{{.XYZ}}' --format '{{.ID}}' $IMAGE iid=$output run_podman images --noheading --filter=after=$iid diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 71831da10..37695f205 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -449,7 +449,9 @@ json-file | f msg=$(random_string 20) pidfile="${PODMAN_TMPDIR}/$(random_string 20)" - run_podman run --name myctr --log-driver journald --conmon-pidfile $pidfile $IMAGE echo $msg + # Multiple --log-driver options to confirm that last one wins + run_podman run --name myctr --log-driver=none --log-driver journald \ + --conmon-pidfile $pidfile $IMAGE echo $msg journalctl --output cat _PID=$(cat $pidfile) is "$output" "$msg" "check that journalctl output equals the container output" @@ -464,7 +466,9 @@ json-file | f run_podman run --rm $IMAGE date -r $testfile is "$output" "Sun Sep 13 12:26:40 UTC 2020" "podman run with no TZ" - run_podman run --rm --tz=MST7MDT $IMAGE date -r $testfile + # Multiple --tz options; confirm that the last one wins + run_podman run --rm --tz=US/Eastern --tz=Iceland --tz=MST7MDT \ + $IMAGE date -r $testfile is "$output" "Sun Sep 13 06:26:40 MDT 2020" "podman run with --tz=MST7MDT" # --tz=local pays attention to /etc/localtime, not $TZ. We set TZ anyway, @@ -533,8 +537,15 @@ json-file | f } @test "podman run with --net=host and --port prints warning" { - run_podman run -d --rm -p 8080 --net=host $IMAGE ls > /dev/null - is "$output" ".*Port mappings have been discarded as one of the Host, Container, Pod, and None network modes are in use" + rand=$(random_string 10) + + # Please keep the duplicate "--net" options; this tests against #8507, + # a regression in which subsequent --net options did not override earlier. + run_podman run --rm -p 8080 --net=none --net=host $IMAGE echo $rand + is "${lines[0]}" \ + "Port mappings have been discarded as one of the Host, Container, Pod, and None network modes are in use" \ + "Warning is emitted before container output" + is "${lines[1]}" "$rand" "Container runs successfully despite warning" } # vim: filetype=sh diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats index dec2df4d5..1ed2779b2 100644 --- a/test/system/040-ps.bats +++ b/test/system/040-ps.bats @@ -35,4 +35,51 @@ load helpers run_podman rm $cid } +@test "podman ps --filter" { + run_podman run -d --name runner $IMAGE top + cid_runner=$output + + run_podman run -d --name stopped $IMAGE true + cid_stopped=$output + run_podman wait stopped + + run_podman run -d --name failed $IMAGE false + cid_failed=$output + run_podman wait failed + + run_podman create --name created $IMAGE echo hi + cid_created=$output + + run_podman ps --filter name=runner --format '{{.ID}}' + is "$output" "${cid_runner:0:12}" "filter: name=runner" + + # Stopped container should not appear (because we're not using -a) + run_podman ps --filter name=stopped --format '{{.ID}}' + is "$output" "" "filter: name=stopped (without -a)" + + # Again, but with -a + run_podman ps -a --filter name=stopped --format '{{.ID}}' + is "$output" "${cid_stopped:0:12}" "filter: name=stopped (with -a)" + + run_podman ps --filter status=stopped --format '{{.Names}}' --sort names + is "${lines[0]}" "failed" "status=stopped: 1 of 2" + is "${lines[1]}" "stopped" "status=stopped: 2 of 2" + + run_podman ps --filter status=exited --filter exited=0 --format '{{.Names}}' + is "$output" "stopped" "exited=0" + + run_podman ps --filter status=exited --filter exited=1 --format '{{.Names}}' + is "$output" "failed" "exited=1" + + # Multiple statuses allowed; and test sort=created + run_podman ps -a --filter status=exited --filter status=running \ + --format '{{.Names}}' --sort created + is "${lines[0]}" "runner" "status=stopped: 1 of 3" + is "${lines[1]}" "stopped" "status=stopped: 2 of 3" + is "${lines[2]}" "failed" "status=stopped: 3 of 3" + + run_podman stop -t 1 runner + run_podman rm -a +} + # vim: filetype=sh diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 83bcd13eb..59da503a6 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -135,10 +135,13 @@ echo "\$1" printenv | grep MYENV | sort | sed -e 's/^MYENV.=//' EOF - # For overriding with --env-file - cat >$PODMAN_TMPDIR/env-file <<EOF + # For overriding with --env-file; using multiple files confirms that + # the --env-file option is cumulative, not last-one-wins. + cat >$PODMAN_TMPDIR/env-file1 <<EOF MYENV3=$s_env3 http_proxy=http-proxy-in-env-file +EOF + cat >$PODMAN_TMPDIR/env-file2 <<EOF https_proxy=https-proxy-in-env-file EOF @@ -185,7 +188,8 @@ EOF export MYENV2="$s_env2" export MYENV3="env-file-should-override-env-host!" run_podman run --rm \ - --env-file=$PODMAN_TMPDIR/env-file \ + --env-file=$PODMAN_TMPDIR/env-file1 \ + --env-file=$PODMAN_TMPDIR/env-file2 \ ${ENVHOST} \ -e MYENV4="$s_env4" \ build_test @@ -205,7 +209,9 @@ EOF # Proxies - environment should override container, but not env-file http_proxy=http-proxy-from-env ftp_proxy=ftp-proxy-from-env \ - run_podman run --rm --env-file=$PODMAN_TMPDIR/env-file \ + run_podman run --rm \ + --env-file=$PODMAN_TMPDIR/env-file1 \ + --env-file=$PODMAN_TMPDIR/env-file2 \ build_test \ printenv http_proxy https_proxy ftp_proxy is "${lines[0]}" "http-proxy-in-env-file" "env-file overrides env" @@ -222,7 +228,8 @@ EOF is "$output" "$workdir" "pwd command in container" # Determine buildah version, so we can confirm it gets into Labels - run_podman info --format '{{ .Host.BuildahVersion }}' + # Multiple --format options confirm command-line override (last one wins) + run_podman info --format '{{.Ignore}}' --format '{{ .Host.BuildahVersion }}' is "$output" "[1-9][0-9.-]\+" ".Host.BuildahVersion is reasonable" buildah_version=$output diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats index edd7dedc4..c028e16c9 100644 --- a/test/system/075-exec.bats +++ b/test/system/075-exec.bats @@ -91,7 +91,8 @@ load helpers # #6829 : add username to /etc/passwd inside container if --userns=keep-id @test "podman exec - with keep-id" { - run_podman run -d --userns=keep-id $IMAGE sh -c \ + # Multiple --userns options confirm command-line override (last one wins) + run_podman run -d --userns=private --userns=keep-id $IMAGE sh -c \ "echo READY;while [ ! -f /tmp/stop ]; do sleep 1; done" cid="$output" wait_for_ready $cid diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index b0f645c53..51835e4a3 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -286,6 +286,10 @@ EOF is "$output" "nc: bind: Address in use" \ "two containers cannot bind to same port" + # make sure we can ping; failure here might mean that capabilities are wrong + run_podman run --rm --pod mypod $IMAGE ping -c1 127.0.0.1 + run_podman run --rm --pod mypod $IMAGE ping -c1 $hostname + # While the container is still running, run 'podman ps' (no --format) # and confirm that the output includes the published port run_podman ps --filter id=$cid diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 9ab47e60c..10e3f17ed 100644 --- a/vendor/github.com/containers/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -28,7 +28,7 @@ const ( Package = "buildah" // Version for the Package. Bump version in contrib/rpm/buildah.spec // too. - Version = "1.18.0" + Version = "1.19.0-dev" // The value we use to identify what type of information, currently a // serialized Builder structure, we are using as per-container state. // This should only be changed when we make incompatible changes to diff --git a/vendor/github.com/containers/buildah/go.mod b/vendor/github.com/containers/buildah/go.mod index b1f3ad67a..0d795f6b6 100644 --- a/vendor/github.com/containers/buildah/go.mod +++ b/vendor/github.com/containers/buildah/go.mod @@ -5,12 +5,11 @@ go 1.12 require ( github.com/containerd/containerd v1.4.1 // indirect github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 - github.com/containers/common v0.26.3 - github.com/containers/image/v5 v5.8.0 + github.com/containers/common v0.29.0 + github.com/containers/image/v5 v5.8.1 github.com/containers/ocicrypt v1.0.3 - github.com/containers/storage v1.24.0 + github.com/containers/storage v1.24.1 github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker v17.12.0-ce-rc1.0.20201020191947-73dc6a680cdd+incompatible // indirect github.com/docker/go-units v0.4.0 github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316 github.com/fsouza/go-dockerclient v1.6.6 diff --git a/vendor/github.com/containers/buildah/go.sum b/vendor/github.com/containers/buildah/go.sum index 069328c38..e3413bc68 100644 --- a/vendor/github.com/containers/buildah/go.sum +++ b/vendor/github.com/containers/buildah/go.sum @@ -73,20 +73,17 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 h1:rqUVLD8I859xRgUx/WMC3v7QAFqbLKZbs+0kqYboRJc= github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/containers/common v0.26.3 h1:5Kb5fMmJ7/xMiJ+iEbPA+5pQpl/FGxCgJex4nml4Slo= -github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4= -github.com/containers/image/v5 v5.7.0 h1:fiTC8/Xbr+zEP6njGTZtPW/3UD7MC93nC9DbUoWdxkA= -github.com/containers/image/v5 v5.7.0/go.mod h1:8aOy+YaItukxghRORkvhq5ibWttHErzDLy6egrKfKos= -github.com/containers/image/v5 v5.8.0 h1:B3FGHi0bdGXgg698kBIGOlHCXN5n+scJr6/5354GOPU= -github.com/containers/image/v5 v5.8.0/go.mod h1:jKxdRtyIDumVa56hdsZvV+gwx4zB50hRou6pIuCWLkg= +github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ= +github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA= +github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q= +github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c= github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g= -github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY= github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI= -github.com/containers/storage v1.24.0 h1:Fo2LkF7tkMLmo38sTZ/G8wHjcn8JfUFPfyTxM4WwMfk= -github.com/containers/storage v1.24.0/go.mod h1:A4d3BzuZK9b3oLVEsiSRhZLPIx3z7utgiPyXLK/YMhY= +github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc= +github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -232,8 +229,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= -github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= @@ -278,7 +275,6 @@ github.com/moby/sys/mount v0.1.1 h1:mdhBytJ1SMmMat0gtzWWjFX/87K5j6E/7Q5z7rR0cZY= github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74= github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= -github.com/moby/sys/mountinfo v0.3.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/term v0.0.0-20200429084858-129dac9f73f6/go.mod h1:or9wGItza1sRcM4Wd3dIv8DsFHYQuFsMHEdxUIlUxms= diff --git a/vendor/github.com/containers/buildah/image.go b/vendor/github.com/containers/buildah/image.go index 154bc503f..7c55020ab 100644 --- a/vendor/github.com/containers/buildah/image.go +++ b/vendor/github.com/containers/buildah/image.go @@ -321,10 +321,7 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System } // If we're not re-exporting the data, and we're reusing layers individually, reuse // the blobsum and diff IDs. - if !i.exporting && !i.squash && layerID != i.layerID { - if layer.UncompressedDigest == "" { - return nil, errors.Errorf("unable to look up size of layer %q", layerID) - } + if !i.exporting && !i.squash && layerID != i.layerID && layer.UncompressedDigest != "" { layerBlobSum := layer.UncompressedDigest layerBlobSize := layer.UncompressedSize diffID := layer.UncompressedDigest diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go index a97a403b3..1ec21e786 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/build.go +++ b/vendor/github.com/containers/buildah/imagebuildah/build.go @@ -185,6 +185,8 @@ type BuildOptions struct { Jobs *int // LogRusage logs resource usage for each step. LogRusage bool + // Excludes is a list of excludes to be used instead of the .dockerignore file. + Excludes []string } // BuildDockerfiles parses a set of one or more Dockerfiles (which may be diff --git a/vendor/github.com/containers/buildah/imagebuildah/executor.go b/vendor/github.com/containers/buildah/imagebuildah/executor.go index 8c96b4e67..3c41ec1d2 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/executor.go @@ -130,9 +130,12 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod return nil, errors.Wrapf(err, "failed to get container config") } - excludes, err := imagebuilder.ParseDockerignore(options.ContextDirectory) - if err != nil { - return nil, err + excludes := options.Excludes + if len(excludes) == 0 { + excludes, err = imagebuilder.ParseDockerignore(options.ContextDirectory) + if err != nil { + return nil, err + } } capabilities, err := defaultContainerConfig.Capabilities("", options.AddCapabilities, options.DropCapabilities) if err != nil { diff --git a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go index 6c058e226..191645b89 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go @@ -368,6 +368,7 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error { Stderr: s.executor.err, Quiet: s.executor.quiet, NamespaceOptions: s.executor.namespaceOptions, + Terminal: buildah.WithoutTerminal, } if config.NetworkDisabled { options.ConfigureNetwork = buildah.NetworkDisabled @@ -1144,7 +1145,11 @@ func (s *StageExecutor) intermediateImageExists(ctx context.Context, currNode *p // lines in the Dockerfile up till the point we are at in the build. manifestType, history, diffIDs, err := s.executor.getImageTypeAndHistoryAndDiffIDs(ctx, image.ID) if err != nil { - return "", errors.Wrapf(err, "error getting history of %q", image.ID) + // It's possible that this image is for another architecture, which results + // in a custom-crafted error message that we'd have to use substring matching + // to recognize. Instead, ignore the image. + logrus.Debugf("error getting history of %q (%v), ignoring it", image.ID, err) + continue } // If this candidate isn't of the type that we're building, then it may have lost // some format-specific information that a building-without-cache run wouldn't lose. diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md index 00381e16a..119315d1f 100644 --- a/vendor/github.com/containers/buildah/install.md +++ b/vendor/github.com/containers/buildah/install.md @@ -59,35 +59,31 @@ sudo dnf -y install buildah #### [Debian](https://debian.org) -The buildah package is [being worked on](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928083) -for inclusion in the default Debian repos. - -Alternatively, the [Kubic project](https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable) -provides packages for Debian 10, testing and unstable. +The buildah package is available in +the [Bullseye (testing) branch](https://packages.debian.org/bullseye/buildah), which +will be the next stable release (Debian 11) as well as Debian Unstable/Sid. ```bash -# Debian Unstable/Sid -echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list -wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_Unstable/Release.key -O Release.key +# Debian Testing/Bullseye or Unstable/Sid +sudo apt-get update +sudo apt-get -y install buildah +``` -# Debian Testing -echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list -wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_Testing/Release.key -O Release.key +The [Kubic project](https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable) +provides packages for Debian 10. The Kubic packages for Debian Testing/Bullseye and Debian Unstable/Sid +have been discontinued to avoid +[conflicts](https://github.com/containers/buildah/issues/2797) with the official packages. -# Debian 10 -echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list -wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Debian_10/Release.key -O Release.key +Caution: If you upgrade from Debian 10 to Testing/Bullseye or +Unstable/Sid you would likely end up downgrading Buildah because the version in +OBS is more frequently updated than the one in Debian's official repositories, +due to how Debian works. -sudo apt-key add - < Release.key -sudo apt-get update -qq -sudo apt-get -qq -y install buildah -``` - -### [Fedora](https://www.fedoraproject.org), [CentOS](https://www.centos.org) +### [Fedora](https://www.fedoraproject.org) ```bash -sudo yum -y install buildah +sudo dnf -y install buildah ``` ### [Fedora SilverBlue](https://silverblue.fedoraproject.org) @@ -127,19 +123,25 @@ sudo subscription-manager repos --enable=rhel-7-server-extras-rpms sudo yum -y install buildah ``` -#### [Raspbian](https://raspbian.org) +#### [Raspberry Pi OS armhf (ex Raspbian)](https://www.raspberrypi.org/downloads/raspberry-pi-os/) The Kubic project provides packages for Raspbian 10. ```bash # Raspbian 10 -echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list -wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/Raspbian_10/Release.key -O Release.key -sudo apt-key add - < Release.key +echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list +curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/Release.key | sudo apt-key add - sudo apt-get update -qq sudo apt-get -qq -y install buildah ``` +#### [Raspberry Pi OS arm64 (beta)](https://downloads.raspberrypi.org/raspios_arm64/images/) + +Raspberry Pi OS use the standard Debian's repositories, +so it is fully compatible with Debian's arm64 repository. +You can simply follow the [steps for Debian](#debian) to install podman. + + ### [RHEL8 Beta](https://www.redhat.com/en/blog/powering-its-future-while-preserving-present-introducing-red-hat-enterprise-linux-8-beta?intcmp=701f2000001Cz6OAAS) ```bash @@ -149,7 +151,16 @@ sudo yum module install -y buildah ### [Ubuntu](https://www.ubuntu.com) -The Kubic project provides packages for Ubuntu 18.04, 19.04 and 19.10 (it should also work with direct derivatives like Pop!\_OS). +The buildah package is available in the official repositories for Ubuntu 20.10 +and newer. + +```bash +# Ubuntu 20.10 and newer +sudo apt-get -y update +sudo apt-get -y install buildah +``` + +The [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah) provides packages for some older but supported Ubuntu versions (it should also work with direct derivatives like Pop!\_OS). ```bash . /etc/os-release diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go index 62a328de0..123548d97 100644 --- a/vendor/github.com/containers/buildah/pkg/cli/common.go +++ b/vendor/github.com/containers/buildah/pkg/cli/common.go @@ -59,6 +59,7 @@ type BudResults struct { Creds string DisableCompression bool DisableContentTrust bool + IgnoreFile string File []string Format string Iidfile string @@ -185,6 +186,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default") fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP") + fs.StringVar(&flags.IgnoreFile, "ignorefile", "", "path to an alternate .dockerignore file") fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile") fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.") fs.StringVar(&flags.Iidfile, "iidfile", "", "`file` to write the image ID to") @@ -231,6 +233,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions { flagCompletion["creds"] = commonComp.AutocompleteNone flagCompletion["file"] = commonComp.AutocompleteDefault flagCompletion["format"] = commonComp.AutocompleteNone + flagCompletion["ignorefile"] = commonComp.AutocompleteDefault flagCompletion["iidfile"] = commonComp.AutocompleteDefault flagCompletion["jobs"] = commonComp.AutocompleteNone flagCompletion["label"] = commonComp.AutocompleteNone diff --git a/vendor/github.com/containers/buildah/pkg/umask/umask_unsupported.go b/vendor/github.com/containers/buildah/pkg/umask/umask_unsupported.go deleted file mode 100644 index 20913a718..000000000 --- a/vendor/github.com/containers/buildah/pkg/umask/umask_unsupported.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !linux,!darwin - -package umask - -func CheckUmask() {} - -func SetUmask(int) int { return 0 } diff --git a/vendor/github.com/containers/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go index d907941ed..d20d39423 100644 --- a/vendor/github.com/containers/buildah/run_linux.go +++ b/vendor/github.com/containers/buildah/run_linux.go @@ -25,10 +25,10 @@ import ( "github.com/containers/buildah/chroot" "github.com/containers/buildah/copier" "github.com/containers/buildah/pkg/overlay" - "github.com/containers/buildah/pkg/secrets" "github.com/containers/buildah/util" "github.com/containers/common/pkg/capabilities" "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/subscriptions" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/reexec" @@ -216,16 +216,28 @@ func (b *Builder) Run(command []string, options RunOptions) error { } // Empty file, so no need to recreate if it exists if _, ok := bindFiles["/run/.containerenv"]; !ok { - // Empty string for now, but we may consider populating this later containerenvPath := filepath.Join(path, "/run/.containerenv") if err = os.MkdirAll(filepath.Dir(containerenvPath), 0755); err != nil { return err } - emptyFile, err := os.Create(containerenvPath) - if err != nil { + + rootless := 0 + if unshare.IsRootless() { + rootless = 1 + } + // Populate the .containerenv with container information + containerenv := fmt.Sprintf(`\ +engine="buildah-%s" +name=%q +id=%q +image=%q +imageid=%q +rootless=%d +`, Version, b.Container, b.ContainerID, b.FromImage, b.FromImageID, rootless) + + if err = ioutils.AtomicWriteFile(containerenvPath, []byte(containerenv), 0755); err != nil { return err } - emptyFile.Close() if err := label.Relabel(containerenvPath, b.MountLabel, false); err != nil { return err } @@ -477,15 +489,15 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st return errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID) } - // Figure out which UID and GID to tell the secrets package to use + // Figure out which UID and GID to tell the subscritions package to use // for files that it creates. rootUID, rootGID, err := util.GetHostRootIDs(spec) if err != nil { return err } - // Get the list of secrets mounts. - secretMounts := secrets.SecretMountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false) + // Get the list of subscriptionss mounts. + secretMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false) // Add temporary copies of the contents of volume locations at the // volume locations, unless we already have something there. diff --git a/vendor/github.com/containers/common/pkg/subscriptions/mounts.conf b/vendor/github.com/containers/common/pkg/subscriptions/mounts.conf new file mode 100644 index 000000000..b7cde9d8a --- /dev/null +++ b/vendor/github.com/containers/common/pkg/subscriptions/mounts.conf @@ -0,0 +1 @@ +/usr/share/rhel/secrets:/run/secrets diff --git a/vendor/github.com/containers/buildah/pkg/secrets/secrets.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index 32f888fa8..6aa66b0c8 100644 --- a/vendor/github.com/containers/buildah/pkg/secrets/secrets.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -1,4 +1,4 @@ -package secrets +package subscriptions import ( "bufio" @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/containers/buildah/pkg/umask" + "github.com/containers/common/pkg/umask" "github.com/containers/storage/pkg/idtools" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" @@ -27,16 +27,16 @@ var ( UserOverrideMountsFile = filepath.Join(os.Getenv("HOME"), ".config/containers/mounts.conf") ) -// secretData stores the name of the file and the content read from it -type secretData struct { +// subscriptionData stores the name of the file and the content read from it +type subscriptionData struct { name string data []byte mode os.FileMode dirMode os.FileMode } -// saveTo saves secret data to given directory -func (s secretData) saveTo(dir string) error { +// saveTo saves subscription data to given directory +func (s subscriptionData) saveTo(dir string) error { path := filepath.Join(dir, s.name) if err := os.MkdirAll(filepath.Dir(path), s.dirMode); err != nil { return err @@ -44,10 +44,10 @@ func (s secretData) saveTo(dir string) error { return ioutil.WriteFile(path, s.data, s.mode) } -func readAll(root, prefix string, parentMode os.FileMode) ([]secretData, error) { +func readAll(root, prefix string, parentMode os.FileMode) ([]subscriptionData, error) { path := filepath.Join(root, prefix) - data := []secretData{} + data := []subscriptionData{} files, err := ioutil.ReadDir(path) if err != nil { @@ -74,7 +74,7 @@ func readAll(root, prefix string, parentMode os.FileMode) ([]secretData, error) return data, nil } -func readFileOrDir(root, name string, parentMode os.FileMode) ([]secretData, error) { +func readFileOrDir(root, name string, parentMode os.FileMode) ([]subscriptionData, error) { path := filepath.Join(root, name) s, err := os.Stat(path) @@ -93,7 +93,7 @@ func readFileOrDir(root, name string, parentMode os.FileMode) ([]secretData, err if err != nil { return nil, err } - return []secretData{{ + return []subscriptionData{{ name: name, data: bytes, mode: s.Mode(), @@ -101,13 +101,13 @@ func readFileOrDir(root, name string, parentMode os.FileMode) ([]secretData, err }}, nil } -func getHostSecretData(hostDir string, mode os.FileMode) ([]secretData, error) { - var allSecrets []secretData - hostSecrets, err := readAll(hostDir, "", mode) +func getHostSubscriptionData(hostDir string, mode os.FileMode) ([]subscriptionData, error) { + var allSubscriptions []subscriptionData + hostSubscriptions, err := readAll(hostDir, "", mode) if err != nil { - return nil, errors.Wrapf(err, "failed to read secrets from %q", hostDir) + return nil, errors.Wrapf(err, "failed to read subscriptions from %q", hostDir) } - return append(allSecrets, hostSecrets...), nil + return append(allSubscriptions, hostSubscriptions...), nil } func getMounts(filePath string) []string { @@ -136,7 +136,7 @@ func getMounts(filePath string) []string { } // getHostAndCtrDir separates the host:container paths -func getMountsMap(path string) (string, string, error) { +func getMountsMap(path string) (string, string, error) { //nolint arr := strings.SplitN(path, ":", 2) switch len(arr) { case 1: @@ -147,27 +147,21 @@ func getMountsMap(path string) (string, string, error) { return "", "", errors.Errorf("unable to get host and container dir from path: %s", path) } -// SecretMounts copies, adds, and mounts the secrets to the container root filesystem -// Deprecated, Please use SecretMountWithUIDGID -func SecretMounts(mountLabel, containerWorkingDir, mountFile string, rootless, disableFips bool) []rspec.Mount { - return SecretMountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, containerWorkingDir, 0, 0, rootless, disableFips) -} - -// SecretMountsWithUIDGID copies, adds, and mounts the secrets to the container root filesystem +// MountsWithUIDGID copies, adds, and mounts the subscriptions to the container root filesystem // mountLabel: MAC/SELinux label for container content -// containerWorkingDir: Private data for storing secrets on the host mounted in container. +// containerWorkingDir: Private data for storing subscriptions on the host mounted in container. // mountFile: Additional mount points required for the container. // mountPoint: Container image mountpoint -// uid: to assign to content created for secrets -// gid: to assign to content created for secrets +// uid: to assign to content created for subscriptions +// gid: to assign to content created for subscriptions // rootless: indicates whether container is running in rootless mode // disableFips: indicates whether system should ignore fips mode -func SecretMountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint string, uid, gid int, rootless, disableFips bool) []rspec.Mount { +func MountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint string, uid, gid int, rootless, disableFips bool) []rspec.Mount { var ( - secretMounts []rspec.Mount - mountFiles []string + subscriptionMounts []rspec.Mount + mountFiles []string ) - // Add secrets from paths given in the mounts.conf files + // Add subscriptions from paths given in the mounts.conf files // mountFile will have a value if the hidden --default-mounts-file flag is set // Note for testing purposes only if mountFile == "" { @@ -180,31 +174,32 @@ func SecretMountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoi } for _, file := range mountFiles { if _, err := os.Stat(file); err == nil { - mounts, err := addSecretsFromMountsFile(file, mountLabel, containerWorkingDir, uid, gid) + mounts, err := addSubscriptionsFromMountsFile(file, mountLabel, containerWorkingDir, uid, gid) if err != nil { - logrus.Warnf("error mounting secrets, skipping entry in %s: %v", file, err) + logrus.Warnf("error mounting subscriptions, skipping entry in %s: %v", file, err) } - secretMounts = mounts + subscriptionMounts = mounts break } } - // Only add FIPS secret mount if disableFips=false + // Only add FIPS subscription mount if disableFips=false if disableFips { - return secretMounts + return subscriptionMounts } - // Add FIPS mode secret if /etc/system-fips exists on the host + // Add FIPS mode subscription if /etc/system-fips exists on the host _, err := os.Stat("/etc/system-fips") - if err == nil { - if err := addFIPSModeSecret(&secretMounts, containerWorkingDir, mountPoint, mountLabel, uid, gid); err != nil { - logrus.Errorf("error adding FIPS mode secret to container: %v", err) + switch { + case err == nil: + if err := addFIPSModeSubscription(&subscriptionMounts, containerWorkingDir, mountPoint, mountLabel, uid, gid); err != nil { + logrus.Errorf("error adding FIPS mode subscription to container: %v", err) } - } else if os.IsNotExist(err) { - logrus.Debug("/etc/system-fips does not exist on host, not mounting FIPS mode secret") - } else { - logrus.Errorf("stat /etc/system-fips failed for FIPS mode secret: %v", err) + case os.IsNotExist(err): + logrus.Debug("/etc/system-fips does not exist on host, not mounting FIPS mode subscription") + default: + logrus.Errorf("stat /etc/system-fips failed for FIPS mode subscription: %v", err) } - return secretMounts + return subscriptionMounts } func rchown(chowndir string, uid, gid int) error { @@ -213,9 +208,9 @@ func rchown(chowndir string, uid, gid int) error { }) } -// addSecretsFromMountsFile copies the contents of host directory to container directory +// addSubscriptionsFromMountsFile copies the contents of host directory to container directory // and returns a list of mounts -func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir string, uid, gid int) ([]rspec.Mount, error) { +func addSubscriptionsFromMountsFile(filePath, mountLabel, containerWorkingDir string, uid, gid int) ([]rspec.Mount, error) { var mounts []rspec.Mount defaultMountsPaths := getMounts(filePath) for _, path := range defaultMountsPaths { @@ -235,7 +230,7 @@ func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir string, ctrDirOrFileOnHost := filepath.Join(containerWorkingDir, ctrDirOrFile) - // In the event of a restart, don't want to copy secrets over again as they already would exist in ctrDirOrFileOnHost + // In the event of a restart, don't want to copy subscriptions over again as they already would exist in ctrDirOrFileOnHost _, err = os.Stat(ctrDirOrFileOnHost) if os.IsNotExist(err) { @@ -245,17 +240,17 @@ func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir string, } // Don't let the umask have any influence on the file and directory creation - oldUmask := umask.SetUmask(0) - defer umask.SetUmask(oldUmask) + oldUmask := umask.Set(0) + defer umask.Set(oldUmask) switch mode := fileInfo.Mode(); { case mode.IsDir(): if err = os.MkdirAll(ctrDirOrFileOnHost, mode.Perm()); err != nil { return nil, errors.Wrapf(err, "making container directory %q failed", ctrDirOrFileOnHost) } - data, err := getHostSecretData(hostDirOrFile, mode.Perm()) + data, err := getHostSubscriptionData(hostDirOrFile, mode.Perm()) if err != nil { - return nil, errors.Wrapf(err, "getting host secret data failed") + return nil, errors.Wrapf(err, "getting host subscription data failed") } for _, s := range data { if err := s.saveTo(ctrDirOrFileOnHost); err != nil { @@ -305,15 +300,15 @@ func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir string, return mounts, nil } -// addFIPSModeSecret creates /run/secrets/system-fips in the container +// addFIPSModeSubscription creates /run/secrets/system-fips in the container // root filesystem if /etc/system-fips exists on hosts. // This enables the container to be FIPS compliant and run openssl in // FIPS mode as the host is also in FIPS mode. -func addFIPSModeSecret(mounts *[]rspec.Mount, containerWorkingDir, mountPoint, mountLabel string, uid, gid int) error { - secretsDir := "/run/secrets" - ctrDirOnHost := filepath.Join(containerWorkingDir, secretsDir) +func addFIPSModeSubscription(mounts *[]rspec.Mount, containerWorkingDir, mountPoint, mountLabel string, uid, gid int) error { + subscriptionsDir := "/run/secrets" + ctrDirOnHost := filepath.Join(containerWorkingDir, subscriptionsDir) if _, err := os.Stat(ctrDirOnHost); os.IsNotExist(err) { - if err = idtools.MkdirAllAs(ctrDirOnHost, 0755, uid, gid); err != nil { + if err = idtools.MkdirAllAs(ctrDirOnHost, 0755, uid, gid); err != nil { //nolint return errors.Wrapf(err, "making container directory %q on host failed", ctrDirOnHost) } if err = label.Relabel(ctrDirOnHost, mountLabel, false); err != nil { @@ -330,10 +325,10 @@ func addFIPSModeSecret(mounts *[]rspec.Mount, containerWorkingDir, mountPoint, m defer file.Close() } - if !mountExists(*mounts, secretsDir) { + if !mountExists(*mounts, subscriptionsDir) { m := rspec.Mount{ Source: ctrDirOnHost, - Destination: secretsDir, + Destination: subscriptionsDir, Type: "bind", Options: []string{"bind", "rprivate"}, } diff --git a/vendor/github.com/containers/buildah/pkg/umask/umask_unix.go b/vendor/github.com/containers/common/pkg/umask/umask_unix.go index 02e10945b..bb589f7ac 100644 --- a/vendor/github.com/containers/buildah/pkg/umask/umask_unix.go +++ b/vendor/github.com/containers/common/pkg/umask/umask_unix.go @@ -8,13 +8,13 @@ import ( "github.com/sirupsen/logrus" ) -func CheckUmask() { - oldUmask := syscall.Umask(0022) +func Check() { + oldUmask := syscall.Umask(0022) //nolint if (oldUmask & ^0022) != 0 { logrus.Debugf("umask value too restrictive. Forcing it to 022") } } -func SetUmask(value int) int { +func Set(value int) int { return syscall.Umask(value) } diff --git a/vendor/github.com/containers/common/pkg/umask/umask_unsupported.go b/vendor/github.com/containers/common/pkg/umask/umask_unsupported.go new file mode 100644 index 000000000..9041d5f20 --- /dev/null +++ b/vendor/github.com/containers/common/pkg/umask/umask_unsupported.go @@ -0,0 +1,7 @@ +// +build !linux,!darwin + +package umask + +func Check() {} + +func Set(int) int { return 0 } diff --git a/vendor/github.com/varlink/go/LICENSE b/vendor/github.com/varlink/go/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/vendor/github.com/varlink/go/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go b/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go deleted file mode 100644 index 98a983c5e..000000000 --- a/vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go +++ /dev/null @@ -1,445 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "go/format" - "io/ioutil" - "os" - "path" - "strings" - - "github.com/varlink/go/varlink/idl" -) - -func writeType(b *bytes.Buffer, t *idl.Type, json bool, ident int) { - switch t.Kind { - case idl.TypeBool: - b.WriteString("bool") - - case idl.TypeInt: - b.WriteString("int64") - - case idl.TypeFloat: - b.WriteString("float64") - - case idl.TypeString, idl.TypeEnum: - b.WriteString("string") - - case idl.TypeObject: - b.WriteString("json.RawMessage") - - case idl.TypeArray: - b.WriteString("[]") - writeType(b, t.ElementType, json, ident) - - case idl.TypeMap: - b.WriteString("map[string]") - writeType(b, t.ElementType, json, ident) - - case idl.TypeMaybe: - b.WriteString("*") - writeType(b, t.ElementType, json, ident) - - case idl.TypeAlias: - b.WriteString(t.Alias) - - case idl.TypeStruct: - if len(t.Fields) == 0 { - b.WriteString("struct{}") - } else { - b.WriteString("struct {\n") - for _, field := range t.Fields { - for i := 0; i < ident+1; i++ { - b.WriteString("\t") - } - - b.WriteString(strings.Title(field.Name) + " ") - writeType(b, field.Type, json, ident+1) - if json { - b.WriteString(" `json:\"" + field.Name) - if field.Type.Kind == idl.TypeMaybe { - b.WriteString(",omitempty") - } - b.WriteString("\"`") - } - b.WriteString("\n") - } - for i := 0; i < ident; i++ { - b.WriteString("\t") - } - b.WriteString("}") - } - } -} - -func writeDocString(b *bytes.Buffer, s string) { - if s == "" { - return - } - - // Quote multi-line docstrings - b.WriteString("// " + strings.Replace(s, "\n", "\n// ", -1)) - b.WriteString("\n") -} - -func generateTemplate(description string) (string, []byte, error) { - description = strings.TrimRight(description, "\n") - - midl, err := idl.New(description) - if err != nil { - return "", nil, err - } - - pkgname := strings.Replace(midl.Name, ".", "", -1) - - var b bytes.Buffer - b.WriteString("// Generated with github.com/varlink/go/cmd/varlink-go-interface-generator\n\n") - - writeDocString(&b, midl.Doc) - b.WriteString("package " + pkgname + "\n\n") - b.WriteString("@IMPORTS@\n\n") - - b.WriteString("// Generated type declarations\n\n") - - for _, a := range midl.Aliases { - writeDocString(&b, a.Doc) - b.WriteString("type " + a.Name + " ") - writeType(&b, a.Type, true, 0) - b.WriteString("\n\n") - } - - for _, a := range midl.Errors { - writeDocString(&b, a.Doc) - b.WriteString("type " + a.Name + " ") - writeType(&b, a.Type, true, 0) - b.WriteString("\nfunc (e " + a.Name + ") Error() string {\n") - b.WriteString("\treturn \"" + midl.Name + "." + a.Name + "\"\n") - b.WriteString("}\n\n") - } - - b.WriteString("func Dispatch_Error(err error) error {\n") - b.WriteString("\tif e, ok := err.(*varlink.Error); ok {\n") - b.WriteString("\t\tswitch e.Name {\n") - for _, a := range midl.Errors { - b.WriteString("\t\tcase \"" + midl.Name + "." + a.Name + "\":\n") - b.WriteString("\t\t\terrorRawParameters := e.Parameters.(*json.RawMessage)\n") - b.WriteString("\t\t\tif errorRawParameters == nil {\n") - b.WriteString("\t\t\t\treturn e\n") - b.WriteString("\t\t\t}\n") - b.WriteString("\t\t\tvar param " + a.Name + "\n") - b.WriteString("\t\t\terr := json.Unmarshal(*errorRawParameters, ¶m)\n") - b.WriteString("\t\t\tif err != nil {\n") - b.WriteString("\t\t\t\treturn e\n") - b.WriteString("\t\t\t}\n") - b.WriteString("\t\t\treturn ¶m\n") - } - b.WriteString("\t\t}\n") - b.WriteString("\t}\n") - b.WriteString("\treturn err\n") - b.WriteString("}\n\n") - - b.WriteString("// Generated client method calls\n\n") - - for _, m := range midl.Methods { - writeDocString(&b, m.Doc) - b.WriteString("type " + m.Name + "_methods struct{}\n") - b.WriteString("func " + m.Name + "() " + m.Name + "_methods { return " + m.Name + "_methods{} }\n\n") - - b.WriteString("func (m " + m.Name + "_methods) Call(c *varlink.Connection") - for _, field := range m.In.Fields { - b.WriteString(", " + field.Name + "_in_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") (") - for _, field := range m.Out.Fields { - b.WriteString(field.Name + "_out_ ") - writeType(&b, field.Type, false, 1) - b.WriteString(", ") - } - b.WriteString("err_ error) {\n") - b.WriteString("receive, err_ := m.Send(c, 0") - for _, field := range m.In.Fields { - b.WriteString(", " + field.Name + "_in_ ") - } - b.WriteString(")\n") - b.WriteString("if err_ != nil {\n" + - "\treturn\n" + - "}\n") - b.WriteString("\t") - for _, field := range m.Out.Fields { - b.WriteString(field.Name + "_out_ ") - b.WriteString(", ") - } - b.WriteString("_, err_ = receive()\n") - b.WriteString("\treturn\n" + - "}\n\n") - - b.WriteString("func (m " + m.Name + "_methods) Send(c *varlink.Connection, flags uint64") - for _, field := range m.In.Fields { - b.WriteString(", " + field.Name + "_in_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") (func() (") - for _, field := range m.Out.Fields { - writeType(&b, field.Type, false, 1) - b.WriteString(", ") - } - b.WriteString("uint64, error), error) {\n") - if len(m.In.Fields) > 0 { - b.WriteString("\tvar in ") - writeType(&b, m.In, true, 1) - b.WriteString("\n") - for _, field := range m.In.Fields { - switch field.Type.Kind { - case idl.TypeStruct, idl.TypeArray, idl.TypeMap: - b.WriteString("\tin." + strings.Title(field.Name) + " = ") - writeType(&b, field.Type, true, 1) - b.WriteString("(" + field.Name + "_in_)\n") - - default: - b.WriteString("\tin." + strings.Title(field.Name) + " = " + field.Name + "_in_\n") - } - } - b.WriteString("\treceive, err := c.Send(\"" + midl.Name + "." + m.Name + "\", in, flags)\n") - } else { - b.WriteString("\treceive, err := c.Send(\"" + midl.Name + "." + m.Name + "\", nil, flags)\n") - } - b.WriteString("\tif err != nil {\n" + - "\t\treturn nil, err\n" + - "\t}\n") - b.WriteString("\treturn func() (") - for _, field := range m.Out.Fields { - b.WriteString(field.Name + "_out_ ") - writeType(&b, field.Type, false, 3) - b.WriteString(", ") - } - b.WriteString("flags uint64, err error) {\n") - if len(m.Out.Fields) > 0 { - b.WriteString("\t\tvar out ") - writeType(&b, m.Out, true, 2) - b.WriteString("\n") - b.WriteString("\t\tflags, err = receive(&out)\n") - } else { - b.WriteString("\t\tflags, err = receive(nil)\n") - } - b.WriteString("\t\tif err != nil {\n" + - "\t\t\terr = Dispatch_Error(err)\n" + - "\t\t\treturn\n" + - "\t\t}\n") - for _, field := range m.Out.Fields { - b.WriteString("\t\t" + field.Name + "_out_ = ") - switch field.Type.Kind { - case idl.TypeStruct, idl.TypeArray, idl.TypeMap: - writeType(&b, field.Type, false, 2) - b.WriteString("(out." + strings.Title(field.Name) + ")\n") - - default: - b.WriteString("out." + strings.Title(field.Name) + "\n") - } - } - b.WriteString("\t\treturn\n" + - "\t}, nil\n") - b.WriteString("}\n\n") - } - - b.WriteString("// Generated service interface with all methods\n\n") - - b.WriteString("type " + pkgname + "Interface interface {\n") - for _, m := range midl.Methods { - b.WriteString("\t" + m.Name + "(c VarlinkCall") - for _, field := range m.In.Fields { - b.WriteString(", " + field.Name + "_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") error\n") - } - b.WriteString("}\n\n") - - b.WriteString("// Generated service object with all methods\n\n") - - b.WriteString("type VarlinkCall struct{ varlink.Call }\n\n") - - b.WriteString("// Generated reply methods for all varlink errors\n\n") - - for _, e := range midl.Errors { - writeDocString(&b, e.Doc) - b.WriteString("func (c *VarlinkCall) Reply" + e.Name + "(") - for i, field := range e.Type.Fields { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(field.Name + "_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") error {\n") - b.WriteString("\tvar out " + e.Name + "\n") - if len(e.Type.Fields) > 0 { - for _, field := range e.Type.Fields { - switch field.Type.Kind { - case idl.TypeStruct, idl.TypeArray, idl.TypeMap: - b.WriteString("\tout." + strings.Title(field.Name) + " = ") - writeType(&b, field.Type, true, 1) - b.WriteString("(" + field.Name + "_)\n") - - default: - b.WriteString("\tout." + strings.Title(field.Name) + " = " + field.Name + "_\n") - } - } - } - b.WriteString("\treturn c.ReplyError(\"" + midl.Name + "." + e.Name + "\", &out)\n") - b.WriteString("}\n\n") - } - - b.WriteString("// Generated reply methods for all varlink methods\n\n") - - for _, m := range midl.Methods { - b.WriteString("func (c *VarlinkCall) Reply" + m.Name + "(") - for i, field := range m.Out.Fields { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(field.Name + "_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") error {\n") - if len(m.Out.Fields) > 0 { - b.WriteString("\tvar out ") - writeType(&b, m.Out, true, 1) - b.WriteString("\n") - for _, field := range m.Out.Fields { - switch field.Type.Kind { - case idl.TypeStruct, idl.TypeArray, idl.TypeMap: - b.WriteString("\tout." + strings.Title(field.Name) + " = ") - writeType(&b, field.Type, true, 1) - b.WriteString("(" + field.Name + "_)\n") - - default: - b.WriteString("\tout." + strings.Title(field.Name) + " = " + field.Name + "_\n") - } - } - b.WriteString("\treturn c.Reply(&out)\n") - } else { - b.WriteString("\treturn c.Reply(nil)\n") - } - b.WriteString("}\n\n") - } - - b.WriteString("// Generated dummy implementations for all varlink methods\n\n") - - for _, m := range midl.Methods { - writeDocString(&b, m.Doc) - b.WriteString("func (s *VarlinkInterface) " + m.Name + "(c VarlinkCall") - for _, field := range m.In.Fields { - b.WriteString(", " + field.Name + "_ ") - writeType(&b, field.Type, false, 1) - } - b.WriteString(") error {\n" + - "\treturn c.ReplyMethodNotImplemented(\"" + midl.Name + "." + m.Name + "\")\n" + - "}\n\n") - } - - b.WriteString("// Generated method call dispatcher\n\n") - - b.WriteString("func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error {\n" + - "\tswitch methodname {\n") - for _, m := range midl.Methods { - b.WriteString("\tcase \"" + m.Name + "\":\n") - if len(m.In.Fields) > 0 { - b.WriteString("\t\tvar in ") - writeType(&b, m.In, true, 2) - b.WriteString("\n") - b.WriteString("\t\terr := call.GetParameters(&in)\n" + - "\t\tif err != nil {\n" + - "\t\t\treturn call.ReplyInvalidParameter(\"parameters\")\n" + - "\t\t}\n") - b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call}") - if len(m.In.Fields) > 0 { - for _, field := range m.In.Fields { - switch field.Type.Kind { - case idl.TypeStruct, idl.TypeArray, idl.TypeMap: - b.WriteString(", ") - writeType(&b, field.Type, false, 2) - b.WriteString("(in." + strings.Title(field.Name) + ")") - - default: - b.WriteString(", in." + strings.Title(field.Name)) - } - } - } - b.WriteString(")\n") - } else { - b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call})\n") - } - b.WriteString("\n") - } - b.WriteString("\tdefault:\n" + - "\t\treturn call.ReplyMethodNotFound(methodname)\n" + - "\t}\n" + - "}\n\n") - - b.WriteString("// Generated varlink interface name\n\n") - - b.WriteString("func (s *VarlinkInterface) VarlinkGetName() string {\n" + - "\treturn `" + midl.Name + "`\n" + "}\n\n") - - b.WriteString("// Generated varlink interface description\n\n") - - // Special-quote backtick, it cannot be part of a backtick-quoted string - b.WriteString("func (s *VarlinkInterface) VarlinkGetDescription() string {\n" + - "\treturn `" + strings.Replace(midl.Description, "`", "` + \"`\" + `", -1) + "\n`\n}\n\n") - - b.WriteString("// Generated service interface\n\n") - - b.WriteString("type VarlinkInterface struct {\n" + - "\t" + pkgname + "Interface\n" + - "}\n\n") - - b.WriteString("func VarlinkNew(m " + pkgname + "Interface) *VarlinkInterface {\n" + - "\treturn &VarlinkInterface{m}\n" + - "}\n") - - ret_string := b.String() - - if strings.Contains(ret_string, "json.RawMessage") { - ret_string = strings.Replace(ret_string, "@IMPORTS@", "import (\n\t\"github.com/varlink/go/varlink\"\n\t\"encoding/json\"\n)", 1) - } else { - ret_string = strings.Replace(ret_string, "@IMPORTS@", `import "github.com/varlink/go/varlink"`, 1) - } - - pretty, err := format.Source([]byte(ret_string)) - if err != nil { - return "", nil, err - } - - return pkgname, pretty, nil -} - -func generateFile(varlinkFile string) { - file, err := ioutil.ReadFile(varlinkFile) - if err != nil { - fmt.Fprintf(os.Stderr, "Error reading file '%s': %s\n", varlinkFile, err) - os.Exit(1) - } - - pkgname, b, err := generateTemplate(string(file)) - if err != nil { - fmt.Fprintf(os.Stderr, "Error parsing file '%s': %s\n", varlinkFile, err) - os.Exit(1) - } - - filename := path.Dir(varlinkFile) + "/" + pkgname + ".go" - err = ioutil.WriteFile(filename, b, 0660) - if err != nil { - fmt.Fprintf(os.Stderr, "Error writing file '%s': %s\n", filename, err) - os.Exit(1) - } -} - -func main() { - if len(os.Args) != 2 { - fmt.Printf("Usage: %s <file>\n", os.Args[0]) - os.Exit(1) - } - generateFile(os.Args[1]) -} diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go deleted file mode 100644 index c478dcd88..000000000 --- a/vendor/github.com/varlink/go/varlink/bridge.go +++ /dev/null @@ -1,65 +0,0 @@ -// +build !windows - -package varlink - -import ( - "bufio" - "io" - "net" - "os" - "os/exec" -) - -type PipeCon struct { - net.Conn - cmd *exec.Cmd - reader *io.ReadCloser - writer *io.WriteCloser -} - -func (p PipeCon) Close() error { - err1 := (*p.reader).Close() - err2 := (*p.writer).Close() - if err1 != nil { - return err1 - } - if err2 != nil { - return err2 - } - p.cmd.Wait() - - return nil -} - -// NewBridgeWithStderr returns a new connection with the given bridge. -func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) { - //var err error - - c := Connection{} - cmd := exec.Command("sh", "-c", bridge) - cmd.Stderr = stderr - r, err := cmd.StdoutPipe() - if err != nil { - return nil, err - } - w, err := cmd.StdinPipe() - if err != nil { - return nil, err - } - c.conn = PipeCon{nil, cmd, &r, &w} - c.address = "" - c.Reader = bufio.NewReader(r) - c.Writer = bufio.NewWriter(w) - - err = cmd.Start() - if err != nil { - return nil, err - } - - return &c, nil -} - -// NewBridge returns a new connection with the given bridge. -func NewBridge(bridge string) (*Connection, error) { - return NewBridgeWithStderr(bridge, os.Stderr) -} diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go deleted file mode 100644 index 42953b871..000000000 --- a/vendor/github.com/varlink/go/varlink/bridge_windows.go +++ /dev/null @@ -1,63 +0,0 @@ -package varlink - -import ( - "bufio" - "io" - "net" - "os" - "os/exec" -) - -type PipeCon struct { - net.Conn - cmd *exec.Cmd - reader *io.ReadCloser - writer *io.WriteCloser -} - -func (p PipeCon) Close() error { - err1 := (*p.reader).Close() - err2 := (*p.writer).Close() - if err1 != nil { - return err1 - } - if err2 != nil { - return err2 - } - p.cmd.Wait() - - return nil -} - -// NewBridgeWithStderr returns a new connection with the given bridge. -func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) { - //var err error - - c := Connection{} - cmd := exec.Command("cmd", "/C", bridge) - cmd.Stderr = stderr - r, err := cmd.StdoutPipe() - if err != nil { - return nil, err - } - w, err := cmd.StdinPipe() - if err != nil { - return nil, err - } - c.conn = PipeCon{nil, cmd, &r, &w} - c.address = "" - c.Reader = bufio.NewReader(r) - c.Writer = bufio.NewWriter(w) - - err = cmd.Start() - if err != nil { - return nil, err - } - - return &c, nil -} - -// NewBridge returns a new connection with the given bridge. -func NewBridge(bridge string) (*Connection, error) { - return NewBridgeWithStderr(bridge, os.Stderr) -}
\ No newline at end of file diff --git a/vendor/github.com/varlink/go/varlink/call.go b/vendor/github.com/varlink/go/varlink/call.go deleted file mode 100644 index 0eaf24aca..000000000 --- a/vendor/github.com/varlink/go/varlink/call.go +++ /dev/null @@ -1,104 +0,0 @@ -package varlink - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net" - "strings" -) - -// Call is a method call retrieved by a Service. The connection from the -// client can be terminated by returning an error from the call instead -// of sending a reply or error reply. -type Call struct { - *bufio.Reader - *bufio.Writer - Conn *net.Conn - Request *[]byte - In *serviceCall - Continues bool - Upgrade bool -} - -// WantsMore indicates if the calling client accepts more than one reply to this method call. -func (c *Call) WantsMore() bool { - return c.In.More -} - -// WantsUpgrade indicates that the calling client wants the connection to be upgraded. -func (c *Call) WantsUpgrade() bool { - return c.In.Upgrade -} - -// IsOneway indicate that the calling client does not expect a reply. -func (c *Call) IsOneway() bool { - return c.In.Oneway -} - -// GetParameters retrieves the method call parameters. -func (c *Call) GetParameters(p interface{}) error { - if c.In.Parameters == nil { - return fmt.Errorf("empty parameters") - } - return json.Unmarshal(*c.In.Parameters, p) -} - -func (c *Call) sendMessage(r *serviceReply) error { - if c.In.Oneway { - return nil - } - - b, e := json.Marshal(r) - if e != nil { - return e - } - - b = append(b, 0) - _, e = c.Writer.Write(b) - if e != nil { - if e == io.EOF { - return io.ErrUnexpectedEOF - } - return e - } - e = c.Writer.Flush() - if e == io.EOF { - return io.ErrUnexpectedEOF - } - return e -} - -// Reply sends a reply to this method call. -func (c *Call) Reply(parameters interface{}) error { - if !c.Continues { - return c.sendMessage(&serviceReply{ - Parameters: parameters, - }) - } - - if !c.In.More { - return fmt.Errorf("call did not set more, it does not expect continues") - } - - return c.sendMessage(&serviceReply{ - Continues: true, - Parameters: parameters, - }) -} - -// ReplyError sends an error reply to this method call. -func (c *Call) ReplyError(name string, parameters interface{}) error { - r := strings.LastIndex(name, ".") - if r <= 0 { - return fmt.Errorf("invalid error name") - } - if name[:r] == "org.varlink.service" { - return fmt.Errorf("refused to send org.varlink.service errors") - } - return c.sendMessage(&serviceReply{ - Error: name, - Parameters: parameters, - }) -} diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go deleted file mode 100644 index 596caa825..000000000 --- a/vendor/github.com/varlink/go/varlink/connection.go +++ /dev/null @@ -1,291 +0,0 @@ -package varlink - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net" - "strings" -) - -// Message flags for Send(). More indicates that the client accepts more than one method -// reply to this call. Oneway requests, that the service must not send a method reply to -// this call. Continues indicates that the service will send more than one reply. -const ( - More = 1 << iota - Oneway = 1 << iota - Continues = 1 << iota - Upgrade = 1 << iota -) - -// Error is a varlink error returned from a method call. -type Error struct { - Name string - Parameters interface{} -} - -func (e *Error) DispatchError() error { - errorRawParameters := e.Parameters.(*json.RawMessage) - - switch e.Name { - case "org.varlink.service.InterfaceNotFound": - var param InterfaceNotFound - if errorRawParameters != nil { - err := json.Unmarshal(*errorRawParameters, ¶m) - if err != nil { - return e - } - } - return ¶m - case "org.varlink.service.MethodNotFound": - var param MethodNotFound - if errorRawParameters != nil { - err := json.Unmarshal(*errorRawParameters, ¶m) - if err != nil { - return e - } - } - return ¶m - case "org.varlink.service.MethodNotImplemented": - var param MethodNotImplemented - if errorRawParameters != nil { - err := json.Unmarshal(*errorRawParameters, ¶m) - if err != nil { - return e - } - } - return ¶m - case "org.varlink.service.InvalidParameter": - var param InvalidParameter - if errorRawParameters != nil { - err := json.Unmarshal(*errorRawParameters, ¶m) - if err != nil { - return e - } - } - return ¶m - } - return e -} - -// Error returns the fully-qualified varlink error name. -func (e *Error) Error() string { - return e.Name -} - -// Connection is a connection from a client to a service. -type Connection struct { - io.Closer - address string - conn net.Conn - Reader *bufio.Reader - Writer *bufio.Writer -} - -// Send sends a method call. It returns a receive() function which is called to retrieve the method reply. -// If Send() is called with the `More`flag and the receive() function carries the `Continues` flag, receive() -// can be called multiple times to retrieve multiple replies. -func (c *Connection) Send(method string, parameters interface{}, flags uint64) (func(interface{}) (uint64, error), error) { - type call struct { - Method string `json:"method"` - Parameters interface{} `json:"parameters,omitempty"` - More bool `json:"more,omitempty"` - Oneway bool `json:"oneway,omitempty"` - Upgrade bool `json:"upgrade,omitempty"` - } - - if (flags&More != 0) && (flags&Oneway != 0) { - return nil, &Error{ - Name: "org.varlink.InvalidParameter", - Parameters: "oneway", - } - } - - if (flags&More != 0) && (flags&Upgrade != 0) { - return nil, &Error{ - Name: "org.varlink.InvalidParameter", - Parameters: "more", - } - } - - m := call{ - Method: method, - Parameters: parameters, - More: flags&More != 0, - Oneway: flags&Oneway != 0, - Upgrade: flags&Upgrade != 0, - } - b, err := json.Marshal(m) - if err != nil { - return nil, err - } - - b = append(b, 0) - _, err = c.Writer.Write(b) - if err != nil { - if err == io.EOF { - return nil, io.ErrUnexpectedEOF - } - return nil, err - } - - err = c.Writer.Flush() - if err != nil { - if err == io.EOF { - return nil, io.ErrUnexpectedEOF - } - return nil, err - } - - receive := func(out_parameters interface{}) (uint64, error) { - type reply struct { - Parameters *json.RawMessage `json:"parameters"` - Continues bool `json:"continues"` - Error string `json:"error"` - } - - out, err := c.Reader.ReadBytes('\x00') - if err != nil { - if err == io.EOF { - return 0, io.ErrUnexpectedEOF - } - return 0, err - } - - var m reply - err = json.Unmarshal(out[:len(out)-1], &m) - if err != nil { - return 0, err - } - - if m.Error != "" { - e := &Error{ - Name: m.Error, - Parameters: m.Parameters, - } - return 0, e.DispatchError() - } - - if m.Parameters != nil { - json.Unmarshal(*m.Parameters, out_parameters) - } - - if m.Continues { - return Continues, nil - } - - return 0, nil - } - - return receive, nil -} - -// Call sends a method call and returns the method reply. -func (c *Connection) Call(method string, parameters interface{}, out_parameters interface{}) error { - receive, err := c.Send(method, ¶meters, 0) - if err != nil { - return err - } - - _, err = receive(out_parameters) - return err -} - -// GetInterfaceDescription requests the interface description string from the service. -func (c *Connection) GetInterfaceDescription(name string) (string, error) { - type request struct { - Interface string `json:"interface"` - } - type reply struct { - Description string `json:"description"` - } - - var r reply - err := c.Call("org.varlink.service.GetInterfaceDescription", request{Interface: name}, &r) - if err != nil { - return "", err - } - - return r.Description, nil -} - -// GetInfo requests information about the service. -func (c *Connection) GetInfo(vendor *string, product *string, version *string, url *string, interfaces *[]string) error { - type reply struct { - Vendor string `json:"vendor"` - Product string `json:"product"` - Version string `json:"version"` - URL string `json:"url"` - Interfaces []string `json:"interfaces"` - } - - var r reply - err := c.Call("org.varlink.service.GetInfo", nil, &r) - if err != nil { - return err - } - - if vendor != nil { - *vendor = r.Vendor - } - if product != nil { - *product = r.Product - } - if version != nil { - *version = r.Version - } - if url != nil { - *url = r.URL - } - if interfaces != nil { - *interfaces = r.Interfaces - } - - return nil -} - -// Close terminates the connection. -func (c *Connection) Close() error { - return c.conn.Close() -} - -// NewConnection returns a new connection to the given address. -func NewConnection(address string) (*Connection, error) { - var err error - - words := strings.SplitN(address, ":", 2) - - if len(words) != 2 { - return nil, fmt.Errorf("Protocol missing") - } - - protocol := words[0] - addr := words[1] - - // Ignore parameters after ';' - words = strings.SplitN(addr, ";", 2) - if words != nil { - addr = words[0] - } - - switch protocol { - case "unix": - break - - case "tcp": - break - } - - c := Connection{} - c.conn, err = net.Dial(protocol, addr) - if err != nil { - return nil, err - } - - c.address = address - c.Reader = bufio.NewReader(c.conn) - c.Writer = bufio.NewWriter(c.conn) - - return &c, nil -} diff --git a/vendor/github.com/varlink/go/varlink/doc.go b/vendor/github.com/varlink/go/varlink/doc.go deleted file mode 100644 index de1ed2380..000000000 --- a/vendor/github.com/varlink/go/varlink/doc.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Package varlink provides varlink client and server implementations. See http://varlink.org -for more information about varlink. - -Example varlink interface definition in a org.example.this.varlink file: - interface org.example.this - - method Ping(in: string) -> (out: string) - -Generated Go module in a orgexamplethis/orgexamplethis.go file. The generated module -provides reply methods for all methods specified in the varlink interface description. -The stub implementations return a MethodNotImplemented error; the service implementation -using this module will override the methods with its own implementation. - // Generated with github.com/varlink/go/cmd/varlink-go-interface-generator - package orgexamplethis - - import "github.com/varlink/go/varlink" - - type orgexamplethisInterface interface { - Ping(c VarlinkCall, in string) error - } - - type VarlinkCall struct{ varlink.Call } - - func (c *VarlinkCall) ReplyPing(out string) error { - var out struct { - Out string `json:"out,omitempty"` - } - out.Out = out - return c.Reply(&out) - } - - func (s *VarlinkInterface) Ping(c VarlinkCall, in string) error { - return c.ReplyMethodNotImplemented("Ping") - } - - [...] - -Service implementing the interface and its method: - import ("orgexamplethis") - - type Data struct { - orgexamplethis.VarlinkInterface - data string - } - - data := Data{data: "test"} - - func (d *Data) Ping(call orgexamplethis.VarlinkCall, ping string) error { - return call.ReplyPing(ping) - } - - service, _ = varlink.NewService( - "Example", - "This", - "1", - "https://example.org/this", - ) - - service.RegisterInterface(orgexamplethis.VarlinkNew(&data)) - err := service.Listen("unix:/run/org.example.this", 0) -*/ -package varlink diff --git a/vendor/github.com/varlink/go/varlink/idl/idl.go b/vendor/github.com/varlink/go/varlink/idl/idl.go deleted file mode 100644 index b09b4798b..000000000 --- a/vendor/github.com/varlink/go/varlink/idl/idl.go +++ /dev/null @@ -1,497 +0,0 @@ -// Package idl provides a varlink interface description parser. -package idl - -import ( - "bytes" - "fmt" - "regexp" -) - -// Valid TypeKind values. -const ( - TypeBool = iota - TypeInt - TypeFloat - TypeString - TypeObject - TypeArray - TypeMaybe - TypeMap - TypeStruct - TypeEnum - TypeAlias -) - -// TypeKind specifies the type of an Type. -type TypeKind uint - -// Type represents a varlink type. Types are method input and output parameters, -// error output parameters, or custom defined types in the interface description. -type Type struct { - Kind TypeKind - ElementType *Type - Alias string - Fields []TypeField -} - -// TypeField is a named member of a TypeStruct. -type TypeField struct { - Name string - Type *Type -} - -// Alias represents a named Type in the interface description. -type Alias struct { - Name string - Doc string - Type *Type -} - -// Method represents a method defined in the interface description. -type Method struct { - Name string - Doc string - In *Type - Out *Type -} - -// Error represents an error defined in the interface description. -type Error struct { - Name string - Doc string - Type *Type -} - -// IDL represents a parsed varlink interface description with types, methods, errors and -// documentation. -type IDL struct { - Name string - Doc string - Description string - Members []interface{} - Aliases []*Alias - Methods []*Method - Errors []*Error -} - -type parser struct { - input string - position int - lineStart int - lastComment bytes.Buffer -} - -func (p *parser) next() int { - r := -1 - - if p.position < len(p.input) { - r = int(p.input[p.position]) - } - - p.position++ - return r -} - -func (p *parser) backup() { - p.position-- -} - -func (p *parser) advance() bool { - for { - char := p.next() - - if char == '\n' { - p.lineStart = p.position - p.lastComment.Reset() - - } else if char == ' ' || char == '\t' { - // ignore - - } else if char == '#' { - p.next() - start := p.position - for { - c := p.next() - if c < 0 || c == '\n' { - p.backup() - break - } - } - if p.lastComment.Len() > 0 { - p.lastComment.WriteByte('\n') - } - p.lastComment.WriteString(p.input[start:p.position]) - p.next() - - } else { - p.backup() - break - } - } - - return p.position < len(p.input) -} - -func (p *parser) advanceOnLine() { - for { - char := p.next() - if char != ' ' { - p.backup() - return - } - } -} - -func (p *parser) readKeyword() string { - start := p.position - - for { - char := p.next() - if char < 'a' || char > 'z' { - p.backup() - break - } - } - - return p.input[start:p.position] -} - -func (p *parser) readInterfaceName() string { - start := p.position - dnrx := regexp.MustCompile(`^[a-z]+(\.[a-z0-9]+([-][a-z0-9]+)*)+`) - name := dnrx.FindString(p.input[start:]) - if name != "" { - if len(name) > 255 { - return "" - } - p.position += len(name) - return name - } - xdnrx := regexp.MustCompile(`^xn--[a-z0-9]+(\.[a-z0-9]+([-][a-z0-9]+)*)+`) - name = xdnrx.FindString(p.input[start:]) - if name != "" { - if len(name) > 255 { - return "" - } - p.position += len(name) - return name - } - return "" -} - -func (p *parser) readFieldName() string { - start := p.position - - char := p.next() - if char < 'a' || char > 'z' { - p.backup() - return "" - } - - for { - char := p.next() - if (char < 'A' || char > 'Z') && (char < 'a' || char > 'z') && (char < '0' || char > '9') && char != '_' { - p.backup() - break - } - } - - return p.input[start:p.position] -} - -func (p *parser) readTypeName() string { - start := p.position - - for { - char := p.next() - if (char < 'A' || char > 'Z') && (char < 'a' || char > 'z') && (char < '0' || char > '9') { - p.backup() - break - } - } - - return p.input[start:p.position] -} - -func (p *parser) readStructType() *Type { - if p.next() != '(' { - p.backup() - return nil - } - - t := &Type{Kind: TypeStruct} - t.Fields = make([]TypeField, 0) - - char := p.next() - if char != ')' { - p.backup() - - for { - field := TypeField{} - - p.advance() - field.Name = p.readFieldName() - if field.Name == "" { - return nil - } - - p.advance() - - // Enums have no types, they are just a list of names - if p.next() == ':' { - if t.Kind == TypeEnum { - return nil - } - - p.advance() - field.Type = p.readType() - if field.Type == nil { - return nil - } - - } else { - t.Kind = TypeEnum - p.backup() - } - - t.Fields = append(t.Fields, field) - - p.advance() - char = p.next() - if char != ',' { - break - } - } - - if char != ')' { - return nil - } - } - - return t -} - -func (p *parser) readType() *Type { - var t *Type - - switch p.next() { - case '?': - e := p.readType() - if e == nil { - return nil - } - if e.Kind == TypeMaybe { - return nil - } - t = &Type{Kind: TypeMaybe, ElementType: e} - - case '[': - var kind TypeKind - - switch p.readKeyword() { - case "string": - kind = TypeMap - - case "": - kind = TypeArray - - default: - return nil - } - - if p.next() != ']' { - return nil - } - e := p.readType() - if e == nil { - return nil - } - t = &Type{Kind: kind, ElementType: e} - - default: - p.backup() - if keyword := p.readKeyword(); keyword != "" { - switch keyword { - case "bool": - t = &Type{Kind: TypeBool} - - case "int": - t = &Type{Kind: TypeInt} - - case "float": - t = &Type{Kind: TypeFloat} - - case "string": - t = &Type{Kind: TypeString} - - case "object": - t = &Type{Kind: TypeObject} - } - - } else if name := p.readTypeName(); name != "" { - t = &Type{Kind: TypeAlias, Alias: name} - - } else if t = p.readStructType(); t == nil { - return nil - } - } - - return t -} - -func (p *parser) readAlias(idl *IDL) (*Alias, error) { - a := &Alias{} - - p.advance() - a.Doc = p.lastComment.String() - a.Name = p.readTypeName() - if a.Name == "" { - return nil, fmt.Errorf("missing type name") - } - - p.advance() - a.Type = p.readType() - if a.Type == nil { - return nil, fmt.Errorf("missing type declaration") - } - - return a, nil -} - -func (p *parser) readMethod(idl *IDL) (*Method, error) { - m := &Method{} - - p.advance() - m.Doc = p.lastComment.String() - m.Name = p.readTypeName() - if m.Name == "" { - return nil, fmt.Errorf("missing method type") - } - - p.advance() - m.In = p.readType() - if m.In == nil { - return nil, fmt.Errorf("missing method input") - } - - p.advance() - one := p.next() - two := p.next() - if (one != '-') || two != '>' { - return nil, fmt.Errorf("missing method '->' operator") - } - - p.advance() - m.Out = p.readType() - if m.Out == nil { - return nil, fmt.Errorf("missing method output") - } - - return m, nil -} - -func (p *parser) readError(idl *IDL) (*Error, error) { - e := &Error{} - - p.advance() - e.Doc = p.lastComment.String() - e.Name = p.readTypeName() - if e.Name == "" { - return nil, fmt.Errorf("missing error name") - } - - p.advanceOnLine() - e.Type = p.readType() - - return e, nil -} - -func (p *parser) readIDL() (*IDL, error) { - if keyword := p.readKeyword(); keyword != "interface" { - return nil, fmt.Errorf("missing interface keyword") - } - - idl := &IDL{ - Members: make([]interface{}, 0), - Aliases: make([]*Alias, 0), - Methods: make([]*Method, 0), - Errors: make([]*Error, 0), - } - - p.advance() - idl.Doc = p.lastComment.String() - idl.Name = p.readInterfaceName() - if idl.Name == "" { - return nil, fmt.Errorf("interface name") - } - - // Check for duplicates - members := make(map[string]struct{}, 0) - - for { - if !p.advance() { - break - } - - switch keyword := p.readKeyword(); keyword { - case "type": - a, err := p.readAlias(idl) - if err != nil { - return nil, err - } - if _, ok := members[a.Name]; ok { - return nil, fmt.Errorf("type `%s` already defined", a.Name) - } - members[a.Name] = struct{}{} - idl.Aliases = append(idl.Aliases, a) - idl.Members = append(idl.Members, a) - - case "method": - m, err := p.readMethod(idl) - if err != nil { - return nil, err - } - if _, ok := members[m.Name]; ok { - return nil, fmt.Errorf("method `%s` already defined", m.Name) - } - members[m.Name] = struct{}{} - idl.Methods = append(idl.Methods, m) - idl.Members = append(idl.Members, m) - - case "error": - e, err := p.readError(idl) - if err != nil { - return nil, err - } - if _, ok := members[e.Name]; ok { - return nil, fmt.Errorf("error `%s` already defined", e.Name) - } - members[e.Name] = struct{}{} - idl.Errors = append(idl.Errors, e) - idl.Members = append(idl.Members, e) - - default: - return nil, fmt.Errorf("unknown keyword '%s'", keyword) - } - } - - return idl, nil -} - -// New parses a varlink interface description. -func New(description string) (*IDL, error) { - p := &parser{input: description} - - p.advance() - idl, err := p.readIDL() - if err != nil { - return nil, err - } - - if len(idl.Methods) == 0 { - return nil, fmt.Errorf("no methods defined") - } - - idl.Description = description - return idl, nil -} diff --git a/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go b/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go deleted file mode 100644 index 600c99d34..000000000 --- a/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go +++ /dev/null @@ -1,162 +0,0 @@ -package varlink - -// The requested interface was not found. -type InterfaceNotFound struct { - Interface string `json:"interface"` -} - -func (e InterfaceNotFound) Error() string { - return "org.varlink.service.InterfaceNotFound" -} - -// The requested method was not found -type MethodNotFound struct { - Method string `json:"method"` -} - -func (e MethodNotFound) Error() string { - return "org.varlink.service.MethodNotFound" -} - -// The interface defines the requested method, but the service does not -// implement it. -type MethodNotImplemented struct { - Method string `json:"method"` -} - -func (e MethodNotImplemented) Error() string { - return "org.varlink.service.MethodNotImplemented" -} - -// One of the passed parameters is invalid. -type InvalidParameter struct { - Parameter string `json:"parameter"` -} - -func (e InvalidParameter) Error() string { - return "org.varlink.service.InvalidParameter" -} - -func doReplyError(c *Call, name string, parameters interface{}) error { - return c.sendMessage(&serviceReply{ - Error: name, - Parameters: parameters, - }) -} - -// ReplyInterfaceNotFound sends a org.varlink.service errror reply to this method call -func (c *Call) ReplyInterfaceNotFound(interfaceA string) error { - var out InterfaceNotFound - out.Interface = interfaceA - return doReplyError(c, "org.varlink.service.InterfaceNotFound", &out) -} - -// ReplyMethodNotFound sends a org.varlink.service errror reply to this method call -func (c *Call) ReplyMethodNotFound(method string) error { - var out MethodNotFound - out.Method = method - return doReplyError(c, "org.varlink.service.MethodNotFound", &out) -} - -// ReplyMethodNotImplemented sends a org.varlink.service errror reply to this method call -func (c *Call) ReplyMethodNotImplemented(method string) error { - var out MethodNotImplemented - out.Method = method - return doReplyError(c, "org.varlink.service.MethodNotImplemented", &out) -} - -// ReplyInvalidParameter sends a org.varlink.service errror reply to this method call -func (c *Call) ReplyInvalidParameter(parameter string) error { - var out InvalidParameter - out.Parameter = parameter - return doReplyError(c, "org.varlink.service.InvalidParameter", &out) -} - -func (c *Call) replyGetInfo(vendor string, product string, version string, url string, interfaces []string) error { - var out struct { - Vendor string `json:"vendor,omitempty"` - Product string `json:"product,omitempty"` - Version string `json:"version,omitempty"` - URL string `json:"url,omitempty"` - Interfaces []string `json:"interfaces,omitempty"` - } - out.Vendor = vendor - out.Product = product - out.Version = version - out.URL = url - out.Interfaces = interfaces - return c.Reply(&out) -} - -func (c *Call) replyGetInterfaceDescription(description string) error { - var out struct { - Description string `json:"description,omitempty"` - } - out.Description = description - return c.Reply(&out) -} - -func (s *Service) orgvarlinkserviceDispatch(c Call, methodname string) error { - switch methodname { - case "GetInfo": - return s.getInfo(c) - case "GetInterfaceDescription": - var in struct { - Interface string `json:"interface"` - } - err := c.GetParameters(&in) - if err != nil { - return c.ReplyInvalidParameter("parameters") - } - return s.getInterfaceDescription(c, in.Interface) - - default: - return c.ReplyMethodNotFound(methodname) - } -} - -func (s *orgvarlinkserviceInterface) VarlinkDispatch(call Call, methodname string) error { - return nil -} - -func (s *orgvarlinkserviceInterface) VarlinkGetName() string { - return `org.varlink.service` -} - -func (s *orgvarlinkserviceInterface) VarlinkGetDescription() string { - return `# The Varlink Service Interface is provided by every varlink service. It -# describes the service and the interfaces it implements. -interface org.varlink.service - -# Get a list of all the interfaces a service provides and information -# about the implementation. -method GetInfo() -> ( - vendor: string, - product: string, - version: string, - url: string, - interfaces: []string -) - -# Get the description of an interface that is implemented by this service. -method GetInterfaceDescription(interface: string) -> (description: string) - -# The requested interface was not found. -error InterfaceNotFound (interface: string) - -# The requested method was not found -error MethodNotFound (method: string) - -# The interface defines the requested method, but the service does not -# implement it. -error MethodNotImplemented (method: string) - -# One of the passed parameters is invalid. -error InvalidParameter (parameter: string)` -} - -type orgvarlinkserviceInterface struct{} - -func orgvarlinkserviceNew() *orgvarlinkserviceInterface { - return &orgvarlinkserviceInterface{} -} diff --git a/vendor/github.com/varlink/go/varlink/resolver.go b/vendor/github.com/varlink/go/varlink/resolver.go deleted file mode 100644 index f0f4487d2..000000000 --- a/vendor/github.com/varlink/go/varlink/resolver.go +++ /dev/null @@ -1,92 +0,0 @@ -package varlink - -// ResolverAddress is the well-known address of the varlink interface resolver, -// it translates varlink interface names to varlink service addresses. -const ResolverAddress = "unix:/run/org.varlink.resolver" - -// Resolver resolves varlink interface names to varlink addresses -type Resolver struct { - address string - conn *Connection -} - -// Resolve resolves a varlink interface name to a varlink address. -func (r *Resolver) Resolve(iface string) (string, error) { - type request struct { - Interface string `json:"interface"` - } - type reply struct { - Address string `json:"address"` - } - - /* don't ask the resolver for itself */ - if iface == "org.varlink.resolver" { - return r.address, nil - } - - var rep reply - err := r.conn.Call("org.varlink.resolver.Resolve", &request{Interface: iface}, &rep) - if err != nil { - return "", err - } - - return rep.Address, nil -} - -// GetInfo requests information about the resolver. -func (r *Resolver) GetInfo(vendor *string, product *string, version *string, url *string, interfaces *[]string) error { - type reply struct { - Vendor string - Product string - Version string - URL string - Interfaces []string - } - - var rep reply - err := r.conn.Call("org.varlink.resolver.GetInfo", nil, &rep) - if err != nil { - return err - } - - if vendor != nil { - *vendor = rep.Vendor - } - if product != nil { - *product = rep.Product - } - if version != nil { - *version = rep.Version - } - if url != nil { - *url = rep.URL - } - if interfaces != nil { - *interfaces = rep.Interfaces - } - - return nil -} - -// Close terminates the resolver. -func (r *Resolver) Close() error { - return r.conn.Close() -} - -// NewResolver returns a new resolver connected to the given address. -func NewResolver(address string) (*Resolver, error) { - if address == "" { - address = ResolverAddress - } - - c, err := NewConnection(address) - if err != nil { - return nil, err - } - r := Resolver{ - address: address, - conn: c, - } - - return &r, nil -} diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go deleted file mode 100644 index bf13aa1de..000000000 --- a/vendor/github.com/varlink/go/varlink/service.go +++ /dev/null @@ -1,375 +0,0 @@ -package varlink - -import ( - "bufio" - "encoding/json" - "fmt" - "net" - "os" - "strings" - "sync" - "time" -) - -type dispatcher interface { - VarlinkDispatch(c Call, methodname string) error - VarlinkGetName() string - VarlinkGetDescription() string -} - -type serviceCall struct { - Method string `json:"method"` - Parameters *json.RawMessage `json:"parameters,omitempty"` - More bool `json:"more,omitempty"` - Oneway bool `json:"oneway,omitempty"` - Upgrade bool `json:"upgrade,omitempty"` -} - -type serviceReply struct { - Parameters interface{} `json:"parameters,omitempty"` - Continues bool `json:"continues,omitempty"` - Error string `json:"error,omitempty"` -} - -// Service represents an active varlink service. In addition to the registered custom varlink Interfaces, every service -// implements the org.varlink.service interface which allows clients to retrieve information about the -// running service. -type Service struct { - vendor string - product string - version string - url string - interfaces map[string]dispatcher - names []string - descriptions map[string]string - running bool - listener net.Listener - conncounter int64 - mutex sync.Mutex - protocol string - address string -} - -// ServiceTimoutError helps API users to special-case timeouts. -type ServiceTimeoutError struct{} - -func (ServiceTimeoutError) Error() string { - return "service timeout" -} - -func (s *Service) getInfo(c Call) error { - return c.replyGetInfo(s.vendor, s.product, s.version, s.url, s.names) -} - -func (s *Service) getInterfaceDescription(c Call, name string) error { - if name == "" { - return c.ReplyInvalidParameter("interface") - } - - description, ok := s.descriptions[name] - if !ok { - return c.ReplyInvalidParameter("interface") - } - - return c.replyGetInterfaceDescription(description) -} - -func (s *Service) HandleMessage(conn *net.Conn, reader *bufio.Reader, writer *bufio.Writer, request []byte) error { - var in serviceCall - - err := json.Unmarshal(request, &in) - - if err != nil { - return err - } - - c := Call{ - Conn: conn, - Reader: reader, - Writer: writer, - In: &in, - Request: &request, - } - - r := strings.LastIndex(in.Method, ".") - if r <= 0 { - return c.ReplyInvalidParameter("method") - } - - interfacename := in.Method[:r] - methodname := in.Method[r+1:] - - if interfacename == "org.varlink.service" { - return s.orgvarlinkserviceDispatch(c, methodname) - } - - // Find the interface and method in our service - iface, ok := s.interfaces[interfacename] - if !ok { - return c.ReplyInterfaceNotFound(interfacename) - } - - return iface.VarlinkDispatch(c, methodname) -} - -// Shutdown shuts down the listener of a running service. -func (s *Service) Shutdown() { - s.running = false - s.mutex.Lock() - if s.listener != nil { - s.listener.Close() - } - s.mutex.Unlock() -} - -func (s *Service) handleConnection(conn net.Conn, wg *sync.WaitGroup) { - defer func() { s.mutex.Lock(); s.conncounter--; s.mutex.Unlock(); wg.Done() }() - reader := bufio.NewReader(conn) - writer := bufio.NewWriter(conn) - - for { - request, err := reader.ReadBytes('\x00') - if err != nil { - break - } - - err = s.HandleMessage(&conn, reader, writer, request[:len(request)-1]) - if err != nil { - // FIXME: report error - //fmt.Fprintf(os.Stderr, "handleMessage: %v", err) - break - } - } - - conn.Close() -} - -func (s *Service) teardown() { - s.mutex.Lock() - s.listener = nil - s.running = false - s.protocol = "" - s.address = "" - s.mutex.Unlock() -} - -func (s *Service) parseAddress(address string) error { - words := strings.SplitN(address, ":", 2) - if len(words) != 2 { - return fmt.Errorf("Unknown protocol") - } - - s.protocol = words[0] - s.address = words[1] - - // Ignore parameters after ';' - words = strings.SplitN(s.address, ";", 2) - if words != nil { - s.address = words[0] - } - - switch s.protocol { - case "unix": - break - case "tcp": - break - - default: - return fmt.Errorf("Unknown protocol") - } - - return nil -} - -func (s *Service) GetListener() (*net.Listener, error) { - s.mutex.Lock() - l := s.listener - s.mutex.Unlock() - return &l, nil -} - -func (s *Service) setListener() error { - l := activationListener() - if l == nil { - if s.protocol == "unix" && s.address[0] != '@' { - os.Remove(s.address) - } - - var err error - l, err = net.Listen(s.protocol, s.address) - if err != nil { - return err - } - - if s.protocol == "unix" && s.address[0] != '@' { - l.(*net.UnixListener).SetUnlinkOnClose(true) - } - } - - s.mutex.Lock() - s.listener = l - s.mutex.Unlock() - - return nil -} - -func (s *Service) refreshTimeout(timeout time.Duration) error { - switch l := s.listener.(type) { - case *net.UnixListener: - if err := l.SetDeadline(time.Now().Add(timeout)); err != nil { - return err - } - case *net.TCPListener: - if err := l.SetDeadline(time.Now().Add(timeout)); err != nil { - return err - } - - } - return nil -} - -// Listen starts a Service. -func (s *Service) Bind(address string) error { - s.mutex.Lock() - if s.running { - s.mutex.Unlock() - return fmt.Errorf("Init(): already running") - } - s.mutex.Unlock() - - s.parseAddress(address) - - err := s.setListener() - if err != nil { - return err - } - return nil -} - -// Listen starts a Service. -func (s *Service) Listen(address string, timeout time.Duration) error { - var wg sync.WaitGroup - defer func() { s.teardown(); wg.Wait() }() - - err := s.Bind(address) - if err != nil { - return err - } - - s.mutex.Lock() - s.running = true - l := s.listener - s.mutex.Unlock() - - for s.running { - if timeout != 0 { - if err := s.refreshTimeout(timeout); err != nil { - return err - } - } - conn, err := l.Accept() - if err != nil { - if err.(net.Error).Timeout() { - s.mutex.Lock() - if s.conncounter == 0 { - s.mutex.Unlock() - return ServiceTimeoutError{} - } - s.mutex.Unlock() - continue - } - if !s.running { - return nil - } - return err - } - s.mutex.Lock() - s.conncounter++ - s.mutex.Unlock() - wg.Add(1) - go s.handleConnection(conn, &wg) - } - - return nil -} - -// Listen starts a Service. -func (s *Service) DoListen(timeout time.Duration) error { - var wg sync.WaitGroup - defer func() { s.teardown(); wg.Wait() }() - - s.mutex.Lock() - l := s.listener - s.mutex.Unlock() - - if l == nil { - return fmt.Errorf("No listener set") - } - - s.mutex.Lock() - s.running = true - s.mutex.Unlock() - - for s.running { - if timeout != 0 { - if err := s.refreshTimeout(timeout); err != nil { - return err - } - } - conn, err := l.Accept() - if err != nil { - if err.(net.Error).Timeout() { - s.mutex.Lock() - if s.conncounter == 0 { - s.mutex.Unlock() - return ServiceTimeoutError{} - } - s.mutex.Unlock() - continue - } - if !s.running { - return nil - } - return err - } - s.mutex.Lock() - s.conncounter++ - s.mutex.Unlock() - wg.Add(1) - go s.handleConnection(conn, &wg) - } - - return nil -} - -// RegisterInterface registers a varlink.Interface containing struct to the Service -func (s *Service) RegisterInterface(iface dispatcher) error { - name := iface.VarlinkGetName() - if _, ok := s.interfaces[name]; ok { - return fmt.Errorf("interface '%s' already registered", name) - } - - if s.running { - return fmt.Errorf("service is already running") - } - s.interfaces[name] = iface - s.descriptions[name] = iface.VarlinkGetDescription() - s.names = append(s.names, name) - - return nil -} - -// NewService creates a new Service which implements the list of given varlink interfaces. -func NewService(vendor string, product string, version string, url string) (*Service, error) { - s := Service{ - vendor: vendor, - product: product, - version: version, - url: url, - interfaces: make(map[string]dispatcher), - descriptions: make(map[string]string), - } - err := s.RegisterInterface(orgvarlinkserviceNew()) - - return &s, err -} diff --git a/vendor/github.com/varlink/go/varlink/socketactivation.go b/vendor/github.com/varlink/go/varlink/socketactivation.go deleted file mode 100644 index a64c0dc8e..000000000 --- a/vendor/github.com/varlink/go/varlink/socketactivation.go +++ /dev/null @@ -1,63 +0,0 @@ -// +build !windows - -package varlink - -import ( - "net" - "os" - "strconv" - "strings" - "syscall" -) - -func activationListener() net.Listener { - pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) - if err != nil || pid != os.Getpid() { - return nil - } - - nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) - if err != nil || nfds < 1 { - return nil - } - - fd := -1 - - // If more than one file descriptor is passed, find the - // "varlink" tag. The first file descriptor is always 3. - if nfds > 1 { - fdnames, set := os.LookupEnv("LISTEN_FDNAMES") - if !set { - return nil - } - - names := strings.Split(fdnames, ":") - if len(names) != nfds { - return nil - } - - for i, name := range names { - if name == "varlink" { - fd = 3 + i - break - } - } - - if fd < 0 { - return nil - } - - } else { - fd = 3 - } - - syscall.CloseOnExec(fd) - - file := os.NewFile(uintptr(fd), "varlink") - listener, err := net.FileListener(file) - if err != nil { - return nil - } - - return listener -} diff --git a/vendor/github.com/varlink/go/varlink/socketactivation_windows.go b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go deleted file mode 100644 index fb0894531..000000000 --- a/vendor/github.com/varlink/go/varlink/socketactivation_windows.go +++ /dev/null @@ -1,7 +0,0 @@ -package varlink - -import "net" - -func activationListener() net.Listener { - return nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 557fe263f..0c6b4de57 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -67,7 +67,7 @@ github.com/containernetworking/plugins/pkg/utils/hwaddr github.com/containernetworking/plugins/pkg/utils/sysctl github.com/containernetworking/plugins/plugins/ipam/host-local/backend github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator -# github.com/containers/buildah v1.18.0 +# github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c github.com/containers/buildah github.com/containers/buildah/bind github.com/containers/buildah/chroot @@ -84,9 +84,7 @@ github.com/containers/buildah/pkg/manifests github.com/containers/buildah/pkg/overlay github.com/containers/buildah/pkg/parse github.com/containers/buildah/pkg/rusage -github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented -github.com/containers/buildah/pkg/umask github.com/containers/buildah/util # github.com/containers/common v0.29.0 github.com/containers/common/pkg/apparmor @@ -100,7 +98,9 @@ github.com/containers/common/pkg/report github.com/containers/common/pkg/report/camelcase github.com/containers/common/pkg/retry github.com/containers/common/pkg/seccomp +github.com/containers/common/pkg/subscriptions github.com/containers/common/pkg/sysinfo +github.com/containers/common/pkg/umask github.com/containers/common/version # github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon/runner/config @@ -549,10 +549,6 @@ github.com/ulikunitz/xz github.com/ulikunitz/xz/internal/hash github.com/ulikunitz/xz/internal/xlog github.com/ulikunitz/xz/lzma -# github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b -github.com/varlink/go/cmd/varlink-go-interface-generator -github.com/varlink/go/varlink -github.com/varlink/go/varlink/idl # github.com/vbatts/tar-split v0.11.1 github.com/vbatts/tar-split/archive/tar github.com/vbatts/tar-split/tar/asm |