summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml129
-rwxr-xr-xAPI.md9
-rw-r--r--Makefile40
-rw-r--r--README.md6
-rw-r--r--RELEASE_NOTES.md81
-rw-r--r--changelog.txt296
-rw-r--r--cmd/podman/cliconfig/config.go16
-rw-r--r--cmd/podman/common.go4
-rw-r--r--cmd/podman/cp.go5
-rw-r--r--cmd/podman/libpodruntime/runtime.go19
-rw-r--r--cmd/podman/main.go2
-rw-r--r--cmd/podman/main_local.go2
-rw-r--r--cmd/podman/main_remote.go38
-rw-r--r--cmd/podman/main_remote_supported.go57
-rw-r--r--cmd/podman/main_remote_windows.go7
-rw-r--r--cmd/podman/network.go31
-rw-r--r--cmd/podman/network_inspect.go48
-rw-r--r--cmd/podman/network_list.go53
-rw-r--r--cmd/podman/network_rm.go48
-rw-r--r--cmd/podman/pod_create.go3
-rw-r--r--cmd/podman/pod_stats.go13
-rw-r--r--cmd/podman/port.go11
-rw-r--r--cmd/podman/pull.go4
-rw-r--r--cmd/podman/remoteclientconfig/config_linux.go9
-rw-r--r--cmd/podman/restore.go1
-rw-r--r--cmd/podman/shared/container.go8
-rw-r--r--cmd/podman/shared/create.go26
-rw-r--r--cmd/podman/shared/intermediate.go2
-rw-r--r--cmd/podman/shared/intermediate_varlink.go2
-rw-r--r--cmd/podman/sign.go3
-rw-r--r--cmd/podman/stats.go13
-rw-r--r--cmd/podman/system_df.go8
-rw-r--r--cmd/podman/varlink.go2
-rw-r--r--cmd/podman/varlink/io.podman.varlink7
-rw-r--r--commands.md4
-rw-r--r--completions/bash/podman74
-rw-r--r--contrib/cirrus/README.md8
-rw-r--r--contrib/cirrus/add_second_partition.sh62
-rwxr-xr-xcontrib/cirrus/build_vm_images.sh2
-rwxr-xr-xcontrib/cirrus/check_image.sh18
-rwxr-xr-xcontrib/cirrus/integration_test.sh14
-rw-r--r--contrib/cirrus/lib.sh27
-rwxr-xr-xcontrib/cirrus/networking.sh17
-rw-r--r--contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg1
-rw-r--r--contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg4
l---------contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg1
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh18
-rw-r--r--contrib/cirrus/packer/libpod_images.yml7
-rw-r--r--contrib/cirrus/packer/ubuntu_setup.sh7
l---------contrib/cirrus/packer/xfedora_setup.sh1
-rw-r--r--contrib/cirrus/required_host_ports.txt11
-rwxr-xr-xcontrib/cirrus/setup_environment.sh14
-rw-r--r--contrib/imgprune/Dockerfile2
-rw-r--r--contrib/perftest/main.go2
-rw-r--r--contrib/snapcraft/.editorconfig17
-rw-r--r--contrib/snapcraft/.gitignore12
-rw-r--r--contrib/snapcraft/LICENSE21
-rw-r--r--contrib/snapcraft/README.md82
-rw-r--r--contrib/snapcraft/snap/snapcraft.yaml45
-rw-r--r--contrib/spec/podman.spec.in11
-rw-r--r--contrib/varlink/io.podman.service3
-rw-r--r--contrib/varlink/io.podman.socket2
-rw-r--r--docs/podman-build.1.md45
-rw-r--r--docs/podman-container-restore.1.md9
-rw-r--r--docs/podman-container-runlabel.1.md4
-rw-r--r--docs/podman-create.1.md32
-rw-r--r--docs/podman-events.1.md9
-rw-r--r--docs/podman-login.1.md4
-rw-r--r--docs/podman-logout.1.md4
-rw-r--r--docs/podman-network-inspect.1.md50
-rw-r--r--docs/podman-network-ls.1.md43
-rw-r--r--docs/podman-network-rm.1.md25
-rw-r--r--docs/podman-network.1.md21
-rw-r--r--docs/podman-play-kube.1.md2
-rw-r--r--docs/podman-pull.1.md2
-rw-r--r--docs/podman-push.1.md2
-rw-r--r--docs/podman-run.1.md24
-rw-r--r--docs/podman-search.1.md2
-rw-r--r--docs/podman.1.md11
-rw-r--r--docs/tutorials/README.md4
-rw-r--r--docs/tutorials/rootless_tutorial.md4
-rw-r--r--go.mod9
-rw-r--r--go.sum12
-rwxr-xr-xhack/get_ci_vm.sh3
-rw-r--r--install.md8
-rw-r--r--libpod/container.go3
-rw-r--r--libpod/container_api.go5
-rw-r--r--libpod/container_internal.go18
-rw-r--r--libpod/container_internal_linux.go44
-rw-r--r--libpod/define/errors.go4
-rw-r--r--libpod/driver/driver.go4
-rw-r--r--libpod/events/config.go10
-rw-r--r--libpod/events/journal_linux.go41
-rw-r--r--libpod/events/logfile.go5
-rw-r--r--libpod/events/nullout.go8
-rw-r--r--libpod/image/docker_registry_options.go7
-rw-r--r--libpod/image/image.go6
-rw-r--r--libpod/image/image_test.go11
-rw-r--r--libpod/info.go2
-rw-r--r--libpod/oci.go2
-rw-r--r--libpod/oci_internal_linux.go58
-rw-r--r--libpod/options.go27
-rw-r--r--libpod/pod.go2
-rw-r--r--libpod/runtime.go96
-rw-r--r--libpod/runtime_ctr.go10
-rw-r--r--libpod/runtime_img.go7
-rw-r--r--libpod/runtime_pod_infra_linux.go6
-rw-r--r--libpod/runtime_pod_linux.go4
-rw-r--r--libpod/util_linux.go11
-rw-r--r--pkg/adapter/checkpoint_restore.go3
-rw-r--r--pkg/adapter/client.go3
-rw-r--r--pkg/adapter/containers.go3
-rw-r--r--pkg/adapter/network.go147
-rw-r--r--pkg/adapter/pods.go15
-rw-r--r--pkg/adapter/runtime.go31
-rw-r--r--pkg/adapter/runtime_remote.go34
-rw-r--r--pkg/cgroups/cgroups.go73
-rw-r--r--pkg/cgroups/systemd.go23
-rw-r--r--pkg/hooks/hooks.go3
-rw-r--r--pkg/namespaces/namespaces.go87
-rw-r--r--pkg/network/config.go4
-rw-r--r--pkg/network/network.go26
-rw-r--r--pkg/rootless/rootless_linux.c14
-rw-r--r--pkg/spec/createconfig.go9
-rw-r--r--pkg/spec/spec.go37
-rw-r--r--pkg/spec/storage.go40
-rw-r--r--pkg/util/mountOpts.go3
-rw-r--r--pkg/util/utils.go35
-rw-r--r--pkg/util/utils_supported.go36
-rw-r--r--pkg/util/utils_windows.go15
-rw-r--r--pkg/varlinkapi/containers.go9
-rw-r--r--pkg/varlinkapi/images.go11
-rw-r--r--pkg/varlinkapi/system.go1
-rw-r--r--test/e2e/checkpoint_test.go28
-rw-r--r--test/e2e/common_test.go2
-rw-r--r--test/e2e/cp_test.go36
-rw-r--r--test/e2e/create_test.go23
-rw-r--r--test/e2e/events_test.go22
-rw-r--r--test/e2e/exec_test.go4
-rw-r--r--test/e2e/libpod_suite_remoteclient_test.go7
-rw-r--r--test/e2e/libpod_suite_test.go7
-rw-r--r--test/e2e/login_logout_test.go4
-rw-r--r--test/e2e/network_test.go158
-rw-r--r--test/e2e/pause_test.go12
-rw-r--r--test/e2e/play_kube_test.go76
-rw-r--r--test/e2e/pod_infra_container_test.go20
-rw-r--r--test/e2e/port_test.go38
-rw-r--r--test/e2e/run_cpu_test.go110
-rw-r--r--test/e2e/run_dns_test.go7
-rw-r--r--test/e2e/run_exit_test.go4
-rw-r--r--test/e2e/run_memory_test.go38
-rw-r--r--test/e2e/run_selinux_test.go12
-rw-r--r--test/e2e/run_test.go93
-rw-r--r--test/e2e/run_volume_test.go18
-rw-r--r--test/e2e/start_test.go4
-rw-r--r--test/system/001-basic.bats8
-rw-r--r--test/system/030-run.bats13
-rw-r--r--test/system/055-rm.bats42
-rw-r--r--test/system/070-build.bats6
-rw-r--r--test/system/200-pod-top.bats5
-rw-r--r--test/system/README.md2
-rw-r--r--test/system/helpers.bash21
-rw-r--r--troubleshooting.md78
-rw-r--r--vendor/github.com/containers/buildah/.golangci.yml2
-rw-r--r--vendor/github.com/containers/buildah/CHANGELOG.md191
-rw-r--r--vendor/github.com/containers/buildah/Makefile21
-rw-r--r--vendor/github.com/containers/buildah/buildah.go2
-rw-r--r--vendor/github.com/containers/buildah/changelog.txt26
-rw-r--r--vendor/github.com/containers/buildah/chroot/run.go16
-rw-r--r--vendor/github.com/containers/buildah/config.go10
-rw-r--r--vendor/github.com/containers/buildah/go.mod28
-rw-r--r--vendor/github.com/containers/buildah/go.sum59
-rw-r--r--vendor/github.com/containers/buildah/install.md2
-rw-r--r--vendor/github.com/containers/buildah/new.go4
-rw-r--r--vendor/github.com/containers/buildah/ostree_tag.sh2
-rw-r--r--vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go4
-rw-r--r--vendor/github.com/containers/buildah/pkg/cli/common.go8
-rw-r--r--vendor/github.com/containers/buildah/pkg/overlay/overlay.go73
-rw-r--r--vendor/github.com/containers/buildah/pkg/parse/parse.go18
-rw-r--r--vendor/github.com/containers/buildah/troubleshooting.md36
-rw-r--r--vendor/github.com/containers/buildah/util.go9
-rw-r--r--vendor/github.com/containers/image/docker/docker_client.go9
-rw-r--r--vendor/github.com/containers/image/ostree/ostree_src.go16
-rw-r--r--vendor/github.com/containers/image/pkg/docker/config/config.go34
-rw-r--r--vendor/github.com/containers/image/pkg/docker/config/config_linux.go79
-rw-r--r--vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go16
-rw-r--r--vendor/github.com/containers/image/pkg/keyctl/key.go64
-rw-r--r--vendor/github.com/containers/image/pkg/keyctl/keyring.go79
-rw-r--r--vendor/github.com/containers/image/pkg/keyctl/perm.go33
-rw-r--r--vendor/github.com/containers/image/pkg/keyctl/sys_linux.go25
-rw-r--r--vendor/github.com/containers/image/pkg/sysregistries/system_registries.go103
-rw-r--r--vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go22
-rw-r--r--vendor/github.com/containers/image/signature/policy_types.go2
-rw-r--r--vendor/github.com/containers/image/transports/alltransports/alltransports.go2
-rw-r--r--vendor/github.com/containers/image/version/version.go4
-rw-r--r--vendor/github.com/containers/storage/Makefile18
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/btrfs.go12
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/version.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/version_none.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/device_setup.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/deviceset.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/devmapper_doc.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/driver.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/mount.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/fsdiff.go1
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go53
-rw-r--r--vendor/github.com/containers/storage/drivers/quota/projectquota.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/register/register_devicemapper.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/register/register_overlay.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/vfs/driver.go12
-rw-r--r--vendor/github.com/containers/storage/drivers/windows/windows.go10
-rw-r--r--vendor/github.com/containers/storage/ffjson_deps.go10
-rw-r--r--vendor/github.com/containers/storage/go.mod2
-rw-r--r--vendor/github.com/containers/storage/layers.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/idtools/idtools.go11
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/ioctl.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/loop_wrapper.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/loopback.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/loopback_unsupported.go1
-rw-r--r--vendor/github.com/containers/storage/pkg/ostree/no_ostree.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/ostree/ostree.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go48
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go18
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go14
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go13
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/decoder.go323
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/decoder_tpl.go773
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/encoder.go544
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/encoder_tpl.go73
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/inception.go160
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/reflect.go290
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/tags.go79
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/template.go60
-rw-r--r--vendor/github.com/pquerna/ffjson/inception/writerstack.go65
-rw-r--r--vendor/github.com/pquerna/ffjson/shared/options.go51
-rw-r--r--vendor/modules.txt16
-rw-r--r--version/version.go2
240 files changed, 6716 insertions, 750 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 8389c638d..5a9dbcb54 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -28,11 +28,13 @@ env:
TIMESTAMP: "awk --file ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/timestamp.awk"
####
- #### Cache-image names to test with
+ #### Cache-image names to test with (double-quotes around names are critical)
###
- FEDORA_CACHE_IMAGE_NAME: "fedora-30-libpod-5479475851034624"
- PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5479475851034624"
- UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5479475851034624"
+ _BUILT_IMAGE_SUFFIX: "libpod-5751722641719296"
+ FEDORA_CACHE_IMAGE_NAME: "fedora-30-${_BUILT_IMAGE_SUFFIX}"
+ PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-${_BUILT_IMAGE_SUFFIX}"
+ SPECIAL_FEDORA_CACHE_IMAGE_NAME: "xfedora-30-${_BUILT_IMAGE_SUFFIX}"
+ UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-${_BUILT_IMAGE_SUFFIX}"
####
#### Variables for composing new cache-images (used in PR testing) from
@@ -47,6 +49,7 @@ env:
####
SPECIALMODE: "none" # don't do anything special
TEST_REMOTE_CLIENT: false # don't test remote client by default
+ ADD_SECOND_PARTITION: false # will certainly fail inside containers
####
#### Credentials and other secret-sauces, decrypted at runtime when authorized.
@@ -90,8 +93,8 @@ gating_task:
timeout_in: 20m
- networking_script: # Don't bother going further if something is down
- - 'while read host port; do nc -zv -w 13 $host $port || exit 1; done < ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/required_host_ports.txt'
+ # Don't bother going further if something is down
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
gate_script:
# N/B: entrypoint.sh resets $GOSRC (same as make clean)
@@ -261,6 +264,7 @@ meta_task:
IMGNAMES: >-
${FEDORA_CACHE_IMAGE_NAME}
${PRIOR_FEDORA_CACHE_IMAGE_NAME}
+ ${SPECIAL_FEDORA_CACHE_IMAGE_NAME}
${UBUNTU_CACHE_IMAGE_NAME}
${IMAGE_BUILDER_CACHE_IMAGE_NAME}
BUILDID: "${CIRRUS_BUILD_ID}"
@@ -285,7 +289,7 @@ image_prune_task:
- "meta"
container:
- image: "quay.io/cevich/imgprune:latest" # see contrib/imgprune
+ image: "quay.io/libpod/imgprune:latest" # see contrib/imgprune
cpu: 1
memory: 1
@@ -322,10 +326,12 @@ testing_task:
timeout_in: 120m
env:
+ ADD_SECOND_PARTITION: true
matrix:
TEST_REMOTE_CLIENT: true
TEST_REMOTE_CLIENT: false
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}'
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
@@ -343,6 +349,41 @@ testing_task:
audit_log_script: '$SCRIPT_BASE/logcollector.sh audit'
journal_script: '$SCRIPT_BASE/logcollector.sh journal'
+# Test crun only on latest Fedora
+testing_crun_task:
+
+ depends_on:
+ - "gating"
+ - "vendor"
+ - "varlink_api"
+ - "build_each_commit"
+ - "build_without_cgo"
+
+ # Only test build cache-images, if that's what's requested
+ only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
+
+ timeout_in: 120m
+
+ env:
+ ADD_SECOND_PARTITION: true
+ OCI_RUNTIME: "/usr/bin/crun"
+
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
+ setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
+ install_crun_script: 'dnf install -y crun'
+ unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}'
+ integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
+ system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
+ cache_release_archive_script: >-
+ [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \
+ $SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP}
+
+ on_failure:
+ failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
+
+ always:
+ <<: *standardlogs
+
# This task executes tests under unique environments/conditions
special_testing_rootless_task:
@@ -357,14 +398,15 @@ special_testing_rootless_task:
only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
env:
+ ADD_SECOND_PARTITION: true
SPECIALMODE: 'rootless' # See docs
-
matrix:
TEST_REMOTE_CLIENT: true
TEST_REMOTE_CLIENT: false
timeout_in: 60m
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
@@ -388,10 +430,12 @@ special_testing_in_podman_task:
only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
env:
+ ADD_SECOND_PARTITION: true
SPECIALMODE: 'in_podman' # See docs
timeout_in: 60m
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
@@ -418,6 +462,7 @@ special_testing_cross_task:
timeout_in: 20m
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
cache_release_archive_script: '$SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP}'
@@ -425,6 +470,37 @@ special_testing_cross_task:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
+special_testing_cgroupv2_task:
+
+ depends_on:
+ - "gating"
+ - "varlink_api"
+ - "vendor"
+
+ only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
+
+ gce_instance:
+ image_name: "${SPECIAL_FEDORA_CACHE_IMAGE_NAME}"
+
+ env:
+ SPECIALMODE: 'cgroupv2' # See docs
+ matrix:
+ TEST_REMOTE_CLIENT: true
+ TEST_REMOTE_CLIENT: false
+
+ timeout_in: 20m
+
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
+ setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
+ integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
+
+ on_failure:
+ failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
+
+ always:
+ <<: *standardlogs
+
+
# Test building of new cache-images for future PR testing, in this PR.
test_build_cache_images_task:
@@ -450,7 +526,8 @@ test_build_cache_images_task:
- compute
- devstorage.full_control
- environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
+ setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
build_vm_images_script: '$SCRIPT_BASE/build_vm_images.sh |& ${TIMESTAMP}'
df_script: '${DFCMD}'
journalctl_b_script: 'journalctl -b'
@@ -474,24 +551,36 @@ verify_test_built_images_task:
- "test_build_cache_images"
gce_instance:
- matrix:
- # Images are generated separately, from build_images_task (below)
- image_name: "fedora-29${BUILT_IMAGE_SUFFIX}"
- image_name: "fedora-30${BUILT_IMAGE_SUFFIX}"
- image_name: "ubuntu-18${BUILT_IMAGE_SUFFIX}"
+ # Images generated by test_build_cache_images_task (above)
+ image_name: "${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}"
env:
+ ADD_SECOND_PARTITION: true
matrix:
TEST_REMOTE_CLIENT: true
TEST_REMOTE_CLIENT: false
+ matrix:
+ # Required env. var. by check_image_script
+ PACKER_BUILDER_NAME: "fedora-29"
+ PACKER_BUILDER_NAME: "fedora-30"
+ PACKER_BUILDER_NAME: "xfedora-30"
+ PACKER_BUILDER_NAME: "ubuntu-18"
+ networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
+ environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
+ # Verify expectations once per image
+ check_image_script: >-
+ [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \
+ $SCRIPT_BASE/check_image.sh |& ${TIMESTAMP}
# Note: A truncated form of normal testing. It only needs to confirm new images
# "probably" work. A full round of testing will happen again after $*_CACHE_IMAGE_NAME
# are updated in this or another PR (w/o '***CIRRUS: TEST IMAGES***').
- environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
- check_image_script: '$SCRIPT_BASE/check_image.sh'
- integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
- system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
+ integration_test_script: >-
+ [[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \
+ $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}
+ system_test_script: >-
+ [[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \
+ $SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}
always:
<<: *standardlogs
@@ -513,8 +602,10 @@ success_task:
- "meta"
- "image_prune"
- "testing"
+ - "testing_crun"
- "special_testing_rootless"
- "special_testing_in_podman"
+ - "special_testing_cgroupv2"
- "special_testing_cross"
- "test_build_cache_images"
- "verify_test_built_images"
@@ -551,8 +642,10 @@ release_task:
- "meta"
- "image_prune"
- "testing"
+ - "testing_crun"
- "special_testing_rootless"
- "special_testing_in_podman"
+ - "special_testing_cgroupv2"
- "special_testing_cross"
- "test_build_cache_images"
- "verify_test_built_images"
diff --git a/API.md b/API.md
index 2dfb19b3c..8d53a77d3 100755
--- a/API.md
+++ b/API.md
@@ -265,6 +265,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[error ErrCtrStopped](#ErrCtrStopped)
+[error ErrRequiresCgroupsV2ForRootless](#ErrRequiresCgroupsV2ForRootless)
+
[error ErrorOccurred](#ErrorOccurred)
[error ImageNotFound](#ImageNotFound)
@@ -1501,6 +1503,8 @@ publish [?[]string](#?[]string)
publishAll [?bool](#?bool)
+pull [?string](#?string)
+
quiet [?bool](#?bool)
readonly [?bool](#?bool)
@@ -1721,6 +1725,8 @@ 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
@@ -2002,6 +2008,9 @@ ContainerNotFound means the container could not be found by the provided name or
### <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
diff --git a/Makefile b/Makefile
index 29eb9b3af..c4b66e261 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ export GO111MODULE=off
GO ?= go
DESTDIR ?=
-EPOCH_TEST_COMMIT ?= 55e028a12ee003e057c65e376fe4b723d28ae52e
+EPOCH_TEST_COMMIT ?= b9a176bea94b8e3a97a70dd7cd599f1a057777b0
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
@@ -20,6 +20,7 @@ SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers
ETCDIR ?= /etc
TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d
SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system
+USERSYSTEMDDIR ?= ${PREFIX}/lib/systemd/user
BUILDFLAGS ?=
BUILDTAGS ?= \
$(shell hack/apparmor_tag.sh) \
@@ -253,10 +254,34 @@ remoteintegration: varlink_generate test-binaries ginkgo-remote
localsystem:
# Wipe existing config, database, and cache: start with clean slate.
$(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers
- if timeout -v 1 true; then PODMAN=./bin/podman bats test/system/; else echo "Skipping localsystem: 'timeout -v' unavailable'"; fi
+ if timeout -v 1 true; then PODMAN=./bin/podman bats test/system/; else echo "Skipping $@: 'timeout -v' unavailable'"; fi
remotesystem:
- @echo "remotesystem - unimplemented"
+ # Wipe existing config, database, and cache: start with clean slate.
+ $(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers
+ # Start varlink server using tmp socket; loop-wait for it;
+ # test podman-remote; kill server, clean up tmp socket file.
+ # varlink server spews copious unhelpful output; ignore it.
+ rc=0;\
+ if timeout -v 1 true; then \
+ SOCK_FILE=$(shell mktemp --dry-run --tmpdir io.podman.XXXXXX);\
+ export PODMAN_VARLINK_ADDRESS=unix:$$SOCK_FILE; \
+ ./bin/podman varlink --timeout=0 $$PODMAN_VARLINK_ADDRESS &>/dev/null & \
+ retry=5;\
+ while [[ $$retry -ge 0 ]]; do\
+ echo Waiting for varlink server...;\
+ sleep 1;\
+ ./bin/podman-remote info &>/dev/null && break;\
+ retry=$$(expr $$retry - 1);\
+ done;\
+ env PODMAN=./bin/podman-remote bats test/system/ ;\
+ rc=$$?;\
+ kill %1;\
+ rm -f $$SOCK_FILE;\
+ else \
+ echo "Skipping $@: 'timeout -v' unavailable'";\
+ fi;\
+ exit $$rc
system.test-binary: .install.ginkgo
$(GO) test -c ./test/system
@@ -311,6 +336,7 @@ brew-pkg: install-podman-remote-docs podman-remote-darwin
@cp ./bin/podman-remote-darwin ./brew/podman
@cp -r ./docs/remote ./brew/docs/
@cp docs/podman-remote.1 ./brew/docs/podman.1
+ @cp docs/podman-remote.conf.5 ./brew/docs/podman-remote.conf.5
@sed -i 's/podman\\*-remote/podman/g' ./brew/docs/podman.1
@sed -i 's/Podman\\*-remote/Podman\ for\ Mac/g' ./brew/docs/podman.1
@sed -i 's/podman\.conf/podman\-remote\.conf/g' ./brew/docs/podman.1
@@ -333,12 +359,12 @@ changelog: ## Generate changelog
install: .gopathok install.bin install.remote install.man install.cni install.systemd ## Install binaries to system locations
-install.remote:
+install.remote: podman-remote
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR)
install ${SELINUXOPT} -m 755 bin/podman-remote $(DESTDIR)$(BINDIR)/podman-remote
test -z "${SELINUXOPT}" || chcon --verbose --reference=$(DESTDIR)$(BINDIR)/podman bin/podman-remote
-install.bin:
+install.bin: podman
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR)
install ${SELINUXOPT} -m 755 bin/podman $(DESTDIR)$(BINDIR)/podman
test -z "${SELINUXOPT}" || chcon --verbose --reference=$(DESTDIR)$(BINDIR)/podman bin/podman
@@ -371,9 +397,11 @@ install.docker: docker-docs
install ${SELINUXOPT} -m 644 docs/docker*.1 -t $(DESTDIR)$(MANDIR)/man1
install.systemd:
- install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${TMPFILESDIR}
+ install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} ${DESTDIR}${TMPFILESDIR}
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
+ install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.service ${DESTDIR}${USERSYSTEMDDIR}/io.podman.service
install ${SELINUXOPT} -m 644 contrib/varlink/podman.conf ${DESTDIR}${TMPFILESDIR}/podman.conf
uninstall:
diff --git a/README.md b/README.md
index e22c35d4f..e9cedc989 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`
* [Latest Version: 1.4.4](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
+* [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod)
## Overview and scope
@@ -41,6 +42,8 @@ If you run Podman as your user and mount in `/etc/passwd` from the host, you sti
Almost all normal Podman functionality is available, though there are some [shortcomings](https://github.com/containers/libpod/blob/master/rootless.md).
Any recent Podman release should be able to run rootless without any additional configuration, though your operating system may require some additional configuration detailed in the [install guide](https://github.com/containers/libpod/blob/master/install.md).
+A little configuration by an administrator is required before rootless Podman can be used, the necessary setup is documented [here](https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md).
+
## Out of scope
* Specializing in signing and pushing images to various storage backends.
@@ -101,6 +104,9 @@ Tutorials on using Podman.
**[Remote Client](remote_client.md)**
A brief how-to on using the Podman remote-client.
+**[Basic Setup and Use of Podman in a Rootless environment](https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md)
+A tutorial showing the setup and configuration necessary to run Rootless Podman.
+
**[Release Notes](RELEASE_NOTES.md)**
Release notes for recent Podman versions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 69244bb09..3cfd8ed86 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,86 @@
# Release Notes
+## 1.5.1
+### Features
+- The hostname of pods is now set to the pod's name
+
+### Bugfixes
+- Fixed a bug where `podman run` and `podman create` did not honor the `--authfile` option ([#3730](https://github.com/containers/libpod/issues/3730))
+- Fixed a bug where containers restored with `podman container restore --import` would incorrectly duplicate the Conmon PID file of the original container
+- Fixed a bug where `podman build` ignored the default OCI runtime configured in `libpod.conf`
+- Fixed a bug where `podman run --rm` (or force-removing any running container with `podman rm --force`) were not retrieving the correct exit code ([#3795](https://github.com/containers/libpod/issues/3795))
+- Fixed a bug where Podman would exit with an error if any configured hooks directory was not present
+- Fixed a bug where `podman inspect` and `podman commit` would not use the correct `CMD` for containers run with `podman play kube`
+- Fixed a bug created pods when using rootless Podman and CGroups V2 ([#3801](https://github.com/containers/libpod/issues/3801))
+- Fixed a bug where the `podman events` command with the `--since` or `--until` options could take a very long time to complete
+
+### Misc
+- Rootless Podman will now inherit OCI runtime configuration from the root configuration ([#3781](https://github.com/containers/libpod/issues/3781))
+- Podman now properly sets a user agent while contacting registries ([#3788](https://github.com/containers/libpod/issues/3788))
+
+## 1.5.0
+### Features
+- Podman containers can now join the user namespaces of other containers with `--userns=container:$ID`, or a user namespace at an arbitary path with `--userns=ns:$PATH`
+- Rootless Podman can experimentally squash all UIDs and GIDs in an image to a single UID and GID (which does not require use of the `newuidmap` and `newgidmap` executables) by passing `--storage-opt ignore_chown_errors`
+- The `podman generate kube` command now produces YAML for any bind mounts the container has created ([#2303](https://github.com/containers/libpod/issues/2303))
+- The `podman container restore` command now features a new flag, `--ignore-static-ip`, that can be used with `--import` to import a single container with a static IP multiple times on the same host
+- Added the ability for `podman events` to output JSON by specifying `--format=json`
+- If the OCI runtime or `conmon` binary cannot be found at the paths specified in `libpod.conf`, Podman will now also search for them in the calling user's path
+- Added the ability to use `podman import` with URLs ([#3609](https://github.com/containers/libpod/issues/3609))
+- The `podman ps` command now supports filtering names using regular expressions ([#3394](https://github.com/containers/libpod/issues/3394))
+- Rootless Podman containers with `--privileged` set will now mount in all host devices that the user can access
+- The `podman create` and `podman run` commands now support the `--env-host` flag to forward all environment variables from the host into the container
+- Rootless Podman now supports healthchecks ([#3523](https://github.com/containers/libpod/issues/3523))
+- The format of the `HostConfig` portion of the output of `podman inspect` on containers has been improved and synced with Docker
+- Podman containers now support CGroup namespaces, and can create them by passing `--cgroupns=private` to `podman run` or `podman create`
+- The `podman create` and `podman run` commands now support the `--ulimit=host` flag, which uses any ulimits currently set on the host for the container
+- The `podman rm` and `podman rmi` commands now use different exit codes to indicate 'no such container' and 'container is running' errors
+- Support for CGroups V2 through the `crun` OCI runtime has been greatly improved, allowing resource limits to be set for rootless containers when the CGroups V2 hierarchy is in use
+
+### Bugfixes
+- Fixed a bug where a race condition could cause `podman restart` to fail to start containers with ports
+- Fixed a bug where containers restored from a checkpoint would not properly report the time they were started at
+- Fixed a bug where `podman search` would return at most 25 results, even when the maximum number of results was set higher
+- Fixed a bug where `podman play kube` would not honor capabilities set in imported YAML ([#3689](https://github.com/containers/libpod/issues/3689))
+- Fixed a bug where `podman run --env`, when passed a single key (to use the value from the host), would set the environment variable in the container even if it was not set on the host ([#3648](https://github.com/containers/libpod/issues/3648))
+- Fixed a bug where `podman commit --changes` would not properly set environment variables
+- Fixed a bug where Podman could segfault while working with images with no history
+- Fixed a bug where `podman volume rm` could remove arbitrary volumes if given an ambiguous name ([#3635](https://github.com/containers/libpod/issues/3635))
+- Fixed a bug where `podman exec` invocations leaked memory by not cleaning up files in tmpfs
+- Fixed a bug where the `--dns` and `--net=container` flags to `podman run` and `podman create` were not mutually exclusive ([#3553](https://github.com/containers/libpod/issues/3553))
+- Fixed a bug where rootless Podman would be unable to run containers when less than 5 UIDs were available
+- Fixed a bug where containers in pods could not be removed without removing the entire pod ([#3556](https://github.com/containers/libpod/issues/3556))
+- Fixed a bug where Podman would not properly clean up all CGroup controllers for created cgroups when using the `cgroupfs` CGroup driver
+- Fixed a bug where Podman containers did not properly clean up files in tmpfs, resulting in a memory leak as containers stopped
+- Fixed a bug where healthchecks from images would not use default settings for interval, retries, timeout, and start period when they were not provided by the image ([#3525](https://github.com/containers/libpod/issues/3525))
+- Fixed a bug where healthchecks using the `HEALTHCHECK CMD` format where not properly supported ([#3507](https://github.com/containers/libpod/issues/3507))
+- Fixed a bug where volume mounts using relative source paths would not be properly resolved ([#3504](https://github.com/containers/libpod/issues/3504))
+- Fixed a bug where `podman run` did not use authorization credentials when a custom path was specified ([#3524](https://github.com/containers/libpod/issues/3524))
+- Fixed a bug where containers checkpointed with `podman container checkpoint` did not properly set their finished time
+- Fixed a bug where running `podman inspect` on any container not created with `podman run` or `podman create` (for example, pod infra containers) would result in a segfault ([#3500](https://github.com/containers/libpod/issues/3500))
+- Fixed a bug where healthcheck flags for `podman create` and `podman run` were incorrectly named ([#3455](https://github.com/containers/libpod/pull/3455))
+- Fixed a bug where Podman commands would fail to find targets if a partial ID was specified that was ambiguous between a container and pod ([#3487](https://github.com/containers/libpod/issues/3487))
+- Fixed a bug where restored containers would not have the correct SELinux label
+- Fixed a bug where Varlink endpoints were not working properly if `more` was not correctly specified
+- Fixed a bug where the Varlink PullImage endpoint would crash if an error occurred ([#3715](https://github.com/containers/libpod/issues/3715))
+- Fixed a bug where the `--mount` flag to `podman create` and `podman run` did not allow boolean arguments for its `ro` and `rw` options ([#2980](https://github.com/containers/libpod/issues/2980))
+- Fixed a bug where pods did not properly share the UTS namespace, resulting in incorrect behavior from some utilities which rely on hostname ([#3547](https://github.com/containers/libpod/issues/3547))
+- Fixed a bug where Podman would unconditionally append `ENTRYPOINT` to `CMD` during `podman commit` (and when reporting `CMD` in `podman inspect`) ([#3708](https://github.com/containers/libpod/issues/3708))
+- Fixed a bug where `podman events` with the `journald` events backend would incorrectly print 6 previous events when only new events were requested ([#3616](https://github.com/containers/libpod/issues/3616))
+- Fixed a bug where `podman port` would exit prematurely when a port number was specified ([#3747](https://github.com/containers/libpod/issues/3747))
+- Fixed a bug where passing `.` as an argument to the `--dns-search` flag to `podman create` and `podman run` was not properly clearing DNS search domains in the container
+
+### Misc
+- Updated vendored Buildah to v1.10.1
+- Updated vendored containers/image to v3.0.2
+- Updated vendored containers/storage to v1.13.1
+- Podman now requires conmon v2.0.0 or higher
+- The `podman info` command now displays the events logger being in use
+- The `podman inspect` command on containers now includes the ID of the pod a container has joined and the PID of the container's conmon process
+- The `-v` short flag for `podman --version` has been re-added
+- Error messages from `podman pull` should be significantly clearer
+- The `podman exec` command is now available in the remote client
+
## 1.4.4
### Bugfixes
- Fixed a bug where rootless Podman would attempt to use the entire root configuration if no rootless configuration was present for the user, breaking rootless Podman for new installations
diff --git a/changelog.txt b/changelog.txt
index 51ac92979..b0a847aee 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,299 @@
+- Changelog for v1.5.1 (2019-08-15)
+ * Add release notes for v1.5.1
+ * Set Pod hostname as Pod name
+ * tests for exit status on podman run --rm
+ * performance fix for podman events with large journalds
+ * pkg/cgroups: use DBUS session when rootless
+ * Fix play kube command in pod yaml
+ * removMergeDir from inspect result if not mounted
+ * Running Podman with a nonexistent hooks dir is nonfatal
+ * Cirrus: Install varlink on Ubuntu
+ * Cirrus: Install varlink on Fedora
+ * Add missing stage-packages in snapcraft.yaml.
+ * Add RHEL and SUSE to snap doc
+ * start groundwork for adding snap
+ * Add user systemd service and socket
+ * Small optimization - only store exit code when nonzero
+ * Fix container exit code with Journald backend
+ * Revert "Cirrus: Temp. workaround missing imgprune image"
+ * Homebrew installation in install.md
+ * varlink endpoint for containerstats requires root
+ * Adjust get_ci_vm.sh for substitution
+ * Cirrus: Add verification for cgroupv2 image
+ * Cirrus: Add experimental fedora VM image & test
+ * image: add user agent to Docker registry options
+ * Cirrus: Minor, use newer Ubuntu base image
+ * tests: disable some tests currently failing when not using runc
+ * containers: look also for 'file not found' in the error message
+ * cirrus: add tests with crun on Fedora 30
+ * rootless: cherry-pick runtime from the system configuration
+ * cirrus: install crun
+ * cmd: drop check for euid==0
+ * storage: drop unused geteuid check
+ * cmd, stats: fix check for rootless mode
+ * oci: drop check for euid==0
+ * build: use the configured runtime
+ * Adjust read count so that a newline can be added afterwards
+ * Fix incorrect use of realloc()
+ * Bump gitvalidation epoch
+ * Bump to v1.5.1-dev
+ * Fix a couple of errors descovered by coverity
+ * Test that restored container does not depend on the original container
+ * Fix up ConmonPidFile after restore
+ * Cirrus: Enable updates-testing repo for Fedora
+ * enable windows remote client
+ * implement 'make remotesystem'
+ * Squish a few tpyo nits in container.go doc
+ * Cirrus: Add Second partition for storage testing
+
+- Changelog for v1.5.0 (2019-08-09)
+ * vendor github.com/containers/storage@v1.13.2
+ * Improve dns-search validation, empty domains now return an error
+ * fix create&run getting --authfile from cli
+ * Add release notes for v1.5.0
+ * Touch up build man page
+ * podman-container-runlabel(1): drop note
+ * make rmi messages more compatible with docker
+ * Add conmon probe to runtime construction
+ * fix copy change file owner if cp from container
+ * Vendor Buildah 1.10.1
+ * Allow the passing of '.' to --dns-search
+ * add make to make installs
+ * namespaces: fix Container() call
+ * Add a test for verifying ENTRYPOINT and CMD
+ * fix port early return
+ * Allow --ro=[true|false] with mount flag
+ * refer to container whose namespace we share
+ * add test to verify hostname is shared in a pod
+ * Properly share UTS namespaces in a pod
+ * When populating CMD, do not include Entrypoint
+ * systemd library conflict with seektail and addmatch
+ * pod top test: reenable
+ * cgroup: fix regression when running systemd
+ * Add invalid credentials fix to docs
+ * Revert "rootless: Rearrange setup of rootless containers"
+ * restore: correctly set StartedTime
+ * container stop: kill conmon
+ * honor libpod.conf in /usr/share/containers
+ * fix system df crashes on unnamed images
+ * Don't log errors to the screen when XDG_RUNTIME_DIR is not set
+ * various fixes for varlink endpoints
+ * add eventlogger to info
+ * Add handling for empty LogDriver
+ * Add rootless NFS and OverlayFS warnings to docs
+ * podman events format json
+ * add godoc link to readme
+ * restore: added --ignore-static-ip option
+ * System tests: resolve hang in rawhide rootless
+ * fix search output limit
+ * Add capability functionality to play kube
+ * Use "none" instead of "null" for the null eventer
+ * Deduplicate capabilities in generate kube
+ * Fix typo
+ * Pass on events-backend config to cleanup processes
+ * Print Pod ID in `podman inspect` output
+ * go build: use `-mod=vendor` for go >= 1.11.x
+ * Use buildah/pkg/parse volume parsing rather then internal version
+ * github.com/containers/storage v1.12.13
+ * Add new exit codes to rm & rmi for running containers & dependencies
+ * Add runtime and conmon path discovery
+ * systemd, cgroupsv2: not bind mount /sys/fs/cgroup/systemd
+ * Ensure we generate a 'stopped' event on force-remove
+ * Fix Dockerfile - a dependency's name was changed
+ * System events are valid, don't error on them
+ * Do not use an events backend when restoring images
+ * Expose Null eventer and allow its use in the Podman CLI
+ * Force tests to use file backend for events
+ * Add a flag to set events logger type
+ * Fix test suite
+ * Retrieve exit codes for containers via events
+ * podman: fix memleak caused by renaming and not deleting the exit file
+ * Cirrus: Fix release dependencies
+ * Cirrus: Fix re-run of release task into no-op.
+ * e2e test: check exit codes for pull, save, inspect
+ * rootless: Rearrange setup of rootless containers
+ * Add comment to describe postConfigureNetNS
+ * Vendor in buildah 1.9.2
+ * Build fix for 32-bit systems.
+ * Set -env variables as appropriate
+ * Touch up input argument error on create
+ * Update libpod.conf to be NixOS friendly
+ * Allow info test to work with usernames w/dash
+ * Touch up XDG, add rootless links
+ * Fix the syntax in the podman export documentation example
+ * fix `podman -v` regression
+ * Move random IP code for tests from checkpoint to common
+ * Fix commit --changes env=X=Y
+ * Update pause/unpause video links and demo
+ * Cirrus: Remove fixed clone depth
+ * podman: support --userns=ns|container
+ * pods: do not to join a userns if there is not any
+ * Documenation & build automation for remote darwin
+ * Cirrus: Bypass release during image-building
+ * Use systemd cgroups for Ubuntu
+ * Cirrus: Ubuntu: Set + Test for $RUNC_BINARY
+ * Cirrus: Simplify evil-unit check in image
+ * Cirrus: Silence systemd-banish noise
+ * Cirrus: Fix image build metadata update
+ * Cirrus: Fix missing -n on CentOS
+ * Cirrus: Remove disused COMMIT variables
+ * Improved hooks monitoring
+ * Fix possible runtime panic if image history len is zero
+ * When retrieving volumes, only use exact names
+ * fix import not ignoring url path
+ * Document SELinux label requirements for the rootfs argument
+ * Fixes issue #3577.
+ * refactor to reduce duplicated error parsing
+ * remove debug prints
+ * Re-add int64 casts for ctime
+ * fix build --network=container
+ * Fix a segfault on Podman no-store commands with refresh
+ * always send generic error in case io fails
+ * only use stdin if specified
+ * buffer errChan
+ * move handleTerminalAttach to generic build
+ * remove unnecessary conversions
+ * add detach keys support for remote
+ * move editing of exitCode to runtime
+ * Update e2e tests for remote exec
+ * Finish up remote exec implementation
+ * golangci-lint cleanup
+ * install.md: mention all build tags
+ * golangci-lint phase 4
+ * Change wait to sleep in podmanimage readme
+ * bump cirrus images to get new conmon
+ * Implement conmon exec
+ * bump conmon to 1.0.0-rc2
+ * Cirrus: Temp. workaround missing imgprune image
+ * vendor github.com/containers/image@v2.0.1
+ * golangci-lint round #3
+ * Remove debug message
+ * Cleanup Pull Message
+ * Cirrus: Fix post-merge env. var. not set.
+ * mkdir -p /etc/cni/net.d requires sudo
+ * Add support for listing read/only and read/write images
+ * support podman ps filter regular expressions
+ * rootless: add rw devices with --privileged
+ * Cirrus: Minor scripting typo fix
+ * fix --dns* and --network not set to host conflict
+ * podman-remote make --size optional in ps
+ * Remove exec PID files after use to prevent memory leaks
+ * Add DefaultContent API to retrieve apparmor profile content
+ * libpod: support for cgroup namespace
+ * Make GOPATH-related symlinking more precise
+ * Populate inspect with security-opt settings
+ * Properly retrieve Conmon PID
+ * Move the HostConfig portion of Inspect inside libpod
+ * Fix play kube command
+ * spec: rework --ulimit host
+ * Cirrus: Add image-test for locked dpkg
+ * Cirrus: Use images w/o periodic svcs
+ * Cirrus: Disable most periodic services/timers
+ * dependency/analyses: simplify scripts
+ * dependency-tree analysis: direct and transitive
+ * analyses: README: consistent code examples
+ * analyses: README: fix typos
+ * analyses: add dependency-tree.sh
+ * analyses: add README.md
+ * hack/analyses -> dependencies/analyses
+ * hack/analyses/go-archive-analysis.sh: fix sorting
+ * add hack/analyses/nm-symbols-analysis.sh
+ * analyse package sizes
+ * Completion: complete "--health-start-period" in bash
+ * Make the healthcheck flags compatible with Docker CLI
+ * healthcheck: reject empty commands
+ * create: ignore check if image has HEALTHCHECK NONE
+ * create: apply defaults on image healthcheck options
+ * healthcheck: improve command list parser
+ * Completion: --no-healthcheck is not an option
+ * Cirrus: Abstract destination branch refs.
+ * Cirrus: Print images that should be pruned
+ * create: improve parser for --healthcheck-command
+ * Improves STD output/readability in combination with debug output.
+ * Fix the double replySendFile()
+ * Cirrus: Update to freshly built cache-images
+ * Cirrus: Execute system-tests during image-validation
+ * Cirrus: Fix missing removal of packaged podman
+ * cgroupsv2: do not enable controllers for the last component
+ * spec: fix userns with less than 5 gids
+ * Fix spelling mistakes in man pages and other docs
+ * Add glob parsing for --env flag
+ * Add support for -env-host
+ * cgroups: fix a leak when using cgroupfs
+ * cgroups: attempt a recursive rmdir
+ * Fix a bug where ctrs could not be removed from pods
+ * golangci-lint pass number 2
+ * Add tests for --ignore-rootfs checkpoint/restore option
+ * Add --ignore-rootfs option for checkpoint/restore
+ * Fix typo in checkpoint/restore related texts
+ * Include root file-system changes in container migration
+ * Add function to get a filtered tarstream diff
+ * Correctly set FinishedTime for checkpointed container
+ * first pass of corrections for golangci-lint
+ * Cirrus: Fix #3543: Failure in 'release' task
+ * fix bug convert volume host path to absolute
+ * Cirrus: Fix 473d06045 / enable build_without_cgo
+ * account for varlink calls that dont use more
+ * runtime: drop spurious message log
+ * Ensure we have a valid store when we refresh
+ * cgroups: skip not existing cpuacct files
+ * cgroups: support creating cgroupsv2 paths
+ * make localsystem: wipe all user config state
+ * podman: create and run honors auth file location
+ * healthcheck: support rootless mode
+ * Use random IP addresses during checkpoint/restore tests
+ * Fix podman-remote usage message to display `podman-remote` instead of `podman`
+ * rootless.md: Include GPFS as a parallel filesystem
+ * speed up rootless tests
+ * podman: add --ulimit host
+ * docs: fix --healthcheck-command option
+ * code cleanup
+ * fix integration flake tests
+ * CONTRIBUTING.md: fix project paths
+ * get last container event
+ * Do not hardcode podman binary location in generate systemd.
+ * Move skipping systemd tests to early setup.
+ * Reload systemd daemon on creation of units location dir in tests.
+ * Add debug information to "generate systemd" test.
+ * Use default conmon pidfile location for root containers.
+ * Use conmon pidfile in generated systemd unit as PIDFile.
+ * Cirrus: Automate releasing of tested binaries
+ * trivial cleanups from golang
+ * ps should use nostore when possible
+ * libpod: discerne partial IDs between containers and pods
+ * Added instruction to enable the user namespaces permanenty in Manjaro
+ * Addressed code review comments
+ * Updated install.md for Manjaro Linux
+ * Vendor latest OCICNI version
+ * Bump current version in README
+ * Wipe PID and ConmonPID in state after container stops
+ * Store Conmon's PID in our state and display in inspect
+ * Restart failed containers in tests
+ * Improve parsing of mounts
+ * Add test for generate kube with volumes
+ * Bump gitvalidation epoch
+ * Bump to v1.4.5-dev
+ * Fix rootless detection error for pause & unpause
+ * Deduplicate volumes
+ * cirrus: add test for compiling without cgo
+ * lock: new lock type "file"
+ * runtime: allow to specify the lock mechanism
+ * lock: disable without cgo
+ * spec: move cgo stuff to their own file
+ * rootless: allow to build without cgo
+ * attach: move cgo bits to a different file
+ * vendor: update containers/psgo
+ * Update the testing documentation with system tests.
+ * Pass along volumes to pod yaml
+ * Configure container volumes for generate kube
+ * configure runtime without store
+ * Add RUN priv'd test for build
+ * Cirrus: Use packaged dependencies
+ * Add exec after checkpoint/restore test
+ * Provide correct SELinux mount-label for restored container
+ * Track if a container is restored from an exported checkpoint
+ * libpod/container_internal: Make all errors loading explicitly configured hook dirs fatal
+
- Changelog for v1.4.4 (2019-07-02)
* Fix release notes
* Ensure locks are freed when ctr/pod creation fails
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 37d6d3908..e7ad921da 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -258,6 +258,20 @@ type MountValues struct {
Latest bool
}
+type NetworkListValues struct {
+ PodmanCommand
+ Filter []string
+ Quiet bool
+}
+
+type NetworkRmValues struct {
+ PodmanCommand
+}
+
+type NetworkInspectValues struct {
+ PodmanCommand
+}
+
type PauseValues struct {
PodmanCommand
All bool
@@ -286,6 +300,7 @@ type PodCreateValues struct {
LabelFile []string
Labels []string
Name string
+ Hostname string
PodIDFile string
Publish []string
Share string
@@ -437,6 +452,7 @@ type RestoreValues struct {
Import string
Name string
IgnoreRootfs bool
+ IgnoreStaticIP bool
}
type RmValues struct {
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 1e9092bd6..32478bb51 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -388,6 +388,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"publish-all", "P", false,
"Publish all exposed ports to random ports on the host interface",
)
+ createFlags.String(
+ "pull", "missing",
+ `Pull image before creating ("always"|"missing"|"never") (default "missing")`,
+ )
createFlags.BoolP(
"quiet", "q", false,
"Suppress output information when pulling images",
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index bee7d2199..ad7253ac0 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -140,7 +140,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
if err != nil {
return errors.Wrapf(err, "error getting IDMappingOptions")
}
- containerOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
+ destOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
hostUID, hostGID, err := util.GetHostIDs(convertIDMap(idMappingOpts.UIDMap), convertIDMap(idMappingOpts.GIDMap), user.UID, user.GID)
if err != nil {
return err
@@ -183,6 +183,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
destPath = cleanedPath
}
} else {
+ destOwner = idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()}
if isVol, volDestName, volName := isVolumeDestName(srcPath, ctr); isVol {
path, err := pathWithVolumeMount(ctr, runtime, volDestName, volName, srcPath)
if err != nil {
@@ -230,7 +231,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
src = os.Stdin.Name()
extract = true
}
- err := copy(src, destPath, dest, idMappingOpts, &containerOwner, extract, isFromHostToCtr)
+ err := copy(src, destPath, dest, idMappingOpts, &destOwner, extract, isFromHostToCtr)
if lastError != nil {
logrus.Error(lastError)
}
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index ee9e57966..a133549ea 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -15,25 +15,30 @@ import (
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, true, false)
+ return getRuntime(ctx, c, false, true, false, true)
+}
+
+// GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify
+func GetRuntimeDisableFDs(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
+ return getRuntime(ctx, c, false, false, false, false)
}
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, true, false, false)
+ return getRuntime(ctx, c, true, false, false, true)
}
// GetRuntime generates a new libpod runtime configured by command line options
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, false, false)
+ return getRuntime(ctx, c, false, false, false, true)
}
// GetRuntimeNoStore generates a new libpod runtime configured by command line options
func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, false, true)
+ return getRuntime(ctx, c, false, false, true, true)
}
-func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore bool) (*libpod.Runtime, error) {
+func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore, withFDS bool) (*libpod.Runtime, error) {
options := []libpod.RuntimeOption{}
storageOpts := storage.StoreOptions{}
storageSet := false
@@ -165,6 +170,10 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migra
infraCommand, _ := c.Flags().GetString("infra-command")
options = append(options, libpod.WithDefaultInfraCommand(infraCommand))
}
+
+ if withFDS {
+ options = append(options, libpod.WithEnableSDNotify())
+ }
if c.Flags().Changed("config") {
return libpod.NewRuntimeFromConfig(ctx, c.GlobalFlags.Config, options...)
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 1b54c9458..dc44a9110 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -101,7 +101,7 @@ func initConfig() {
}
func before(cmd *cobra.Command, args []string) error {
- if err := libpod.SetXdgRuntimeDir(); err != nil {
+ if err := libpod.SetXdgDirs(); err != nil {
logrus.Errorf(err.Error())
os.Exit(1)
}
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index 5c8b2b1ff..587c8260f 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -1,4 +1,5 @@
// +build !remoteclient
+// +build linux
package main
@@ -122,6 +123,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") {
return nil
}
+
podmanCmd := cliconfig.PodmanCommand{
Command: cmd,
InputArgs: args,
diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go
index ecbb44d5a..a005e925c 100644
--- a/cmd/podman/main_remote.go
+++ b/cmd/podman/main_remote.go
@@ -3,13 +3,8 @@
package main
import (
- "fmt"
- "os"
"os/user"
- "path/filepath"
- "github.com/docker/docker/pkg/homedir"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -30,39 +25,6 @@ func init() {
rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console")
}
-func setSyslog() error {
- // Log to file if not using syslog
- homeDir := homedir.Get()
- path := filepath.Join(homeDir, ".config", "containers")
-
- if _, err := os.Stat(path); os.IsNotExist(err) {
- if err := os.MkdirAll(path, 0750); err != nil {
- fmt.Fprintf(os.Stderr, "%v", err)
- return err
- }
- }
-
- // Update path to include file name
- path = filepath.Join(path, "podman.log")
-
- // Create the log file if doesn't exist. And append to it if it already exists.
- file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
- if err != nil {
- // Cannot open log file. Logging to stderr
- fmt.Fprintf(os.Stderr, "%v", err)
- return err
- } else {
- formatter := new(logrus.TextFormatter)
- formatter.FullTimestamp = true
- logrus.SetFormatter(formatter)
- logrus.SetOutput(file)
- }
-
- // Note this message is only logged if --log-level >= Info!
- logrus.Infof("Logging level set to %s", logrus.GetLevel().String())
- return nil
-}
-
func profileOn(cmd *cobra.Command) error {
return nil
}
diff --git a/cmd/podman/main_remote_supported.go b/cmd/podman/main_remote_supported.go
new file mode 100644
index 000000000..bb567c273
--- /dev/null
+++ b/cmd/podman/main_remote_supported.go
@@ -0,0 +1,57 @@
+// +build remoteclient
+// +build linux darwin
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func setSyslog() error {
+ var err error
+ cfgHomeDir := os.Getenv("XDG_CONFIG_HOME")
+ if cfgHomeDir == "" {
+ if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil {
+ return err
+ }
+ if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil {
+ return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME")
+ }
+ }
+ path := filepath.Join(cfgHomeDir, "containers")
+
+ // Log to file if not using syslog
+
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ if err := os.MkdirAll(path, 0750); err != nil {
+ fmt.Fprintf(os.Stderr, "%v", err)
+ return err
+ }
+ }
+
+ // Update path to include file name
+ path = filepath.Join(path, "podman.log")
+
+ // Create the log file if doesn't exist. And append to it if it already exists.
+ file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
+ if err != nil {
+ // Cannot open log file. Logging to stderr
+ fmt.Fprintf(os.Stderr, "%v", err)
+ return err
+ } else {
+ formatter := new(logrus.TextFormatter)
+ formatter.FullTimestamp = true
+ logrus.SetFormatter(formatter)
+ logrus.SetOutput(file)
+ }
+
+ // Note this message is only logged if --log-level >= Info!
+ logrus.Infof("Logging level set to %s", logrus.GetLevel().String())
+ return nil
+}
diff --git a/cmd/podman/main_remote_windows.go b/cmd/podman/main_remote_windows.go
new file mode 100644
index 000000000..0ef1370ce
--- /dev/null
+++ b/cmd/podman/main_remote_windows.go
@@ -0,0 +1,7 @@
+// +build remoteclient,windows
+
+package main
+
+func setSyslog() error {
+ return nil
+}
diff --git a/cmd/podman/network.go b/cmd/podman/network.go
new file mode 100644
index 000000000..83a5e71ab
--- /dev/null
+++ b/cmd/podman/network.go
@@ -0,0 +1,31 @@
+//+build !remoteclient
+
+package main
+
+import (
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/spf13/cobra"
+)
+
+var networkcheckDescription = "Manage networks"
+var networkcheckCommand = cliconfig.PodmanCommand{
+ Command: &cobra.Command{
+ Use: "network",
+ Short: "Manage Networks",
+ Long: networkcheckDescription,
+ RunE: commandRunE(),
+ },
+}
+
+// Commands that are universally implemented
+var networkcheckCommands = []*cobra.Command{
+ _networkinspectCommand,
+ _networklistCommand,
+ _networkrmCommand,
+}
+
+func init() {
+ networkcheckCommand.AddCommand(networkcheckCommands...)
+ networkcheckCommand.SetUsageTemplate(UsageTemplate())
+ rootCmd.AddCommand(networkcheckCommand.Command)
+}
diff --git a/cmd/podman/network_inspect.go b/cmd/podman/network_inspect.go
new file mode 100644
index 000000000..38aaf6ba4
--- /dev/null
+++ b/cmd/podman/network_inspect.go
@@ -0,0 +1,48 @@
+// +build !remoteclient
+
+package main
+
+import (
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ networkinspectCommand cliconfig.NetworkInspectValues
+ networkinspectDescription = `Inspect network`
+ _networkinspectCommand = &cobra.Command{
+ Use: "inspect NETWORK [NETWORK...] [flags] ",
+ Short: "network inspect",
+ Long: networkinspectDescription,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ networkinspectCommand.InputArgs = args
+ networkinspectCommand.GlobalFlags = MainGlobalOpts
+ networkinspectCommand.Remote = remoteclient
+ return networkinspectCmd(&networkinspectCommand)
+ },
+ Example: `podman network inspect podman`,
+ }
+)
+
+func init() {
+ networkinspectCommand.Command = _networkinspectCommand
+ networkinspectCommand.SetHelpTemplate(HelpTemplate())
+ networkinspectCommand.SetUsageTemplate(UsageTemplate())
+}
+
+func networkinspectCmd(c *cliconfig.NetworkInspectValues) error {
+ if rootless.IsRootless() && !remoteclient {
+ return errors.New("network inspect is not supported for rootless mode")
+ }
+ if len(c.InputArgs) < 1 {
+ return errors.Errorf("at least one network name is required")
+ }
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ if err != nil {
+ return err
+ }
+ return runtime.NetworkInspect(c)
+}
diff --git a/cmd/podman/network_list.go b/cmd/podman/network_list.go
new file mode 100644
index 000000000..16edf743b
--- /dev/null
+++ b/cmd/podman/network_list.go
@@ -0,0 +1,53 @@
+// +build !remoteclient
+
+package main
+
+import (
+ "errors"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/spf13/cobra"
+)
+
+var (
+ networklistCommand cliconfig.NetworkListValues
+ networklistDescription = `List networks`
+ _networklistCommand = &cobra.Command{
+ Use: "ls",
+ Args: noSubArgs,
+ Short: "network list",
+ Long: networklistDescription,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ networklistCommand.InputArgs = args
+ networklistCommand.GlobalFlags = MainGlobalOpts
+ networklistCommand.Remote = remoteclient
+ return networklistCmd(&networklistCommand)
+ },
+ Example: `podman network list`,
+ }
+)
+
+func init() {
+ networklistCommand.Command = _networklistCommand
+ networklistCommand.SetHelpTemplate(HelpTemplate())
+ networklistCommand.SetUsageTemplate(UsageTemplate())
+ flags := networklistCommand.Flags()
+ // TODO enable filters based on something
+ //flags.StringSliceVarP(&networklistCommand.Filter, "filter", "f", []string{}, "Pause all running containers")
+ flags.BoolVarP(&networklistCommand.Quiet, "quiet", "q", false, "display only names")
+}
+
+func networklistCmd(c *cliconfig.NetworkListValues) error {
+ if rootless.IsRootless() && !remoteclient {
+ return errors.New("network list is not supported for rootless mode")
+ }
+ if len(c.InputArgs) > 0 {
+ return errors.New("network list takes no arguments")
+ }
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ if err != nil {
+ return err
+ }
+ return runtime.NetworkList(c)
+}
diff --git a/cmd/podman/network_rm.go b/cmd/podman/network_rm.go
new file mode 100644
index 000000000..50bd48cea
--- /dev/null
+++ b/cmd/podman/network_rm.go
@@ -0,0 +1,48 @@
+// +build !remoteclient
+
+package main
+
+import (
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ networkrmCommand cliconfig.NetworkRmValues
+ networkrmDescription = `Remove networks`
+ _networkrmCommand = &cobra.Command{
+ Use: "rm [flags] NETWORK [NETWORK...]",
+ Short: "network rm",
+ Long: networkrmDescription,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ networkrmCommand.InputArgs = args
+ networkrmCommand.GlobalFlags = MainGlobalOpts
+ networkrmCommand.Remote = remoteclient
+ return networkrmCmd(&networkrmCommand)
+ },
+ Example: `podman network rm podman`,
+ }
+)
+
+func init() {
+ networkrmCommand.Command = _networkrmCommand
+ networkrmCommand.SetHelpTemplate(HelpTemplate())
+ networkrmCommand.SetUsageTemplate(UsageTemplate())
+}
+
+func networkrmCmd(c *cliconfig.NetworkRmValues) error {
+ if rootless.IsRootless() && !remoteclient {
+ return errors.New("network rm is not supported for rootless mode")
+ }
+ if len(c.InputArgs) < 1 {
+ return errors.Errorf("at least one network name is required")
+ }
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ if err != nil {
+ return err
+ }
+ return runtime.NetworkRemove(c)
+}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index b6154b4db..ad3c00aa8 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -52,6 +52,7 @@ func init() {
flags.StringSliceVar(&podCreateCommand.LabelFile, "label-file", []string{}, "Read in a line delimited file of labels")
flags.StringSliceVarP(&podCreateCommand.Labels, "label", "l", []string{}, "Set metadata on pod (default [])")
flags.StringVarP(&podCreateCommand.Name, "name", "n", "", "Assign a name to the pod")
+ flags.StringVarP(&podCreateCommand.Hostname, "hostname", "", "", "Set a hostname to the pod")
flags.StringVar(&podCreateCommand.PodIDFile, "pod-id-file", "", "Write the pod ID to the file")
flags.StringSliceVarP(&podCreateCommand.Publish, "publish", "p", []string{}, "Publish a container's port, or a range of ports, to the host (default [])")
flags.StringVar(&podCreateCommand.Share, "share", shared.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
@@ -78,7 +79,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" {
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
}
- if c.Flag("pod-id-file").Changed && os.Geteuid() == 0 {
+ if c.Flag("pod-id-file").Changed {
podIdFile, err = util.OpenExclusiveFile(c.PodIDFile)
if err != nil && os.IsExist(err) {
return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", c.PodIDFile)
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 46cacc026..2f1ebd3ac 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -15,6 +15,8 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -53,9 +55,14 @@ func init() {
}
func podStatsCmd(c *cliconfig.PodStatsValues) error {
-
- if os.Geteuid() != 0 {
- return errors.New("stats is not supported in rootless mode")
+ if rootless.IsRootless() {
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return err
+ }
+ if !unified {
+ return errors.New("stats is not supported in rootless mode without cgroups v2")
+ }
}
format := c.Format
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index 5753c8e56..4e1f9642c 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -48,8 +48,8 @@ func init() {
func portCmd(c *cliconfig.PortValues) error {
var (
- userProto, containerName string
- userPort int
+ userProto string
+ userPort int
)
args := c.InputArgs
@@ -106,6 +106,7 @@ func portCmd(c *cliconfig.PortValues) error {
if err != nil {
return err
}
+ var found bool
// Iterate mappings
for _, v := range portmappings {
hostIP := v.HostIP
@@ -125,12 +126,14 @@ func portCmd(c *cliconfig.PortValues) error {
if v.ContainerPort == int32(userPort) {
if userProto == "" || userProto == v.Protocol {
fmt.Printf("%s:%d\n", hostIP, v.HostPort)
+ found = true
break
}
- } else {
- return errors.Errorf("No public port '%d' published for %s", userPort, containerName)
}
}
+ if !found && port != "" {
+ return errors.Errorf("failed to find published port '%d'", userPort)
+ }
}
return nil
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 0eee51e79..53f133929 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -150,7 +150,7 @@ func pullCmd(c *cliconfig.PullValues) (retError error) {
// See https://bugzilla.redhat.com/show_bug.cgi?id=1701922 for background
// information.
if !c.Bool("all-tags") {
- newImage, err := runtime.New(getContext(), imgArg, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, true, nil)
+ newImage, err := runtime.New(getContext(), imgArg, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways)
if err != nil {
return errors.Wrapf(err, "error pulling image %q", imgArg)
}
@@ -188,7 +188,7 @@ func pullCmd(c *cliconfig.PullValues) (retError error) {
var foundIDs []string
foundImage := true
for _, name := range names {
- newImage, err := runtime.New(getContext(), name, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, true, nil)
+ newImage, err := runtime.New(getContext(), name, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways)
if err != nil {
logrus.Errorf("error pulling image %q", name)
foundImage = false
diff --git a/cmd/podman/remoteclientconfig/config_linux.go b/cmd/podman/remoteclientconfig/config_linux.go
index b94941381..5d27f19f2 100644
--- a/cmd/podman/remoteclientconfig/config_linux.go
+++ b/cmd/podman/remoteclientconfig/config_linux.go
@@ -1,12 +1,17 @@
package remoteclientconfig
import (
+ "os"
"path/filepath"
"github.com/docker/docker/pkg/homedir"
)
func getConfigFilePath() string {
- homeDir := homedir.Get()
- return filepath.Join(homeDir, ".config", "containers", remoteConfigFileName)
+ path := os.Getenv("XDG_CONFIG_HOME")
+ if path == "" {
+ homeDir := homedir.Get()
+ path = filepath.Join(homeDir, ".config")
+ }
+ return filepath.Join(path, "containers", remoteConfigFileName)
}
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index 3ae141d41..90d0b2dc4 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -46,6 +46,7 @@ func init() {
flags.StringVarP(&restoreCommand.Import, "import", "i", "", "Restore from exported checkpoint archive (tar.gz)")
flags.StringVarP(&restoreCommand.Name, "name", "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
flags.BoolVar(&restoreCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
+ flags.BoolVar(&restoreCommand.IgnoreStaticIP, "ignore-static-ip", false, "Ignore IP address set via --static-ip")
markFlagHiddenForRemoteClient("latest", flags)
}
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 7f53f5ec9..5122d37d1 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -660,7 +660,7 @@ func formatGroup(key string, start, last int32) string {
}
// portsToString converts the ports used to a string of the from "port1, port2"
-// and also groups continuous list of ports in readable format.
+// and also groups a continuous list of ports into a readable format.
func portsToString(ports []ocicni.PortMapping) string {
type portGroup struct {
first int32
@@ -732,7 +732,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
registryCreds = creds
}
dockerRegistryOptions.DockerRegistryCreds = registryCreds
- newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false, &label)
+ newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, &label, util.PullImageMissing)
} else {
newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage)
}
@@ -750,7 +750,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
return runLabel, imageName, err
}
-// GenerateRunlabelCommand generates the command that will eventually be execucted by podman.
+// GenerateRunlabelCommand generates the command that will eventually be execucted 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 == "" {
@@ -809,7 +809,7 @@ func envSliceToMap(env []string) map[string]string {
return m
}
-// GenerateKube generates kubernetes yaml based on a pod or container
+// 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
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 4de68e4bc..094330e24 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -55,7 +55,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
rootfs = c.InputArgs[0]
}
- if c.IsSet("cidfile") && os.Geteuid() == 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"))
@@ -70,8 +70,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
imageName := ""
var data *inspect.ImageData = nil
- // Set the storage if we are running as euid == 0 and there is no rootfs specified
- if rootfs == "" && os.Geteuid() == 0 {
+ // Set the storage if there is no rootfs specified
+ if rootfs == "" {
var writer io.Writer
if !c.Bool("quiet") {
writer = os.Stderr
@@ -83,7 +83,13 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
} else {
return nil, nil, errors.Errorf("error, no input arguments were provided")
}
- newImage, err := runtime.ImageRuntime().New(ctx, name, rtc.SignaturePolicyPath, GetAuthFile(""), writer, nil, image.SigningOptions{}, false, nil)
+
+ pullType, err := util.ValidatePullType(c.String("pull"))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ newImage, err := runtime.ImageRuntime().New(ctx, name, rtc.SignaturePolicyPath, GetAuthFile(c.String("authfile")), writer, nil, image.SigningOptions{}, nil, pullType)
if err != nil {
return nil, nil, err
}
@@ -588,6 +594,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
workDir = data.Config.WorkingDir
}
+ userCommand := []string{}
entrypoint := configureEntrypoint(c, data)
// Build the command
// If we have an entry point, it goes first
@@ -597,9 +604,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
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 {
@@ -624,8 +633,16 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
}
+ // Check for explicit dns-search domain of ''
+ if c.Changed("dns-search") && len(c.StringSlice("dns-search")) == 0 {
+ return nil, errors.Errorf("'' is not a valid domain")
+ }
+
// Validate domains are good
for _, dom := range c.StringSlice("dns-search") {
+ if dom == "." {
+ continue
+ }
if _, err := parse.ValidateDomain(dom); err != nil {
return nil, err
}
@@ -680,6 +697,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
Cgroupns: c.String("cgroupns"),
CgroupParent: c.String("cgroup-parent"),
Command: command,
+ UserCommand: userCommand,
Detach: c.Bool("detach"),
Devices: c.StringSlice("device"),
DNSOpt: c.StringSlice("dns-opt"),
diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go
index 4062ac48a..c6c32f8a9 100644
--- a/cmd/podman/shared/intermediate.go
+++ b/cmd/podman/shared/intermediate.go
@@ -366,6 +366,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["add-host"] = newCRStringSlice(c, "add-host")
m["annotation"] = newCRStringSlice(c, "annotation")
m["attach"] = newCRStringSlice(c, "attach")
+ m["authfile"] = newCRString(c, "authfile")
m["blkio-weight"] = newCRString(c, "blkio-weight")
m["blkio-weight-device"] = newCRStringSlice(c, "blkio-weight-device")
m["cap-add"] = newCRStringSlice(c, "cap-add")
@@ -435,6 +436,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["privileged"] = newCRBool(c, "privileged")
m["publish"] = newCRStringSlice(c, "publish")
m["publish-all"] = newCRBool(c, "publish-all")
+ m["pull"] = newCRString(c, "pull")
m["quiet"] = newCRBool(c, "quiet")
m["read-only"] = newCRBool(c, "read-only")
m["read-only-tmpfs"] = newCRBool(c, "read-only-tmpfs")
diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go
index 4742d4909..9dbf83950 100644
--- a/cmd/podman/shared/intermediate_varlink.go
+++ b/cmd/podman/shared/intermediate_varlink.go
@@ -137,6 +137,7 @@ func (g GenericCLIResults) MakeVarlink() iopodman.Create {
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")),
@@ -393,6 +394,7 @@ func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
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)
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 1333cf441..de289047a 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -15,6 +15,7 @@ import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/trust"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -113,7 +114,7 @@ func signCmd(c *cliconfig.SignValues) error {
if err != nil {
return err
}
- newImage, err := runtime.ImageRuntime().New(getContext(), signimage, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil)
+ newImage, err := runtime.ImageRuntime().New(getContext(), signimage, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, nil, util.PullImageMissing)
if err != nil {
return errors.Wrapf(err, "error pulling image %s", signimage)
}
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index 3accae1b6..2f696445e 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -2,7 +2,6 @@ package main
import (
"fmt"
- "os"
"reflect"
"strings"
"time"
@@ -13,6 +12,8 @@ import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -66,8 +67,14 @@ func init() {
}
func statsCmd(c *cliconfig.StatsValues) error {
- if os.Geteuid() != 0 {
- return errors.New("stats is not supported for rootless containers")
+ if rootless.IsRootless() {
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return err
+ }
+ if !unified {
+ return errors.New("stats is not supported in rootless mode without cgroups v2")
+ }
}
all := c.All
diff --git a/cmd/podman/system_df.go b/cmd/podman/system_df.go
index 6b9824a79..44582a802 100644
--- a/cmd/podman/system_df.go
+++ b/cmd/podman/system_df.go
@@ -460,11 +460,11 @@ func getImageVerboseDiskUsage(ctx context.Context, images []*image.Image, images
}
var repo string
var tag string
- if len(img.Names()) == 0 {
- repo = "<none>"
- tag = "<none>"
+ var repotags []string
+ if len(img.Names()) != 0 {
+ repotags = []string{img.Names()[0]}
}
- repopairs, err := image.ReposToMap([]string{img.Names()[0]})
+ repopairs, err := image.ReposToMap(repotags)
if err != nil {
logrus.Errorf("error finding tag/digest for %s", img.ID())
}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 92315cd6b..5f89534be 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -79,7 +79,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
timeout := time.Duration(c.Timeout) * time.Millisecond
// Create a single runtime for varlink
- runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := libpodruntime.GetRuntimeDisableFDs(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 73f4d1609..08a69275e 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -227,7 +227,8 @@ type InfoHost (
hostname: string,
kernel: string,
os: string,
- uptime: string
+ uptime: string,
+ eventlogger: string
)
# InfoGraphStatus describes the detailed status of the storage driver
@@ -345,6 +346,7 @@ type Create (
privileged: ?bool,
publish: ?[]string,
publishAll: ?bool,
+ pull: ?string,
quiet: ?bool,
readonly: ?bool,
readonlytmpfs: ?bool,
@@ -1275,3 +1277,6 @@ 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) \ No newline at end of file
diff --git a/commands.md b/commands.md
index 1b48d7862..4d3bea439 100644
--- a/commands.md
+++ b/commands.md
@@ -44,6 +44,10 @@
| [podman-logout(1)](/docs/podman-logout.1.md) | Logout of a container registry |
| [podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container |
| [podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem |
+| [podman-network(1)](/docs/podman-network.1.md) | Manage Podman CNI networks |
+| [podman-network-inspect(1)](/docs/podman-network-inspect.1.md) | Inspect one or more Podman networks |
+| [podman-network-ls(1)](/docs/podman-network-ls.1.md) | Display a summary of Podman networks |
+| [podman-network-rm(1)](/docs/podman-network-rm.1.md) | Remove one or more Podman networks |
| [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) |
| [podman-play(1)](/docs/podman-play.1.md) | Play pods and containers based on a structured input file |
| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods |
diff --git a/completions/bash/podman b/completions/bash/podman
index c8f00a3cb..962c15a95 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -872,6 +872,7 @@ _podman_container_restore() {
--latest
--tcp-established
--ignore-rootfs
+ --ignore-static-ip
"
case "$prev" in
-i|--import)
@@ -945,6 +946,78 @@ _podman_healthcheck() {
esac
}
+_podman_network() {
+ local boolean_options="
+ --help
+ -h
+ "
+ subcommands="
+ inspect
+ ls
+ rm
+ "
+ __podman_subcommands "$subcommands $aliases" && return
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
+ ;;
+ *)
+ COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) )
+ ;;
+ esac
+}
+
+_podman_network_inspect() {
+ local options_with_args="
+ "
+ local boolean_options="
+ --help
+ -h
+ "
+ _complete_ "$options_with_args" "$boolean_options"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
+ ;;
+ esac
+}
+
+_podman_network_ls() {
+ local options_with_args="
+ "
+ local boolean_options="
+ --help
+ -h
+ --quiet
+ -q
+ "
+ _complete_ "$options_with_args" "$boolean_options"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
+ ;;
+ esac
+}
+
+_podman_network_ls() {
+ local options_with_args="
+ "
+ local boolean_options="
+ --help
+ -h
+ "
+ _complete_ "$options_with_args" "$boolean_options"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
+ ;;
+ esac
+}
+
_podman_generate() {
local boolean_options="
--help
@@ -1772,6 +1845,7 @@ _podman_container_run() {
--pids-limit
--pod
--publish -p
+ --pull
--runtime
--rootfs
--security-opt
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 18ef3e7f7..ada362d95 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -69,6 +69,13 @@ Confirm that cross-compile of podman-remote functions for both `windows`
and `darwin` targets.
+### ``special_testing_cgroupv2`` Task
+
+Use the latest Fedora release with the required kernel options pre-set for
+exercising cgroups v2 with podman integration tests. Also depends on
+having `SPECIALMODE` set to 'cgroupv2`
+
+
### ``test_build_cache_images_task`` Task
Modifying the contents of cache-images is tested by making changes to
@@ -266,5 +273,6 @@ values follows:
and utilized for testing.
* `in_podman`: Causes testing to occur within a container executed by
podman on the host.
+* `cgroupv2`: The kernel on this VM was prepared with options to enable v2 cgroups
* `windows`: See **darwin**
* `darwin`: Signals the ``special_testing_cross`` task to cross-compile the remote client.
diff --git a/contrib/cirrus/add_second_partition.sh b/contrib/cirrus/add_second_partition.sh
new file mode 100644
index 000000000..73db192c5
--- /dev/null
+++ b/contrib/cirrus/add_second_partition.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# N/B: This script could mega f*!@up your disks if run by mistake.
+# it is left without the execute-bit on purpose!
+
+# $SLASH_DEVICE is the disk device to be f*xtuP
+SLASH_DEVICE="/dev/sda" # Always the case on GCP
+
+# The unallocated space results from the difference in disk-size between VM Image
+# and runtime request. The check_image.sh test includes a minimum-space check,
+# with the Image size set initially lower by contrib/cirrus/packer/libpod_images.yml
+NEW_PART_START="50%"
+NEW_PART_END="100%"
+
+set -eo pipefail
+
+source $(dirname $0)/lib.sh
+
+if [[ ! -r "/root" ]] || [[ -r "/root/second_partition_ready" ]]
+then
+ echo "Warning: Ignoring attempted execution of $(basename $0)"
+ exit 0
+fi
+
+[[ -n "type -P parted" ]] || \
+ die 2 "The parted command is required."
+
+[[ ! -b ${SLASH_DEVICE}2 ]] || \
+ die 5 "Found unexpected block device ${SLASH_DEVICE}2"
+
+PPRINTCMD="parted --script ${SLASH_DEVICE} print"
+FINDMNTCMD="findmnt --source=${SLASH_DEVICE}1 --mountpoint=/ --canonicalize --evaluate --first-only --noheadings"
+TMPF=$(mktemp -p '' $(basename $0)_XXXX)
+trap "rm -f $TMPF" EXIT
+
+if $FINDMNTCMD | tee $TMPF | egrep -q "^/\s+${SLASH_DEVICE}1"
+then
+ echo "Repartitioning original partition table:"
+ $PPRINTCMD
+else
+ die 6 "Unexpected output from '$FINDMNTCMD': $(<$TMPF)"
+fi
+
+echo "Adding partition offset within unpartitioned space."
+parted --script --align optimal /dev/sda unit % mkpart primary "" "" "$NEW_PART_START" "$NEW_PART_END"
+
+echo "New partition table:"
+$PPRINTCMD
+
+echo "Growing ${SLASH_DEVICE}1 meet start of ${SLASH_DEVICE}2"
+growpart ${SLASH_DEVICE} 1
+
+FSTYPE=$(findmnt --first-only --noheadings --output FSTYPE ${SLASH_DEVICE}1)
+echo "Expanding $FSTYPE filesystem on ${SLASH_DEVICE}1"
+case $FSTYPE in
+ ext*) resize2fs ${SLASH_DEVICE}1 ;;
+ *) die 11 "Script $(basename $0) doesn't know how to resize a $FSTYPE filesystem." ;;
+esac
+
+# Must happen last - signals completion to other tooling
+echo "Recording newly available disk partition device into /root/second_partition_ready"
+echo "${SLASH_DEVICE}2" > /root/second_partition_ready
diff --git a/contrib/cirrus/build_vm_images.sh b/contrib/cirrus/build_vm_images.sh
index dd5182c37..6230610cb 100755
--- a/contrib/cirrus/build_vm_images.sh
+++ b/contrib/cirrus/build_vm_images.sh
@@ -62,6 +62,6 @@ URI="gs://packer-import${POST_MERGE_BUCKET_SUFFIX}/manifest${BUILT_IMAGE_SUFFIX}
gsutil cp packer-manifest.json "$URI"
# Ensure any background 'gcloud compute images update' processes finish
-wait # CentOS has no -n option :(
+wait # No -n option in CentOS, this is the best that can be done :(
echo "Finished. A JSON manifest of produced images is available at $URI"
diff --git a/contrib/cirrus/check_image.sh b/contrib/cirrus/check_image.sh
index 22ed1ddc4..ad9a12f49 100755
--- a/contrib/cirrus/check_image.sh
+++ b/contrib/cirrus/check_image.sh
@@ -4,10 +4,12 @@ set -eo pipefail
source $(dirname $0)/lib.sh
+req_env_var PACKER_BUILDER_NAME TEST_REMOTE_CLIENT EVIL_UNITS OS_RELEASE_ID
+
NFAILS=0
echo "Validating VM image"
-MIN_SLASH_GIGS=50
+MIN_SLASH_GIGS=30
read SLASH_DEVICE SLASH_FSTYPE SLASH_SIZE JUNK <<<$(findmnt --df --first-only --noheadings / | cut -d '.' -f 1)
SLASH_SIZE_GIGS=$(echo "$SLASH_SIZE" | sed -r -e 's/G|g//')
item_test "Minimum available disk space" $SLASH_SIZE_GIGS -gt $MIN_SLASH_GIGS || let "NFAILS+=1"
@@ -20,6 +22,9 @@ item_test 'Minimum available memory' $MEM_FREE -ge $MIN_MEM_MB || let "NFAILS+=1
# binary anywhere; that could potentially taint our results.
item_test "remove_packaged_podman_files() did it's job" -z "$(type -P podman)" || let "NFAILS+=1"
+# Integration Tests require varlink in Fedora
+item_test "The varlink executable is present" -x "$(type -P varlink)" || let "NFAILS+=1"
+
MIN_ZIP_VER='3.0'
VER_RE='.+([[:digit:]]+\.[[:digit:]]+).+'
ACTUAL_VER=$(zip --version 2>&1 | egrep -m 1 "Zip$VER_RE" | sed -r -e "s/$VER_RE/\\1/")
@@ -49,5 +54,16 @@ then
item_test "On ubuntu /usr/bin/runc is /usr/lib/cri-o-runc/sbin/runc" "$SAMESAME" -eq "0" || let "NFAILS+=1"
fi
+echo "Checking items specific to ${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}"
+case "$PACKER_BUILDER_NAME" in
+ xfedora*)
+ echo "Kernel Command-line: $(cat /proc/cmdline)"
+ item_test \
+ "On ${PACKER_BUILDER_NAME} images, the /sys/fs/cgroup/unified directory does NOT exist" \
+ "!" "-d" "/sys/fs/cgroup/unified" || let "NFAILS+=1"
+ ;;
+ *) echo "No vm-image specific items to check"
+esac
+
echo "Total failed tests: $NFAILS"
exit $NFAILS
diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh
index cfaf33b85..e5de518fa 100755
--- a/contrib/cirrus/integration_test.sh
+++ b/contrib/cirrus/integration_test.sh
@@ -36,6 +36,18 @@ case "$SPECIALMODE" in
-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
-o CheckHostIP=no $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE}
;;
+ cgroupv2)
+ # FIXME: use the package once all the fixes are in a release
+ # yum install -y crun
+ setenforce 0
+ yum builddep -y crun
+ (git clone --depth=1 https://github.com/containers/crun && cd crun && ./autogen.sh && ./configure --prefix=/usr && make -j4 && make install)
+ export OCI_RUNTIME=/usr/bin/crun
+ make
+ make install PREFIX=/usr ETCDIR=/etc
+ make test-binaries
+ make local${TESTSUITE}
+ ;;
none)
make
make install PREFIX=/usr ETCDIR=/etc
@@ -52,5 +64,5 @@ case "$SPECIALMODE" in
warn '' "No $SPECIALMODE remote client integration tests configured"
;;
*)
- die 110 "Unsupported \$SPECIAL_MODE: $SPECIALMODE"
+ die 110 "Unsupported \$SPECIALMODE: $SPECIALMODE"
esac
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 737ca3c01..a20ee5a62 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -55,9 +55,9 @@ PACKER_VER="1.3.5"
# CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json)
# Base-images rarely change, define them here so they're out of the way.
-export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,fedora-29}"
+export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,xfedora-30,fedora-29}"
# Google-maintained base-image names
-export UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20181203a"
+export UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20190722a"
# Manually produced base-image names (see $SCRIPT_BASE/README.md)
export FEDORA_BASE_IMAGE="fedora-cloud-base-30-1-2-1559164849"
export PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-29-1-2-1559164849"
@@ -100,6 +100,9 @@ OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | cut -d '.' -f 1)"
# Combined to ease soe usage
OS_REL_VER="${OS_RELEASE_ID}-${OS_RELEASE_VER}"
+# Installed into cache-images, supports overrides
+# by user-data in case of breakage or for debugging.
+CUSTOM_CLOUD_CONFIG_DEFAULTS="$GOSRC/$PACKER_BASE/cloud-init/$OS_RELEASE_ID/cloud.cfg.d"
# Pass in a list of one or more envariable names; exit non-zero with
# helpful error message if any value is empty
req_env_var() {
@@ -354,7 +357,7 @@ remove_packaged_podman_files(){
}
systemd_banish(){
- echo "Disabling periodic services that could destabilize testing:"
+ echo "Disabling periodic services that could destabilize testing (ignoring errors):"
set +e # Not all of these exist on every platform
for unit in $EVIL_UNITS
do
@@ -372,11 +375,20 @@ systemd_banish(){
_finalize(){
set +e # Don't fail at the very end
- set +e # make errors non-fatal
- echo "Removing leftover giblets from cloud-init"
+ if [[ -d "$CUSTOM_CLOUD_CONFIG_DEFAULTS" ]]
+ then
+ echo "Installing custom cloud-init defaults"
+ sudo cp -v "$CUSTOM_CLOUD_CONFIG_DEFAULTS"/* /etc/cloud/cloud.cfg.d/
+ else
+ echo "Could not find any files in $CUSTOM_CLOUD_CONFIG_DEFAULTS"
+ fi
+ echo "Re-initializing so next boot does 'first-boot' setup again."
+ sudo history -c
cd /
sudo rm -rf /var/lib/cloud/instanc*
sudo rm -rf /root/.ssh/*
+ sudo rm -rf /etc/ssh/*key*
+ sudo rm -rf /etc/ssh/moduli
sudo rm -rf /home/*
sudo rm -rf /tmp/*
sudo rm -rf /tmp/.??*
@@ -386,11 +398,6 @@ _finalize(){
rh_finalize(){
set +e # Don't fail at the very end
- # Allow root ssh-logins
- if [[ -r /etc/cloud/cloud.cfg ]]
- then
- sudo sed -re 's/^disable_root:.*/disable_root: 0/g' -i /etc/cloud/cloud.cfg
- fi
echo "Resetting to fresh-state for usage as cloud-image."
PKG=$(type -P dnf || type -P yum || echo "")
sudo $PKG clean all
diff --git a/contrib/cirrus/networking.sh b/contrib/cirrus/networking.sh
new file mode 100755
index 000000000..aeaf74035
--- /dev/null
+++ b/contrib/cirrus/networking.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# This script attempts basic confirmation of functional networking
+# by connecting to a set of essential external servers and failing
+# if any cannot be reached.
+
+source $(dirname $0)/lib.sh
+
+while read host port
+do
+ if [[ "$port" -eq "443" ]]
+ then
+ item_test "SSL/TLS to $host:$port" "$(echo -n '' | openssl s_client -quiet -no_ign_eof -connect $host:$port &> /dev/null; echo $?)" -eq "0"
+ else
+ item_test "Connect to $host:$port" "$(nc -zv -w 13 $host $port &> /dev/null; echo $?)" -eq 0
+ fi
+done < ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/required_host_ports.txt
diff --git a/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg
new file mode 100644
index 000000000..672d1907b
--- /dev/null
+++ b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg
@@ -0,0 +1 @@
+disable_root: 0
diff --git a/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg
new file mode 100644
index 000000000..c0fdf0e23
--- /dev/null
+++ b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg
@@ -0,0 +1,4 @@
+#cloud-config
+growpart:
+ mode: false
+resize_rootfs: false
diff --git a/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg b/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg
new file mode 120000
index 000000000..98a0e3918
--- /dev/null
+++ b/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg
@@ -0,0 +1 @@
+../../fedora/cloud.cfg.d/40_enable_root.cfg \ No newline at end of file
diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh
index 1e25a1a3c..0e1a82cc0 100644
--- a/contrib/cirrus/packer/fedora_setup.sh
+++ b/contrib/cirrus/packer/fedora_setup.sh
@@ -8,7 +8,7 @@ set -e
# Load in library (copied by packer, before this script was run)
source /tmp/libpod/$SCRIPT_BASE/lib.sh
-req_env_var SCRIPT_BASE
+req_env_var SCRIPT_BASE PACKER_BUILDER_NAME GOSRC
install_ooe
@@ -17,6 +17,10 @@ trap "sudo rm -rf $GOPATH" EXIT
ooe.sh sudo dnf update -y
+echo "Enabling updates-testing repository"
+ooe.sh sudo dnf install -y 'dnf-command(config-manager)'
+ooe.sh sudo dnf config-manager --set-enabled updates-testing
+
echo "Installing general build/test dependencies"
ooe.sh sudo dnf install -y \
atomic-registries \
@@ -49,6 +53,7 @@ ooe.sh sudo dnf install -y \
libseccomp \
libseccomp-devel \
libselinux-devel \
+ libvarlink-util \
lsof \
make \
nmap-ncat \
@@ -81,6 +86,17 @@ systemd_banish
sudo /tmp/libpod/hack/install_catatonit.sh
+# Same script is used for several related contexts
+case "$PACKER_BUILDER_NAME" in
+ xfedora*)
+ echo "Configuring CGroups v2 enabled on next boot"
+ sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
+ ;& # continue to next matching item
+ *)
+ echo "Finalizing $PACKER_BUILDER_NAME VM image"
+ ;;
+esac
+
rh_finalize
echo "SUCCESS!"
diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml
index 91ed3b474..cae5d4138 100644
--- a/contrib/cirrus/packer/libpod_images.yml
+++ b/contrib/cirrus/packer/libpod_images.yml
@@ -33,7 +33,7 @@ builders:
image_name: '{{build_name}}{{user `BUILT_IMAGE_SUFFIX`}}'
image_family: '{{build_name}}-libpod'
source_image: '{{user `UBUNTU_BASE_IMAGE`}}'
- disk_size: 20
+ disk_size: 20 # REQUIRED: Runtime allocation > this value
project_id: '{{user `GCP_PROJECT_ID`}}'
service_account_email: '{{user `SERVICE_ACCOUNT`}}'
communicator: 'ssh'
@@ -48,6 +48,10 @@ builders:
source_image: '{{user `FEDORA_BASE_IMAGE`}}'
- <<: *gce_hosted_image
+ name: 'xfedora-30'
+ source_image: '{{user `FEDORA_BASE_IMAGE`}}'
+
+ - <<: *gce_hosted_image
name: 'fedora-29'
source_image: '{{user `PRIOR_FEDORA_BASE_IMAGE`}}'
@@ -60,6 +64,7 @@ provisioners:
- type: 'shell'
script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh'
environment_vars:
+ - 'PACKER_BUILDER_NAME={{build_name}}'
- 'GOSRC=/tmp/libpod'
- 'SCRIPT_BASE={{user `SCRIPT_BASE`}}'
diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh
index dba191ad2..00d92570f 100644
--- a/contrib/cirrus/packer/ubuntu_setup.sh
+++ b/contrib/cirrus/packer/ubuntu_setup.sh
@@ -15,6 +15,9 @@ install_ooe
export GOPATH="$(mktemp -d)"
trap "sudo rm -rf $GOPATH" EXIT
+# Ensure there are no disruptive periodic services enabled by default in image
+systemd_banish
+
echo "Updating/configuring package repositories."
$LILTO $SUDOAPTGET update
$LILTO $SUDOAPTGET install software-properties-common
@@ -62,6 +65,7 @@ $BIGTO $SUDOAPTGET install \
libnet1-dev \
libnl-3-dev \
libostree-dev \
+ libvarlink \
libprotobuf-c0-dev \
libprotobuf-dev \
libseccomp-dev \
@@ -100,9 +104,6 @@ ooe.sh sudo update-grub
sudo /tmp/libpod/hack/install_catatonit.sh
ooe.sh sudo make -C /tmp/libpod install.libseccomp.sudo
-# Ensure there are no disruptive periodic services enabled by default in image
-systemd_banish
-
ubuntu_finalize
echo "SUCCESS!"
diff --git a/contrib/cirrus/packer/xfedora_setup.sh b/contrib/cirrus/packer/xfedora_setup.sh
new file mode 120000
index 000000000..5e9f1ec77
--- /dev/null
+++ b/contrib/cirrus/packer/xfedora_setup.sh
@@ -0,0 +1 @@
+fedora_setup.sh \ No newline at end of file
diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt
index 9248e497a..85a6c26be 100644
--- a/contrib/cirrus/required_host_ports.txt
+++ b/contrib/cirrus/required_host_ports.txt
@@ -2,3 +2,14 @@ github.com 22
docker.io 443
quay.io 443
registry.fedoraproject.org 443
+mirrors.fedoraproject.org 443
+dl.fedoraproject.org 443
+ewr.edge.kernel.org 443
+mirror.chpc.utah.edu 443
+mirror.clarkson.edu 443
+mirror.umd.edu 443
+mirror.vcu.edu 443
+mirrors.cat.pdx.edu 443
+pubmirror1.math.uh.edu 443
+pubmirror2.math.uh.edu 443
+sjc.edge.kernel.org 443
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 2230684ac..7b6765f8a 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -42,8 +42,11 @@ case "${OS_REL_VER}" in
ln -f "$CRIO_RUNC_PATH" "/usr/bin/runc"
fi
;;
- fedora-30) ;;
- fedora-29) ;;
+ fedora-30) ;& # continue to next item
+ fedora-29)
+ if [[ "$ADD_SECOND_PARTITION" == "true" ]]; then
+ bash "$SCRIPT_BASE/add_second_partition.sh"; fi
+ ;;
centos-7) # Current VM is an image-builder-image no local podman/testing
echo "No further setup required for VM image building"
exit 0
@@ -59,9 +62,12 @@ install_test_configs
make install.tools
case "$SPECIALMODE" in
- none)
+ cgroupv2)
remove_packaged_podman_files # we're building from source
;;
+ none)
+ remove_packaged_podman_files
+ ;;
rootless)
# Only do this once, even if ROOTLESS_USER (somehow) changes
if ! grep -q 'ROOTLESS_USER' /etc/environment
@@ -82,5 +88,5 @@ case "$SPECIALMODE" in
windows) ;& # for podman-remote building only
darwin) ;;
*)
- die 111 "Unsupported \$SPECIAL_MODE: $SPECIALMODE"
+ die 111 "Unsupported \$SPECIALMODE: $SPECIALMODE"
esac
diff --git a/contrib/imgprune/Dockerfile b/contrib/imgprune/Dockerfile
index 26329e828..b0dc77da5 100644
--- a/contrib/imgprune/Dockerfile
+++ b/contrib/imgprune/Dockerfile
@@ -1,4 +1,4 @@
-FROM libpod/imgts:latest
+FROM quay.io/libpod/imgts:latest
RUN yum -y update && \
yum clean all
diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go
index 237f4f6e6..f6c90914a 100644
--- a/contrib/perftest/main.go
+++ b/contrib/perftest/main.go
@@ -103,7 +103,7 @@ func main() {
}
fmt.Printf("image %s not found locally, fetching from remote registry..\n", *testImageName)
- testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil)
+ testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, nil, util.PullImageMissing)
if err != nil {
logrus.Fatal(err)
}
diff --git a/contrib/snapcraft/.editorconfig b/contrib/snapcraft/.editorconfig
new file mode 100644
index 000000000..1749b2d4c
--- /dev/null
+++ b/contrib/snapcraft/.editorconfig
@@ -0,0 +1,17 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = false
+insert_final_newline = false
+
+[*.yaml]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true \ No newline at end of file
diff --git a/contrib/snapcraft/.gitignore b/contrib/snapcraft/.gitignore
new file mode 100644
index 000000000..59894f50f
--- /dev/null
+++ b/contrib/snapcraft/.gitignore
@@ -0,0 +1,12 @@
+#snapcraft specifics
+/parts/
+/stage/
+/prime/
+
+*.snap
+
+.snapcraft
+__pycache__
+*.pyc
+*_source.tar.bz2
+snap/.snapcraft
diff --git a/contrib/snapcraft/LICENSE b/contrib/snapcraft/LICENSE
new file mode 100644
index 000000000..81802d619
--- /dev/null
+++ b/contrib/snapcraft/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Snapcrafters
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/contrib/snapcraft/README.md b/contrib/snapcraft/README.md
new file mode 100644
index 000000000..f543c61a7
--- /dev/null
+++ b/contrib/snapcraft/README.md
@@ -0,0 +1,82 @@
+<h1 align="center">
+ <img src="https://raw.githubusercontent.com/containers/podman.io/master/images/podman.svg?sanitize=true" alt="podman">
+ <br />
+</h1>
+
+<p align="center"><b>This is the snap for <a href="https://podman.io/">podman</a></b>, <i>“Managing Pods, Containers, and Container Images in Multiple Formats (Docker, OCI, ...).”</i>. It works on Ubuntu, Fedora, Debian, RHEL, SUSE, and other major Linux
+distributions.</p>
+
+<!-- Uncomment and modify this when you are provided a build status badge
+<p align="center">
+<a href="https://build.snapcraft.io/user/snapcrafters/fork-and-rename-me"><img src="https://build.snapcraft.io/badge/snapcrafters/fork-and-rename-me.svg" alt="Snap Status"></a>
+</p>
+-->
+
+<!-- Uncomment and modify this when you have a screenshot
+![podman](screenshot.png?raw=true "podman")
+-->
+
+<p align="center">Published for <img src="https://raw.githubusercontent.com/anythingcodes/slack-emoji-for-techies/gh-pages/emoji/tux.png" align="top" width="24" /> with 💝 by Snapcrafters</p>
+
+## Install
+
+ sudo snap install podman
+
+([Don't have snapd installed?](https://snapcraft.io/docs/core/install))
+
+## Remaining tasks
+<!-- Uncomment and modify this when you have a screenshot
+![podman](screenshot.png?raw=true "podman")
+-->
+
+Snapcrafters ([join us](https://forum.snapcraft.io/t/join-snapcrafters/1325))
+are working to land snap install documentation and
+the [snapcraft.yaml](https://github.com/snapcrafters/podman/blob/master/snap/snapcraft.yaml)
+upstream so `podman` can authoritatively publish future releases.
+
+ - [x] Fork the [Snapcrafters template](https://github.com/snapcrafters/fork-and-rename-me) repository to your own GitHub account.
+ - If you have already forked the Snapcrafter template to your account and want to create another snap, you'll need to use GitHub's [Import repository](https://github.com/new/import) feature because you can only fork a repository once.
+ - [x] Rename the forked Snapcrafters template repository
+ - [x] Update the description of the repository
+ - [x] Update logos and references to `podman` and `[podman]`
+ - [ ] Create a snap that runs in `devmode`
+ - [x] Register the snap in the store, **using the preferred upstream name**
+ - [ ] Add a screenshot to this `README.md`
+ - [ ] Publish the `devmode` snap in the Snap store edge channel
+ - [ ] Add install instructions to this `README.md`
+ - [ ] Update snap store metadata, icons and screenshots
+ - [ ] Convert the snap to `strict` confinement, or `classic` confinement if it qualifies
+ - [ ] Publish the confined snap in the Snap store beta channel
+ - [ ] Update the install instructions in this `README.md`
+ - [ ] Post a call for testing on the [Snapcraft Forum](https://forum.snapcraft.io) - [link]()
+ - [ ] Make a post in the [Snapcraft Forum](https://forum.snapcraft.io) asking for a transfer of the snap name from you to snapcrafters - [link]()
+ - [ ] Ask a [Snapcrafters admin](https://github.com/orgs/snapcrafters/people?query=%20role%3Aowner) to fork your repo into github.com/snapcrafters, and configure the repo for automatic publishing into edge on commit
+ - [ ] Add the provided Snapcraft build badge to this `README.md`
+ - [ ] Publish the snap in the Snap store stable channel
+ - [ ] Update the install instructions in this `README.md`
+ - [ ] Post an announcement in the [Snapcraft Forum](https://forum.snapcraft.io) - [link]()
+ - [ ] Submit a pull request or patch upstream that adds snap install documentation - [link]()
+ - [ ] Submit a pull request or patch upstream that adds the `snapcraft.yaml` and any required assets/launchers - [link]()
+ - [ ] Add upstream contact information to the `README.md`
+ - If upstream accept the PR:
+ - [ ] Request upstream create a Snap store account
+ - [ ] Contact the Snap Advocacy team to request the snap be transferred to upstream
+ - [ ] Ask the Snap Advocacy team to celebrate the snap - [link]()
+
+If you have any questions, [post in the Snapcraft forum](https://forum.snapcraft.io).
+
+<!--
+## The Snapcrafters
+
+| [![Your Name](https://gravatar.com/avatar/bc0bced65e963eb5c3a16cab8b004431/?s=128)](https://github.com/yourname/) |
+| :---: |
+| [Your Name](https://github.com/yourname/) |
+-->
+
+<!-- Uncomment and modify this when you have upstream contacts
+## Upstream
+
+| [![Upstream Name](https://gravatar.com/avatar/bc0bced65e963eb5c3a16cab8b004431?s=128)](https://github.com/upstreamname) |
+| :---: |
+| [Upstream Name](https://github.com/upstreamname) |
+-->
diff --git a/contrib/snapcraft/snap/snapcraft.yaml b/contrib/snapcraft/snap/snapcraft.yaml
new file mode 100644
index 000000000..7ff0df03b
--- /dev/null
+++ b/contrib/snapcraft/snap/snapcraft.yaml
@@ -0,0 +1,45 @@
+name: podman # you probably want to 'snapcraft register <name>'
+version: '0.11.1.1' # just for humans, typically '1.2+git' or '1.3.2'
+summary: Manage pods, containers and container images
+description: |
+ `podman` is a tool for managing Pods, Containers, and Container Images
+ in multiple formats including Docker/OSI images. It exposes the same
+ command line interface as Docker, but runs containers unprivileged by
+ default.
+
+confinement: devmode # use 'strict' once you have the right plugs and slots
+
+base: core18
+
+parts:
+ podman:
+ plugin: go
+ source: https://github.com/containers/libpod/archive/v0.11.1.1.tar.gz
+ go-importpath: github.com/containers/libpod
+ build-packages:
+ # https://github.com/containers/libpod/blob/master/install.md#build-and-run-dependencies
+ - btrfs-tools
+ - git
+ - golang-go
+ - go-md2man
+ - iptables
+ - libassuan-dev
+ - libdevmapper-dev
+ - libglib2.0-dev
+ - libc6-dev
+ - libgpgme11-dev
+ - libgpg-error-dev
+ - libostree-dev
+ - libprotobuf-dev
+ - libprotobuf-c0-dev
+ - libseccomp-dev
+ - libselinux1-dev
+ - pkg-config
+ stage-packages:
+ - libarchive13
+ - libassuan0
+ - libgpgme11
+ - libicu60
+ - libostree-1-1
+ - libsoup2.4-1
+ - libxml2
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 9d8467783..934f785db 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -39,7 +39,7 @@
%global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7})
Name: podman
-Version: 1.4.5
+Version: 1.5.2
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
@@ -354,9 +354,13 @@ providing packages with %{import_path} prefix.
%prep
%autosetup -Sgit -n %{repo}-%{shortcommit0}
-# untar cri-o
+# untar conmon
tar zxf %{SOURCE1}
+sed -i 's/install.remote: podman-remote/install.remote:/' Makefile
+sed -i 's/install.bin: podman/install.bin:/' Makefile
+sed -i 's/install.man: docs/install.man:/' Makefile
+
%build
mkdir _build
pushd _build
@@ -385,6 +389,7 @@ popd
%install
install -dp %{buildroot}%{_unitdir}
+install -dp %{buildroot}%{_usr}/lib/systemd/user
PODMAN_VERSION=%{version} %{__make} PREFIX=%{buildroot}%{_prefix} ETCDIR=%{buildroot}%{_sysconfdir} \
install.bin \
install.remote \
@@ -483,6 +488,8 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath}
%{_datadir}/containers/%{repo}.conf
%{_unitdir}/io.podman.service
%{_unitdir}/io.podman.socket
+%{_usr}/lib/systemd/user/io.podman.service
+%{_usr}/lib/systemd/user/io.podman.socket
%{_usr}/lib/tmpfiles.d/%{name}.conf
%if 0%{?with_devel}
diff --git a/contrib/varlink/io.podman.service b/contrib/varlink/io.podman.service
index c524ce815..725198e79 100644
--- a/contrib/varlink/io.podman.service
+++ b/contrib/varlink/io.podman.service
@@ -6,7 +6,8 @@ Documentation=man:podman-varlink(1)
[Service]
Type=simple
-ExecStart=/usr/bin/podman varlink unix:/run/podman/io.podman
+ExecStart=/usr/bin/podman varlink unix:%t/podman/io.podman
+KillMode=none
[Install]
WantedBy=multi-user.target
diff --git a/contrib/varlink/io.podman.socket b/contrib/varlink/io.podman.socket
index 0f09fe3ef..f6a3ddc49 100644
--- a/contrib/varlink/io.podman.socket
+++ b/contrib/varlink/io.podman.socket
@@ -3,7 +3,7 @@ Description=Podman Remote API Socket
Documentation=man:podman-varlink(1)
[Socket]
-ListenStream=/run/podman/io.podman
+ListenStream=%t/podman/io.podman
SocketMode=0600
[Install]
diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md
index c4667070d..8deb8811e 100644
--- a/docs/podman-build.1.md
+++ b/docs/podman-build.1.md
@@ -168,6 +168,15 @@ The [username[:password]] to use to authenticate with the registry if required.
If one or both values are not supplied, a command line prompt will appear and the
value can be entered. The password is entered without echo.
+**--disable-compression, -D**
+
+Don't compress filesystem layers when building the image unless it is required
+by the location where the image is being written. This is the default setting,
+because image layers are compressed automatically when they are pushed to
+registries, and images being written to local storage would only need to be
+decompressed again to be stored. Compression can be forced in all cases by
+specifying **--disable-compression=false**.
+
**--disable-content-trust**
This is a Docker specific option to disable image verification to a Docker
@@ -178,6 +187,10 @@ solely for scripting compatibility.
Set custom DNS servers
+This option can be used to override the DNS configuration passed to the container. Typically this is necessary when the host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this is the case the `--dns` flag is necessary for every run.
+
+The special value **none** can be specified to disable creation of /etc/resolv.conf in the container by Podman. The /etc/resolv.conf file in the image will be used without changes.
+
**--dns-option**=*option*
Set custom DNS options
@@ -259,6 +272,12 @@ environment variable. `export BUILDAH_LAYERS=true`
Log output which would be sent to standard output and standard error to the
specified file instead of to standard output and standard error.
+**--loglevel** *number*
+
+Adjust the logging level up or down. Valid option values range from -2 to 3,
+with 3 being roughly equivalent to using the global *--debug* option, and
+values below 0 omitting even error messages which accompany fatal errors.
+
**--memory**, **-m**=*LIMIT*
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
@@ -301,6 +320,12 @@ that the PID namespace in which `podman` itself is being run should be reused,
or it can be the path to a PID namespace which is already in use by another
process.
+**--platform**="Linux"
+
+This option has no effect on the build. Other container engines use this option
+to control the execution platform for the build (e.g., Windows, Linux) which is
+not required for Buildah as it supports only Linux.
+
**--pull**
When the flag is enabled, attempt to pull the latest image from the registries
@@ -350,18 +375,18 @@ to podman build, the option given would be `--runtime-flag log-format=json`.
Security Options
- "label=user:USER" : Set the label user for the container
- "label=role:ROLE" : Set the label role for the container
- "label=type:TYPE" : Set the label type for the container
- "label=level:LEVEL" : Set the label level for the container
- "label=disable" : Turn off label confinement for the container
- "no-new-privileges" : Not supported
+- `apparmor=unconfined` : Turn off apparmor confinement for the container
+- `apparmor=your-profile` : Set the apparmor confinement profile for the container
- "seccomp=unconfined" : Turn off seccomp confinement for the container
- "seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
+- `label=user:USER` : Set the label user for the container processes
+- `label=role:ROLE` : Set the label role for the container processes
+- `label=type:TYPE` : Set the label process type for the container processes
+- `label=level:LEVEL` : Set the label level for the container processes
+- `label=filetype:TYPE` : Set the label file type for the container files
+- `label=disable` : Turn off label separation for the container
- "apparmor=unconfined" : Turn off apparmor confinement for the container
- "apparmor=your-profile" : Set the apparmor confinement profile for the container
+- `seccomp=unconfined` : Turn off seccomp confinement for the container
+- `seccomp=profile.json` : White listed syscalls seccomp Json file to be used as a seccomp filter
**--shm-size**=*size*
diff --git a/docs/podman-container-restore.1.md b/docs/podman-container-restore.1.md
index 544a096d8..a49cb7421 100644
--- a/docs/podman-container-restore.1.md
+++ b/docs/podman-container-restore.1.md
@@ -67,6 +67,15 @@ from a checkpoint tar.gz file it is possible that it also contains all root file
changes. With **--ignore-rootfs** it is possible to explicitly disable applying these
root file-system changes to the restored container.
+**--ignore-static-ip**
+
+If the container was started with **--ip** the restored container also tries to use that
+IP address and restore fails if that IP address is already in use. This can happen, if
+a container is restored multiple times from an exported checkpoint with **--name, -n**.
+
+Using **--ignore-static-ip** tells Podman to ignore the IP address if it was configured
+with **--ip** during container creation.
+
## EXAMPLE
podman container restore mywebserver
diff --git a/docs/podman-container-runlabel.1.md b/docs/podman-container-runlabel.1.md
index aabeb092d..c16d8c3f4 100644
--- a/docs/podman-container-runlabel.1.md
+++ b/docs/podman-container-runlabel.1.md
@@ -20,8 +20,6 @@ If the container image has a LABEL INSTALL instruction like the following:
If the container image does not have the desired label, an error message will be displayed along with a non-zero
return code. If the image is not found in local storage, Podman will attempt to pull it first.
-Note: Podman will always ensure that `podman` is the first argument of the command being executed.
-
**LABEL**
The label name specified via the command.
@@ -45,7 +43,7 @@ Any additional arguments will be appended to the command.
## OPTIONS:
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 50fca3541..7634408f5 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -582,6 +582,15 @@ port to a random port on the host within an *ephemeral port range* defined by
`/proc/sys/net/ipv4/ip_local_port_range`. To find the mapping between the host
ports and the exposed ports, use `podman port`.
+**--pull**=*missing*
+
+Pull image before creating ("always"|"missing"|"never") (default "missing").
+ 'missing': default value, attempt to pull the latest image from the registries listed in registries.conf if a local image does not exist.Raise an error if the image is not in any listed registry and is not present locally.
+ 'always': Pull the image from the first registry it is found in as listed in registries.conf. Raise an error if not found in the registries, even if the image is present locally.
+ 'never': do not pull the image from the registry, use only the local version. Raise an error if the image is not present locally.
+
+Defaults to *missing*.
+
**--quiet**, **-q**
Suppress output information when pulling images
@@ -631,19 +640,20 @@ of the container is assumed to be managed externally.
Security Options
-"apparmor=unconfined" : Turn off apparmor confinement for the container
-"apparmor=your-profile" : Set the apparmor confinement profile for the container
+- `apparmor=unconfined` : Turn off apparmor confinement for the container
+- `apparmor=your-profile` : Set the apparmor confinement profile for the container
-"label=user:USER" : Set the label user for the container
-"label=role:ROLE" : Set the label role for the container
-"label=type:TYPE" : Set the label type for the container
-"label=level:LEVEL" : Set the label level for the container
-"label=disable" : Turn off label confinement for the container
+- `label=user:USER` : Set the label user for the container processes
+- `label=role:ROLE` : Set the label role for the container processes
+- `label=type:TYPE` : Set the label process type for the container processes
+- `label=level:LEVEL` : Set the label level for the container processes
+- `label=filetype:TYPE` : Set the label file type for the container files
+- `label=disable` : Turn off label separation for the container
-"no-new-privileges" : Disable container processes from gaining additional privileges
+- `no-new-privileges` : Disable container processes from gaining additional privileges
-"seccomp=unconfined" : Turn off seccomp confinement for the container
-"seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
+- `seccomp=unconfined` : Turn off seccomp confinement for the container
+- `seccomp=profile.json` : White listed syscalls seccomp Json file to be used as a seccomp filter
Note: Labeling can be disabled for all containers by setting label=false in the **libpod.conf** (`/etc/containers/libpod.conf`) file.
@@ -715,7 +725,7 @@ $ podman run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image
This command mounts a `tmpfs` at `/tmp` within the container. The supported mount
options are the same as the Linux default `mount` flags. If you do not specify
any options, the systems uses the following options:
-`rw,noexec,nosuid,nodev,size=65536k`.
+`rw,noexec,nosuid,nodev`.
**--tty**, **-t**=*true|false*
diff --git a/docs/podman-events.1.md b/docs/podman-events.1.md
index 2097bb1f9..ed3faedfd 100644
--- a/docs/podman-events.1.md
+++ b/docs/podman-events.1.md
@@ -68,7 +68,7 @@ Print usage statement.
**--format**
-Format the output using the given Go template. An output value of *json* is not supported.
+Format the output to JSON Lines or using the given Go template.
**--filter**=*filter*
@@ -134,6 +134,13 @@ $ sudo podman events --since 5m
2019-03-02 10:44:42.374637304 -0600 CST pod create ca731231718e (image=, name=webapp)
```
+Show podman events in JSON Lines format
+```
+events --format json
+{"ID":"683b0909d556a9c02fa8cd2b61c3531a965db42158627622d1a67b391964d519","Image":"localhost/myshdemo:latest","Name":"agitated_diffie","Status":"cleanup","Time":"2019-04-27T22:47:00.849932843-04:00","Type":"container"}
+{"ID":"a0f8ab051bfd43f9c5141a8a2502139707e4b38d98ac0872e57c5315381e88ad","Image":"docker.io/library/alpine:latest","Name":"friendly_tereshkova","Status":"unmount","Time":"2019-04-28T13:43:38.063017276-04:00","Type":"container"}
+```
+
## SEE ALSO
podman(1)
diff --git a/docs/podman-login.1.md b/docs/podman-login.1.md
index 9be67e5a4..9d368e9f2 100644
--- a/docs/podman-login.1.md
+++ b/docs/podman-login.1.md
@@ -11,7 +11,7 @@ podman\-login - Login to a container registry
and password. **podman login** reads in the username and password from STDIN.
The username and password can also be set using the **username** and **password** flags.
The path of the authentication file can be specified by the user by setting the **authfile**
-flag. The default path used is **${XDG\_RUNTIME_DIR}/containers/auth.json**.
+flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**.
**podman [GLOBAL OPTIONS]**
@@ -35,7 +35,7 @@ Username for registry
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`
diff --git a/docs/podman-logout.1.md b/docs/podman-logout.1.md
index 56d661309..01dc52ecd 100644
--- a/docs/podman-logout.1.md
+++ b/docs/podman-logout.1.md
@@ -9,7 +9,7 @@ podman\-logout - Logout of a container registry
## DESCRIPTION
**podman logout** logs out of a specified registry server by deleting the cached credentials
stored in the **auth.json** file. The path of the authentication file can be overridden by the user by setting the **authfile** flag.
-The default path used is **${XDG\_RUNTIME_DIR}/containers/auth.json**.
+The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**.
All the cached credentials can be removed by setting the **all** flag.
**podman [GLOBAL OPTIONS]**
@@ -22,7 +22,7 @@ All the cached credentials can be removed by setting the **all** flag.
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`
diff --git a/docs/podman-network-inspect.1.md b/docs/podman-network-inspect.1.md
new file mode 100644
index 000000000..576e61c79
--- /dev/null
+++ b/docs/podman-network-inspect.1.md
@@ -0,0 +1,50 @@
+% podman-network-inspect(1)
+
+## NAME
+podman\-network-inspect- Inspect one or more Podman networks
+
+## SYNOPSIS
+**podman network inspect** [*network* ...]
+
+## DESCRIPTION
+Display the raw (JSON format) network configuration. This command is not available for rootless users.
+
+## EXAMPLE
+
+Inspect the default podman network
+
+```
+# podman network inspect podman
+[{
+ "cniVersion": "0.3.0",
+ "name": "podman",
+ "plugins": [
+ {
+ "type": "bridge",
+ "bridge": "cni0",
+ "isGateway": true,
+ "ipMasq": true,
+ "ipam": {
+ "type": "host-local",
+ "subnet": "10.88.1.0/24",
+ "routes": [
+ { "dst": "0.0.0.0/0" }
+ ]
+ }
+ },
+ {
+ "type": "portmap",
+ "capabilities": {
+ "portMappings": true
+ }
+ }
+ ]
+}
+]
+```
+
+## SEE ALSO
+podman(1), podman-network(1), podman-network-ls(1)
+
+## HISTORY
+August 2019, Originally compiled by Brent Baude <bbaude@redhat.com>
diff --git a/docs/podman-network-ls.1.md b/docs/podman-network-ls.1.md
new file mode 100644
index 000000000..725e07dbb
--- /dev/null
+++ b/docs/podman-network-ls.1.md
@@ -0,0 +1,43 @@
+% podman-network-ls(1)
+
+## NAME
+podman\-network-ls- Display a summary of CNI networks
+
+## SYNOPSIS
+**podman network ls** [*options*]
+
+## DESCRIPTION
+Displays a list of existing podman networks. This command is not available for rootless users.
+
+## OPTIONS
+**--quiet**, **-q**
+
+The `quiet` options will restrict the output to only the network names
+
+## EXAMPLE
+
+Display networks
+
+```
+# podman network ls
+NAME VERSION PLUGINS
+podman 0.3.0 bridge,portmap
+podman2 0.3.0 bridge,portmap
+outside 0.3.0 bridge
+podman9 0.3.0 bridge,portmap
+```
+
+Display only network names
+```
+# podman network ls -q
+podman
+podman2
+outside
+podman9
+```
+
+## SEE ALSO
+podman(1), podman-network(1), podman-network-inspect(1)
+
+## HISTORY
+August 2019, Originally compiled by Brent Baude <bbaude@redhat.com>
diff --git a/docs/podman-network-rm.1.md b/docs/podman-network-rm.1.md
new file mode 100644
index 000000000..f72d6a694
--- /dev/null
+++ b/docs/podman-network-rm.1.md
@@ -0,0 +1,25 @@
+% podman-network-rm(1)
+
+## NAME
+podman\-network-rm- Delete a Podman CNI network
+
+## SYNOPSIS
+**podman network rm** [*network...*]
+
+## DESCRIPTION
+Delete one or more Podman networks.
+
+## EXAMPLE
+
+Delete the `podman9` network
+
+```
+# podman network rm podman
+Deleted: podman9
+```
+
+## SEE ALSO
+podman(1), podman-network(1), podman-network-inspect(1)
+
+## HISTORY
+August 2019, Originally compiled by Brent Baude <bbaude@redhat.com>
diff --git a/docs/podman-network.1.md b/docs/podman-network.1.md
new file mode 100644
index 000000000..c01adc23e
--- /dev/null
+++ b/docs/podman-network.1.md
@@ -0,0 +1,21 @@
+% podman-network(1)
+
+## NAME
+podman\-network- Manage podman CNI networks
+
+## SYNOPSIS
+**podman network** *subcommand*
+
+## DESCRIPTION
+The network command manages CNI networks for Podman. It is not supported for rootless users.
+
+## COMMANDS
+
+| Command | Man Page | Description |
+| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
+| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md)| Displays the raw CNI network configuration for one or more networks|
+| ls | [podman-network-ls(1)](podman-network-ls.1.md)| Display a summary of CNI networks |
+| rm | [podman-network-rm(1)](podman-network-rm.1.md)| Remove one or more CNI networks |
+
+## SEE ALSO
+podman(1)
diff --git a/docs/podman-play-kube.1.md b/docs/podman-play-kube.1.md
index 2fae09199..8b78c83d0 100644
--- a/docs/podman-play-kube.1.md
+++ b/docs/podman-play-kube.1.md
@@ -19,7 +19,7 @@ Note: HostPath volume types created by play kube will be given an SELinux privat
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
diff --git a/docs/podman-pull.1.md b/docs/podman-pull.1.md
index 2d6d42959..8774075e1 100644
--- a/docs/podman-pull.1.md
+++ b/docs/podman-pull.1.md
@@ -53,7 +53,7 @@ Note: When using the all-tags flag, Podman will not iterate over the search regi
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
diff --git a/docs/podman-push.1.md b/docs/podman-push.1.md
index 4ac901919..2058a432c 100644
--- a/docs/podman-push.1.md
+++ b/docs/podman-push.1.md
@@ -46,7 +46,7 @@ Image stored in local container/storage
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index 209a07c0c..33b5cbf9e 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -56,7 +56,7 @@ each of stdin, stdout, and stderr.
**--authfile**[=*path*]
-Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`
@@ -601,6 +601,15 @@ When using -P, podman will bind any exposed port to a random port on the host
within an *ephemeral port range* defined by `/proc/sys/net/ipv4/ip_local_port_range`.
To find the mapping between the host ports and the exposed ports, use `podman port`.
+**--pull**=*missing*
+
+Pull image before running ("always"|"missing"|"never") (default "missing").
+ 'missing': default value, attempt to pull the latest image from the registries listed in registries.conf if a local image does not exist.Raise an error if the image is not in any listed registry and is not present locally.
+ 'always': Pull the image from the first registry it is found in as listed in registries.conf. Raise an error if not found in the registries, even if the image is present locally.
+ 'never': do not pull the image from the registry, use only the local version. Raise an error if the image is not present locally.
+
+Defaults to *missing*.
+
**--quiet**, **-q**
Suppress output information when pulling images
@@ -656,11 +665,12 @@ Security Options
- `apparmor=unconfined` : Turn off apparmor confinement for the container
- `apparmor=your-profile` : Set the apparmor confinement profile for the container
-- `label=user:USER` : Set the label user for the container
-- `label=role:ROLE` : Set the label role for the container
-- `label=type:TYPE` : Set the label type for the container
-- `label=level:LEVEL` : Set the label level for the container
-- `label=disable` : Turn off label confinement for the container
+- `label=user:USER` : Set the label user for the container processes
+- `label=role:ROLE` : Set the label role for the container processes
+- `label=type:TYPE` : Set the label process type for the container processes
+- `label=level:LEVEL` : Set the label level for the container processes
+- `label=filetype:TYPE` : Set the label file type for the container files
+- `label=disable` : Turn off label separation for the container
- `no-new-privileges` : Disable container processes from gaining additional privileges
@@ -752,7 +762,7 @@ $ podman run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image
This command mounts a `tmpfs` at `/tmp` within the container. The supported mount
options are the same as the Linux default `mount` flags. If you do not specify
any options, the systems uses the following options:
-`rw,noexec,nosuid,nodev,size=65536k`.
+`rw,noexec,nosuid,nodev`.
**--tty**, **-t**=*true|false*
diff --git a/docs/podman-search.1.md b/docs/podman-search.1.md
index c68f94347..31de6f839 100644
--- a/docs/podman-search.1.md
+++ b/docs/podman-search.1.md
@@ -27,7 +27,7 @@ Note, searching without a search term will only work for registries that impleme
**--authfile**=*path*
-Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
+Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json (Not available for remote commands)
Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`
diff --git a/docs/podman.1.md b/docs/podman.1.md
index bfb5a9aec..33ea81ef6 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -161,6 +161,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. |
| [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. |
| [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. |
+| [podman-network(1)](podman-network.1.md) | Manage Podman CNI networks. |
| [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
| [podman-play(1)](podman-play.1.md) | Play pods and containers based on a structured input file. |
| [podman-pod(1)](podman-pod.1.md) | Management tool for groups of containers, called pods. |
@@ -223,7 +224,7 @@ When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.con
## Rootless mode
Podman can also be used as non-root user. When podman runs in rootless mode, a user namespace is automatically created for the user, defined in /etc/subuid and /etc/subgid.
-Containers created by a non-root user are not visible to other users and are not seen or managed by podman running as root.
+Containers created by a non-root user are not visible to other users and are not seen or managed by Podman running as root.
It is required to have multiple uids/gids set for an user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`.
@@ -244,6 +245,14 @@ Images are pulled under `XDG_DATA_HOME` when specified, otherwise in the home di
Currently the slirp4netns package is required to be installed to create a network device, otherwise rootless containers need to run in the network namespace of the host.
+### **NOTE:** Unsupported file systems in rootless mode
+
+The Overlay file system (OverlayFS) is not supported in rootless mode. The fuse-overlayfs package is a tool that provides the functionality of OverlayFS in user namespace that allows mounting file systems in rootless environments. It is recommended to install the fuse-overlayfs package and to enable it by adding `mount_program = "/usr/bin/fuse-overlayfs"` under `[storage.options]` in the `~/.config/containers/storage.conf` file.
+
+The Network File System (NFS) and other distributed file systems (for example: Lustre, Spectrum Scale, the General Parallel File System (GPFS)) are not supported when running in rootless mode as these file systems do not understand user namespace. However, rootless Podman can make use of an NFS Homedir by modifying the `~/.config/containers/storage.conf` to have the `graphroot` option point to a directory stored on local (Non NFS) storage.
+
+For more information, please refer to the [Podman Troubleshooting Page](https://github.com/containers/libpod/blob/master/troubleshooting.md).
+
## SEE ALSO
`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)`
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index ad0c5ae88..925cfb970 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -7,3 +7,7 @@
**[Introduction Tutorial](https://github.com/containers/libpod/tree/master/docs/tutorials/podman_tutorial.md)**
Learn how to setup Podman and perform some basic commands with the utility.
+
+**[Basic Setup and Use of Podman in a Rootless environment.](https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md).
+
+The steps required to setup rootless Podman are enumerated.
diff --git a/docs/tutorials/rootless_tutorial.md b/docs/tutorials/rootless_tutorial.md
index 553e8d297..9453e3855 100644
--- a/docs/tutorials/rootless_tutorial.md
+++ b/docs/tutorials/rootless_tutorial.md
@@ -76,7 +76,9 @@ Once the Administrator has completed the setup on the machine and then the confi
### User Configuration Files.
-The Podman configuration files for root reside in /etc/containers. In the rootless environment they reside in ${HOME}/.config/containers and are owned by each individual user. The user can modify these files as they wish.
+The Podman configuration files for root reside in /usr/share/containers with overrides in /etc/containers. In the rootless environment they reside in ${XDG\_CONFIG\_HOME}/containers and are owned by each individual user. The user can modify these files as they wish.
+
+The default authorization file used by the `podman login` and `podman logout` commands reside in ${XDG\_RUNTIME\_DIR}/containers/auth.json.
## More information
diff --git a/go.mod b/go.mod
index d41a795c0..5f3b3ea66 100644
--- a/go.mod
+++ b/go.mod
@@ -13,11 +13,11 @@ require (
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
github.com/containernetworking/cni v0.7.1
github.com/containernetworking/plugins v0.8.1
- github.com/containers/buildah v1.9.2
+ github.com/containers/buildah v1.10.1
github.com/containers/conmon v0.3.0 // indirect
- github.com/containers/image v2.0.1+incompatible
+ github.com/containers/image v3.0.2+incompatible
github.com/containers/psgo v1.3.1
- github.com/containers/storage v1.12.16
+ github.com/containers/storage v1.13.2
github.com/coreos/bbolt v1.3.3 // indirect
github.com/coreos/etcd v3.3.13+incompatible // indirect
github.com/coreos/go-iptables v0.4.1
@@ -69,7 +69,7 @@ require (
github.com/opencontainers/runc v1.0.0-rc8
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7
github.com/opencontainers/runtime-tools v0.9.0
- github.com/opencontainers/selinux v1.2.2
+ github.com/opencontainers/selinux v1.3.0
github.com/opentracing/opentracing-go v1.1.0
github.com/pelletier/go-toml v1.4.0 // indirect
github.com/pkg/errors v0.8.1
@@ -91,7 +91,6 @@ require (
github.com/ugorji/go v1.1.5-pre // indirect
github.com/ulikunitz/xz v0.5.6 // indirect
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b
- github.com/vbauerster/mpb v3.4.0+incompatible // indirect
github.com/vishvananda/netlink v1.0.0
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
go.etcd.io/bbolt v1.3.3 // indirect
diff --git a/go.sum b/go.sum
index de700bc29..e837f0efc 100644
--- a/go.sum
+++ b/go.sum
@@ -71,12 +71,16 @@ github.com/containers/buildah v1.9.0 h1:ktVRCGNoVfW8PlTuCKUeh+zGdqn1Nik80DSWvGX+
github.com/containers/buildah v1.9.0/go.mod h1:1CsiLJvyU+h+wOjnqJJOWuJCVcMxZOr5HN/gHGdzJxY=
github.com/containers/buildah v1.9.2 h1:dg87r1W1poWVQE0lTmP3BzaqgEI5IRudZ3jKjNIZ3xQ=
github.com/containers/buildah v1.9.2/go.mod h1:UFq7EQtnDEEZv42AE7ZbmQMN+mSWSg1JIMwjYW1bn48=
+github.com/containers/buildah v1.10.1 h1:YBFHZkpbWCxUR/gjRAZrRzs2E0DfdUe3+/8OA9filWY=
+github.com/containers/buildah v1.10.1/go.mod h1:ZTyMFo3IQlu9tYndtnAf0Tjf2NdeUL6bY2/TpP9uIuU=
github.com/containers/conmon v0.3.0 h1:NDkYcQAu1BDZSVLh6xrY9jh/WmiDaUloKzRM16237XM=
github.com/containers/conmon v0.3.0/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image v2.0.0+incompatible h1:FTr6Br7jlIKNCKMjSOMbAxKp2keQ0//jzJaYNTVhauk=
github.com/containers/image v2.0.0+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
github.com/containers/image v2.0.1+incompatible h1:w39mlElA/aSFZ6moFa5N+A4MWu9c8hgdMiMMYnH94Hs=
github.com/containers/image v2.0.1+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/image v3.0.2+incompatible h1:B1lqAE8MUPCrsBLE86J0gnXleeRq8zJnQryhiiGQNyE=
+github.com/containers/image v3.0.2+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
github.com/containers/psgo v1.3.0 h1:kDhiA4gNNyJ2qCzmOuBf6AmrF/Pp+6Jo98P68R7fB8I=
github.com/containers/psgo v1.3.0/go.mod h1:7MELvPTW1fj6yMrwD9I1Iasx1vU+hKlRkHXAJ51sFtU=
github.com/containers/psgo v1.3.1-0.20190626112706-fbef66e4ce92 h1:aVJs/Av0Yc9uNoWnIwmG+6Z+XozuRXFwvLwAOVmwlvI=
@@ -93,6 +97,10 @@ github.com/containers/storage v1.12.13 h1:GtaLCY8p1Drlk1Oew581jGvB137UaO+kpz0HII
github.com/containers/storage v1.12.13/go.mod h1:+RirK6VQAqskQlaTBrOG6ulDvn4si2QjFE1NZCn06MM=
github.com/containers/storage v1.12.16 h1:zePYS1GiG8CuRqLCeA0ufx4X27K06HcJLV50DdojL+Y=
github.com/containers/storage v1.12.16/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
+github.com/containers/storage v1.13.1 h1:rjVirLS9fCGkUFlLDZEoGDDUugtIf46DufWvJu08wxQ=
+github.com/containers/storage v1.13.1/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
+github.com/containers/storage v1.13.2 h1:UXZ0Ckmk6+6+4vj2M2ywruVtH97pnRoAhTG8ctd+yQI=
+github.com/containers/storage v1.13.2/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -386,6 +394,8 @@ github.com/opencontainers/selinux v0.0.0-20190118194635-b707dfcb00a1 h1:V8Icxoi2
github.com/opencontainers/selinux v0.0.0-20190118194635-b707dfcb00a1/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg=
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
+github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
+github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/openshift/imagebuilder v1.1.0 h1:oT704SkwMEzmIMU/+Uv1Wmvt+p10q3v2WuYMeFI18c4=
github.com/openshift/imagebuilder v1.1.0/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/opentracing/opentracing-go v0.0.0-20190218023034-25a84ff92183 h1:kwFCLTA0DYhH0JpGMBOZtVVhyRL5ec+unn4mnoJhQI0=
@@ -432,6 +442,8 @@ github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNG
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.8.0/go.mod h1:fSI0j+IUQrDd7+ZtR9WKIGtoYAYAJUKcKhYLG25tN4g=
+github.com/rhatdan/oci-selinux v0.0.0-20190809194358-225b95ae1d0b h1:9CE1lDQ/YC1deOJE/elAI+nbE1OzOxSvrs6JXwyn+1s=
+github.com/rhatdan/oci-selinux v0.0.0-20190809194358-225b95ae1d0b/go.mod h1:T/CPBeRZLtTvck9OtpX3PGw/uDABnTuRPhyTacu5aSo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh
index 90e3aea8e..e1588d570 100755
--- a/hack/get_ci_vm.sh
+++ b/hack/get_ci_vm.sh
@@ -68,9 +68,10 @@ delvm() {
}
image_hints() {
+ _BIS=$(egrep -m 1 '_BUILT_IMAGE_SUFFIX:[[:space:]+"[[:print:]]+"' "$LIBPODROOT/.cirrus.yml" | cut -d: -f 2 | tr -d '"[:blank:]')
egrep '[[:space:]]+[[:alnum:]].+_CACHE_IMAGE_NAME:[[:space:]+"[[:print:]]+"' \
"$LIBPODROOT/.cirrus.yml" | cut -d: -f 2 | tr -d '"[:blank:]' | \
- grep -v 'notready' | sort -u
+ sed -r -e "s/\\\$[{]_BUILT_IMAGE_SUFFIX[}]/$_BIS/" | sort -u
}
show_usage() {
diff --git a/install.md b/install.md
index 49a67f984..d8d70a7b6 100644
--- a/install.md
+++ b/install.md
@@ -26,6 +26,14 @@ Built-in, no need to install
sudo emerge app-emulation/libpod
```
+#### [MacOS](https://www.apple.com/macos)
+
+Using [Homebrew](https://brew.sh/):
+
+```bash
+brew cask install podman
+```
+
#### [openSUSE](https://www.opensuse.org)
```bash
diff --git a/libpod/container.go b/libpod/container.go
index 2d96b1120..9c01d2adf 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -377,6 +377,9 @@ type ContainerConfig struct {
RestartRetries uint `json:"restart_retries,omitempty"`
// TODO log options for log drivers
+ // PostConfigureNetNS needed when a user namespace is created by an OCI runtime
+ // if the network namespace is created before the user namespace it will be
+ // owned by the wrong user namespace.
PostConfigureNetNS bool `json:"postConfigureNetNS"`
// OCIRuntime used to create the container
diff --git a/libpod/container_api.go b/libpod/container_api.go
index ef9c3f006..abcfcb271 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -773,6 +773,11 @@ type ContainerCheckpointOptions struct {
// IgnoreRootfs tells the API to not export changes to
// the container's root file-system (or to not import)
IgnoreRootfs bool
+ // IgnoreStaticIP tells the API to ignore the IP set
+ // during 'podman run' with '--ip'. This is especially
+ // important to be able to restore a container multiple
+ // times with '--import --name'.
+ IgnoreStaticIP bool
}
// Checkpoint checkpoints a container
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index aba9c5b93..313f67963 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1152,9 +1152,27 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e
c.newContainerEvent(events.Restart)
if c.state.State == define.ContainerStateRunning {
+ conmonPID := c.state.ConmonPID
if err := c.stop(timeout); err != nil {
return err
}
+ // Old versions of conmon have a bug where they create the exit file before
+ // closing open file descriptors causing a race condition when restarting
+ // containers with open ports since we cannot bind the ports as they're not
+ // yet closed by conmon.
+ //
+ // Killing the old conmon PID is ~okay since it forces the FDs of old conmons
+ // to be closed, while it's a NOP for newer versions which should have
+ // exited already.
+ if conmonPID != 0 {
+ // Ignore errors from FindProcess() as conmon could already have exited.
+ p, err := os.FindProcess(conmonPID)
+ if p != nil && err == nil {
+ if err = p.Kill(); err != nil {
+ logrus.Debugf("error killing conmon process: %v", err)
+ }
+ }
+ }
}
defer func() {
if err != nil {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 6dbd53fbf..5aa4ee9a9 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -471,9 +471,9 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
return err
}
- g.RemoveMount("/sys/fs/cgroup")
-
if unified {
+ g.RemoveMount("/sys/fs/cgroup")
+
sourcePath := filepath.Join("/sys/fs/cgroup")
systemdMnt := spec.Mount{
Destination: "/sys/fs/cgroup",
@@ -483,31 +483,13 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
}
g.AddMount(systemdMnt)
} else {
- // rootless containers have no write access to /sys/fs/cgroup, so don't
- // add any mount into the container.
- if !rootless.IsRootless() {
- cgroupPath, err := c.CGroupPath()
- if err != nil {
- return err
- }
- sourcePath := filepath.Join("/sys/fs/cgroup", cgroupPath)
-
- systemdMnt := spec.Mount{
- Destination: "/sys/fs/cgroup",
- Type: "bind",
- Source: sourcePath,
- Options: []string{"bind", "private"},
- }
- g.AddMount(systemdMnt)
- } else {
- systemdMnt := spec.Mount{
- Destination: "/sys/fs/cgroup",
- Type: "bind",
- Source: "/sys/fs/cgroup",
- Options: []string{"bind", "nodev", "noexec", "nosuid"},
- }
- g.AddMount(systemdMnt)
+ systemdMnt := spec.Mount{
+ Destination: "/sys/fs/cgroup/systemd",
+ Type: "bind",
+ Source: "/sys/fs/cgroup/systemd",
+ Options: []string{"bind", "nodev", "noexec", "nosuid"},
}
+ g.AddMount(systemdMnt)
}
return nil
@@ -743,6 +725,14 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
return err
}
+ // If a container is restored multiple times from an exported checkpoint with
+ // the help of '--import --name', the restore will fail if during 'podman run'
+ // a static container IP was set with '--ip'. The user can tell the restore
+ // process to ignore the static IP with '--ignore-static-ip'
+ if options.IgnoreStaticIP {
+ c.config.StaticIP = nil
+ }
+
// Read network configuration from checkpoint
// Currently only one interface with one IP is supported.
networkStatusFile, err := os.Open(filepath.Join(c.bundlePath(), "network.status"))
@@ -752,7 +742,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
// TODO: This implicit restoring with or without IP depending on an
// unrelated restore parameter (--name) does not seem like the
// best solution.
- if err == nil && options.Name == "" {
+ if err == nil && options.Name == "" && !options.IgnoreStaticIP {
// The file with the network.status does exist. Let's restore the
// container with the same IP address as during checkpointing.
defer networkStatusFile.Close()
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index a4368a9aa..9d532263c 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -107,4 +107,8 @@ var (
// ErrOCIRuntimeNotFound indicates the OCI runtime attempted to invoke a command
// that was not found
ErrOCIRuntimeNotFound = errors.New("OCI runtime command not found error")
+
+ // ErrConmonOutdated indicates the version of conmon found (whether via the configuration or $PATH)
+ // is out of date for the current podman version
+ ErrConmonOutdated = errors.New("outdated conmon version")
)
diff --git a/libpod/driver/driver.go b/libpod/driver/driver.go
index f9442fa21..85eda5a21 100644
--- a/libpod/driver/driver.go
+++ b/libpod/driver/driver.go
@@ -38,6 +38,10 @@ func GetDriverData(store cstorage.Store, layerID string) (*Data, error) {
if err != nil {
return nil, err
}
+ if mountTimes, err := store.Mounted(layerID); mountTimes == 0 || err != nil {
+ delete(metaData, "MergedDir")
+ }
+
return &Data{
Name: name,
Data: metaData,
diff --git a/libpod/events/config.go b/libpod/events/config.go
index 96172d47b..453c64f8c 100644
--- a/libpod/events/config.go
+++ b/libpod/events/config.go
@@ -22,13 +22,13 @@ const (
type Event struct {
// ContainerExitCode is for storing the exit code of a container which can
// be used for "internal" event notification
- ContainerExitCode int
+ ContainerExitCode int `json:",omitempty"`
// ID can be for the container, image, volume, etc
- ID string
+ ID string `json:",omitempty"`
// Image used where applicable
- Image string
+ Image string `json:",omitempty"`
// Name where applicable
- Name string
+ Name string `json:",omitempty"`
// Status describes the event that occurred
Status Status
// Time the event occurred
@@ -53,6 +53,8 @@ type Eventer interface {
Write(event Event) error
// Read an event from the backend
Read(options ReadOptions) error
+ // String returns the type of event logger
+ String() string
}
// ReadOptions describe the attributes needed to read event logs
diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go
index d5bce4334..470c76959 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -4,6 +4,7 @@ package events
import (
"fmt"
+ "strconv"
"time"
"github.com/coreos/go-systemd/journal"
@@ -42,6 +43,9 @@ func (e EventJournalD) Write(ee Event) error {
m["PODMAN_IMAGE"] = ee.Image
m["PODMAN_NAME"] = ee.Name
m["PODMAN_ID"] = ee.ID
+ if ee.ContainerExitCode != 0 {
+ m["PODMAN_EXIT_CODE"] = strconv.Itoa(ee.ContainerExitCode)
+ }
case Volume:
m["PODMAN_NAME"] = ee.Name
}
@@ -54,18 +58,26 @@ func (e EventJournalD) Read(options ReadOptions) error {
if err != nil {
return errors.Wrapf(err, "failed to generate event options")
}
- podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint
- j, err := sdjournal.NewJournal() //nolint
+ j, err := sdjournal.NewJournal() //nolint
if err != nil {
return err
}
- if err := j.AddMatch(podmanJournal.String()); err != nil {
- return errors.Wrap(err, "failed to add filter for event log")
- }
+ // TODO AddMatch and Seek seem to conflict
+ // Issue filed upstream -> https://github.com/coreos/go-systemd/issues/315
+ // Leaving commented code in case upstream fixes things
+ //podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint
+ //if err := j.AddMatch(podmanJournal.String()); err != nil {
+ // return errors.Wrap(err, "failed to add filter for event log")
+ //}
if len(options.Since) == 0 && len(options.Until) == 0 && options.Stream {
if err := j.SeekTail(); err != nil {
return errors.Wrap(err, "failed to seek end of journal")
}
+ } else {
+ podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint
+ if err := j.AddMatch(podmanJournal.String()); err != nil {
+ return errors.Wrap(err, "failed to add filter for event log")
+ }
}
// the api requires a next|prev before getting a cursor
if _, err := j.Next(); err != nil {
@@ -96,6 +108,12 @@ func (e EventJournalD) Read(options ReadOptions) error {
if err != nil {
return err
}
+ // TODO this keeps us from feeding the podman event parser with
+ // with regular journal content; it can be removed if the above
+ // problem with AddMatch is resolved.
+ if entry.Fields["PODMAN_EVENT"] == "" {
+ continue
+ }
newEvent, err := newEventFromJournalEntry(entry)
if err != nil {
// We can't decode this event.
@@ -141,8 +159,21 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { /
case Container, Pod:
newEvent.ID = entry.Fields["PODMAN_ID"]
newEvent.Image = entry.Fields["PODMAN_IMAGE"]
+ if code, ok := entry.Fields["PODMAN_EXIT_CODE"]; ok {
+ intCode, err := strconv.Atoi(code)
+ if err != nil {
+ logrus.Errorf("Error parsing event exit code %s", code)
+ } else {
+ newEvent.ContainerExitCode = intCode
+ }
+ }
case Image:
newEvent.ID = entry.Fields["PODMAN_ID"]
}
return &newEvent, nil
}
+
+// String returns a string representation of the logger
+func (e EventJournalD) String() string {
+ return Journald.String()
+}
diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go
index 30d72b9fc..4b65b0ad0 100644
--- a/libpod/events/logfile.go
+++ b/libpod/events/logfile.go
@@ -71,3 +71,8 @@ func (e EventLogFile) Read(options ReadOptions) error {
close(options.EventChannel)
return nil
}
+
+// String returns a string representation of the logger
+func (e EventLogFile) String() string {
+ return LogFile.String()
+}
diff --git a/libpod/events/nullout.go b/libpod/events/nullout.go
index b11afcf80..f3b36e609 100644
--- a/libpod/events/nullout.go
+++ b/libpod/events/nullout.go
@@ -17,6 +17,10 @@ func (e EventToNull) Read(options ReadOptions) error {
// NewNullEventer returns a new null eventer. You should only do this for
// the purposes on internal libpod testing.
func NewNullEventer() Eventer {
- e := EventToNull{}
- return e
+ return EventToNull{}
+}
+
+// String returns a string representation of the logger
+func (e EventToNull) String() string {
+ return "none"
}
diff --git a/libpod/image/docker_registry_options.go b/libpod/image/docker_registry_options.go
index c191a3ca2..60bb3c33f 100644
--- a/libpod/image/docker_registry_options.go
+++ b/libpod/image/docker_registry_options.go
@@ -1,8 +1,12 @@
package image
import (
+ "fmt"
+
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
+
+ podmanVersion "github.com/containers/libpod/version"
)
// DockerRegistryOptions encapsulates settings that affect how we connect or
@@ -36,6 +40,7 @@ func (o DockerRegistryOptions) GetSystemContext(parent *types.SystemContext, add
sc.SignaturePolicyPath = parent.SignaturePolicyPath
sc.AuthFilePath = parent.AuthFilePath
sc.DirForceCompress = parent.DirForceCompress
+ sc.DockerRegistryUserAgent = parent.DockerRegistryUserAgent
}
return sc
}
@@ -48,5 +53,7 @@ func GetSystemContext(signaturePolicyPath, authFilePath string, forceCompress bo
}
sc.AuthFilePath = authFilePath
sc.DirForceCompress = forceCompress
+ sc.DockerRegistryUserAgent = fmt.Sprintf("libpod/%s", podmanVersion.Version)
+
return sc
}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 068491f28..cb7c390c6 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -135,7 +135,7 @@ func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
// New creates a new image object where the image could be local
// or remote
-func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool, label *string) (*Image, error) {
+func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, label *string, pullType util.PullType) (*Image, error) {
span, _ := opentracing.StartSpanFromContext(ctx, "newImage")
span.SetTag("type", "runtime")
defer span.Finish()
@@ -145,11 +145,13 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
InputName: name,
imageruntime: ir,
}
- if !forcePull {
+ if pullType != util.PullImageAlways {
localImage, err := newImage.getLocalImage()
if err == nil {
newImage.image = localImage
return &newImage, nil
+ } else if pullType == util.PullImageNever {
+ return nil, err
}
}
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index e93ebf797..5a6d095f6 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -3,12 +3,13 @@ package image
import (
"context"
"fmt"
- "github.com/containers/libpod/libpod/events"
"io"
"io/ioutil"
"os"
"testing"
+ "github.com/containers/libpod/libpod/events"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
@@ -89,9 +90,9 @@ func TestImage_NewFromLocal(t *testing.T) {
ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
ir.Eventer = events.NewNullEventer()
- bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false, nil)
+ bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, nil, util.PullImageMissing)
assert.NoError(t, err)
- bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false, nil)
+ bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, nil, util.PullImageMissing)
assert.NoError(t, err)
tm, err := makeLocalMatrix(bb, bbglibc)
@@ -139,7 +140,7 @@ func TestImage_New(t *testing.T) {
// Iterate over the names and delete the image
// after the pull
for _, img := range names {
- newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false, nil)
+ newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, nil, util.PullImageMissing)
assert.NoError(t, err)
assert.NotEqual(t, newImage.ID(), "")
err = newImage.Remove(context.Background(), false)
@@ -168,7 +169,7 @@ func TestImage_MatchRepoTag(t *testing.T) {
ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
ir.Eventer = events.NewNullEventer()
- newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false, nil)
+ newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, nil, util.PullImageMissing)
assert.NoError(t, err)
err = newImage.TagImage("foo:latest")
assert.NoError(t, err)
diff --git a/libpod/info.go b/libpod/info.go
index 4a89fa648..9ab6f7e52 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -102,7 +102,7 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
return nil, errors.Wrapf(err, "error getting hostname")
}
info["hostname"] = host
-
+ info["eventlogger"] = r.eventer.String()
return info, nil
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 2eb004b84..4ba3114e3 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -60,6 +60,7 @@ type OCIRuntime struct {
noPivot bool
reservePorts bool
supportsJSON bool
+ sdNotify bool
}
// ociError is used to parse the OCI runtime JSON log. It is not part of the
@@ -87,6 +88,7 @@ func newOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *R
runtime.logSizeMax = runtimeCfg.MaxLogSize
runtime.noPivot = runtimeCfg.NoPivotRoot
runtime.reservePorts = runtimeCfg.EnablePortReservation
+ runtime.sdNotify = runtimeCfg.SDNotify
// TODO: probe OCI runtime for feature and enable automatically if
// available.
diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go
index 0bcd021db..6e4ee2cf2 100644
--- a/libpod/oci_internal_linux.go
+++ b/libpod/oci_internal_linux.go
@@ -247,10 +247,14 @@ func (r *OCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*os.File
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
}
- if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok {
- env = append(env, fmt.Sprintf("LISTEN_FDS=%s", listenfds), "LISTEN_PID=1")
- fds := activation.Files(false)
- extraFiles = append(extraFiles, fds...)
+ if !r.sdNotify {
+ if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok {
+ env = append(env, fmt.Sprintf("LISTEN_FDS=%s", listenfds), "LISTEN_PID=1")
+ fds := activation.Files(false)
+ extraFiles = append(extraFiles, fds...)
+ }
+ } else {
+ logrus.Debug("disabling SD notify")
}
return env, extraFiles, nil
}
@@ -278,6 +282,10 @@ func (r *OCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath
// No case here should happen except JSONLogging, but keep this here in case the options are extended
logrus.Errorf("%s logging specified but not supported. Choosing k8s-file logging instead", ctr.LogDriver())
fallthrough
+ case "":
+ // to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod
+ // since the former case is obscure, and the latter case isn't an error, let's silently fallthrough
+ fallthrough
case KubernetesLogging:
logDriver = fmt.Sprintf("%s:%s", KubernetesLogging, logPath)
}
@@ -348,31 +356,29 @@ func startCommandGivenSelinux(cmd *exec.Cmd) error {
// it then signals for conmon to start by sending nonse data down the start fd
func (r *OCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File, uuid string) error {
cgroupParent := ctr.CgroupParent()
- if os.Geteuid() == 0 {
- if r.cgroupManager == SystemdCgroupsManager {
- unitName := createUnitName("libpod-conmon", ctr.ID())
-
- realCgroupParent := cgroupParent
- splitParent := strings.Split(cgroupParent, "/")
- if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 {
- realCgroupParent = splitParent[len(splitParent)-1]
- }
+ if r.cgroupManager == SystemdCgroupsManager {
+ unitName := createUnitName("libpod-conmon", ctr.ID())
- logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName)
- if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil {
- logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
- }
+ realCgroupParent := cgroupParent
+ splitParent := strings.Split(cgroupParent, "/")
+ if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 {
+ realCgroupParent = splitParent[len(splitParent)-1]
+ }
+
+ logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName)
+ if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil {
+ logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
+ }
+ } else {
+ cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
+ control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
+ if err != nil {
+ logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
} else {
- cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
- control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
- if err != nil {
+ // we need to remove this defer and delete the cgroup once conmon exits
+ // maybe need a conmon monitor?
+ if err := control.AddPid(cmd.Process.Pid); err != nil {
logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- } else {
- // we need to remove this defer and delete the cgroup once conmon exits
- // maybe need a conmon monitor?
- if err := control.AddPid(cmd.Process.Pid); err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- }
}
}
}
diff --git a/libpod/options.go b/libpod/options.go
index 3a123a2a6..a7ddbec34 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -482,6 +482,15 @@ func WithEventsLogger(logger string) RuntimeOption {
}
}
+// WithEnableSDNotify sets a runtime option so we know whether to disable socket/FD
+// listening
+func WithEnableSDNotify() RuntimeOption {
+ return func(rt *Runtime) error {
+ rt.config.SDNotify = true
+ return nil
+ }
+}
+
// Container Creation Options
// WithShmDir sets the directory that should be mounted on /dev/shm.
@@ -1499,6 +1508,24 @@ func WithPodName(name string) PodCreateOption {
}
}
+// WithPodHostname sets the hostname of the pod.
+func WithPodHostname(hostname string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ // Check the hostname against a regex
+ if !nameRegex.MatchString(hostname) {
+ return regexError
+ }
+
+ pod.config.Hostname = hostname
+
+ return nil
+ }
+}
+
// WithPodLabels sets the labels of a pod.
func WithPodLabels(labels map[string]string) PodCreateOption {
return func(pod *Pod) error {
diff --git a/libpod/pod.go b/libpod/pod.go
index 60626bfd7..3b9bb9c60 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -36,6 +36,8 @@ type PodConfig struct {
// Namespace the pod is in
Namespace string `json:"namespace,omitempty"`
+ Hostname string `json:"hostname,omitempty"`
+
// Labels contains labels applied to the pod
Labels map[string]string `json:"labels"`
// CgroupParent contains the pod's CGroup parent
diff --git a/libpod/runtime.go b/libpod/runtime.go
index ffdbc32f1..2fa8dd424 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "bytes"
"context"
"fmt"
"io/ioutil"
@@ -8,6 +9,8 @@ import (
"os/exec"
"os/user"
"path/filepath"
+ "regexp"
+ "strconv"
"strings"
"sync"
"syscall"
@@ -52,7 +55,7 @@ const (
var (
// InstallPrefix is the prefix where podman will be installed.
// It can be overridden at build time.
- installPrefix = "/usr/local"
+ installPrefix = "/usr"
// EtcDir is the sysconfdir where podman should look for system config files.
// It can be overridden at build time.
etcDir = "/etc"
@@ -249,6 +252,10 @@ type RuntimeConfig struct {
EventsLogFilePath string `toml:"-events_logfile_path"`
//DetachKeys is the sequence of keys used to detach a container
DetachKeys string `toml:"detach_keys"`
+
+ // SDNotify tells Libpod to allow containers to notify the host
+ // systemd of readiness using the SD_NOTIFY mechanism
+ SDNotify bool
}
// runtimeConfiguredFrom is a struct used during early runtime init to help
@@ -271,6 +278,8 @@ type runtimeConfiguredFrom struct {
runtimePath bool
cniPluginDir bool
noPivotRoot bool
+ runtimeSupportsJSON bool
+ ociRuntime bool
}
func defaultRuntimeConfig() (RuntimeConfig, error) {
@@ -328,16 +337,19 @@ func defaultRuntimeConfig() (RuntimeConfig, error) {
}, nil
}
-// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set
-// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
-// It internally calls EnableLinger() so that the user's processes are not
+// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
+// containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is
+// use for the libpod.conf configuration file.
+// SetXdgDirs internally calls EnableLinger() so that the user's processes are not
// killed once the session is terminated. EnableLinger() also attempts to
// get the runtime directory when XDG_RUNTIME_DIR is not specified.
-func SetXdgRuntimeDir() error {
+// This function should only be called when running rootless.
+func SetXdgDirs() error {
if !rootless.IsRootless() {
return nil
}
+ // Setup XDG_RUNTIME_DIR
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
runtimeDirLinger, err := rootless.EnableLinger()
@@ -365,6 +377,16 @@ func SetXdgRuntimeDir() error {
if err := os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil {
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
+
+ // Setup XDG_CONFIG_HOME
+ if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" {
+ if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil {
+ return err
+ }
+ if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil {
+ return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME")
+ }
+ }
return nil
}
@@ -577,6 +599,12 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
if tmpConfig.NoPivotRoot {
runtime.configuredFrom.noPivotRoot = true
}
+ if tmpConfig.RuntimeSupportsJSON != nil {
+ runtime.configuredFrom.runtimeSupportsJSON = true
+ }
+ if tmpConfig.OCIRuntime != "" {
+ runtime.configuredFrom.ociRuntime = true
+ }
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath)
@@ -617,6 +645,13 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
if !runtime.configuredFrom.noPivotRoot {
runtime.config.NoPivotRoot = tmpConfig.NoPivotRoot
}
+ if !runtime.configuredFrom.runtimeSupportsJSON {
+ runtime.config.RuntimeSupportsJSON = tmpConfig.RuntimeSupportsJSON
+ }
+ if !runtime.configuredFrom.ociRuntime {
+ runtime.config.OCIRuntime = tmpConfig.OCIRuntime
+ }
+
break
}
}
@@ -726,11 +761,43 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) {
return manager, nil
}
+// probeConmon calls conmon --version and verifies it is a new enough version for
+// the runtime expectations podman currently has
+func probeConmon(conmonBinary string) error {
+ cmd := exec.Command(conmonBinary, "--version")
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ err := cmd.Run()
+ if err != nil {
+ return err
+ }
+ r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`)
+
+ matches := r.FindStringSubmatch(out.String())
+ if len(matches) != 4 {
+ return errors.Wrapf(err, "conmon version changed format")
+ }
+ major, err := strconv.Atoi(matches[1])
+ if err != nil || major < 1 {
+ return define.ErrConmonOutdated
+ }
+ // conmon used to be shipped with CRI-O, and was versioned along with it.
+ // even though the conmon that came with crio-1.9 to crio-1.15 has a higher
+ // version number than conmon 1.0.0, 1.0.0 is newer, so we need this check
+ minor, err := strconv.Atoi(matches[2])
+ if err != nil || minor > 9 {
+ return define.ErrConmonOutdated
+ }
+
+ return nil
+}
+
// Make a new runtime based on the given configuration
// Sets up containers/storage, state store, OCI runtime
func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
// Find a working conmon binary
foundConmon := false
+ foundOutdatedConmon := false
for _, path := range runtime.config.ConmonPath {
stat, err := os.Stat(path)
if err != nil {
@@ -739,6 +806,11 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
if stat.IsDir() {
continue
}
+ if err := probeConmon(path); err != nil {
+ logrus.Warnf("conmon at %s invalid: %v", path, err)
+ foundOutdatedConmon = true
+ continue
+ }
foundConmon = true
runtime.conmonPath = path
logrus.Debugf("using conmon: %q", path)
@@ -748,13 +820,21 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
// Search the $PATH as last fallback
if !foundConmon {
if conmon, err := exec.LookPath("conmon"); err == nil {
- foundConmon = true
- runtime.conmonPath = conmon
- logrus.Debugf("using conmon from $PATH: %q", conmon)
+ if err := probeConmon(conmon); err != nil {
+ logrus.Warnf("conmon at %s is invalid: %v", conmon, err)
+ foundOutdatedConmon = true
+ } else {
+ foundConmon = true
+ runtime.conmonPath = conmon
+ logrus.Debugf("using conmon from $PATH: %q", conmon)
+ }
}
}
if !foundConmon {
+ if foundOutdatedConmon {
+ return errors.Wrapf(define.ErrConmonOutdated, "please update to v1.0.0 or later")
+ }
return errors.Wrapf(define.ErrInvalidArg,
"could not find a working conmon binary (configured options: %v)",
runtime.config.ConmonPath)
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 47d49f6aa..92b2faefb 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -52,6 +52,16 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config
if err != nil {
return nil, errors.Wrapf(err, "error initializing container variables")
}
+ // For an imported checkpoint no one has ever set the StartedTime. Set it now.
+ ctr.state.StartedTime = time.Now()
+
+ // If the path to ConmonPidFile starts with the default value (RunRoot), then
+ // the user has not specified '--conmon-pidfile' during run or create (probably).
+ // In that case reset ConmonPidFile to be set to the default value later.
+ if strings.HasPrefix(ctr.config.ConmonPidFile, r.config.StorageConfig.RunRoot) {
+ ctr.config.ConmonPidFile = ""
+ }
+
return r.setupContainer(ctx, ctr)
}
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 4055734eb..20dee4080 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -28,6 +28,7 @@ import (
// RemoveImage deletes an image from local storage
// Images being used by running containers can only be removed if force=true
func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool) (string, error) {
+ var returnMessage string
r.lock.Lock()
defer r.lock.Unlock()
@@ -93,7 +94,11 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool)
err = errStorage
}
}
- return img.ID(), err
+ for _, name := range img.Names() {
+ returnMessage = returnMessage + fmt.Sprintf("Untagged: %s\n", name)
+ }
+ returnMessage = returnMessage + fmt.Sprintf("Deleted: %s", img.ID())
+ return returnMessage, err
}
// Remove containers that are in storage rather than Podman.
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index da35b7f93..ad6662f03 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
"github.com/opencontainers/image-spec/specs-go/v1"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
@@ -30,6 +31,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
return nil, err
}
+ // Set Pod hostname
+ g.Config.Hostname = p.config.Hostname
+
isRootless := rootless.IsRootless()
entryCmd := []string{r.config.InfraCommand}
@@ -108,7 +112,7 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
return nil, define.ErrRuntimeStopped
}
- newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false, nil)
+ newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, nil, util.PullImageMissing)
if err != nil {
return nil, err
}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index f38e6e7c1..073c5054d 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -52,6 +52,10 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
pod.config.Name = name
}
+ if pod.config.Hostname == "" {
+ pod.config.Hostname = pod.config.Name
+ }
+
// Allocate a lock for the pod
lock, err := r.lockManager.AllocateLock()
if err != nil {
diff --git a/libpod/util_linux.go b/libpod/util_linux.go
index 78cbc75a7..d5c113daf 100644
--- a/libpod/util_linux.go
+++ b/libpod/util_linux.go
@@ -48,6 +48,9 @@ func makeSystemdCgroup(path string) error {
return err
}
+ if rootless.IsRootless() {
+ return controller.CreateSystemdUserUnit(path, rootless.GetRootlessUID())
+ }
return controller.CreateSystemdUnit(path)
}
@@ -57,6 +60,14 @@ func deleteSystemdCgroup(path string) error {
if err != nil {
return err
}
+ if rootless.IsRootless() {
+ conn, err := cgroups.GetUserConnection(rootless.GetRootlessUID())
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return controller.DeleteByPathConn(path, conn)
+ }
return controller.DeleteByPath(path)
}
diff --git a/pkg/adapter/checkpoint_restore.go b/pkg/adapter/checkpoint_restore.go
index 1cac86d12..15f9e8105 100644
--- a/pkg/adapter/checkpoint_restore.go
+++ b/pkg/adapter/checkpoint_restore.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/errorhandling"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage/pkg/archive"
jsoniter "github.com/json-iterator/go"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -112,7 +113,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
return nil, err
}
- _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil)
+ _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing)
if err != nil {
return nil, err
}
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
index 694d9f961..da6ff5fd0 100644
--- a/pkg/adapter/client.go
+++ b/pkg/adapter/client.go
@@ -16,7 +16,7 @@ var remoteEndpoint *Endpoint
func (r RemoteRuntime) RemoteEndpoint() (remoteEndpoint *Endpoint, err error) {
remoteConfigConnections, err := remoteclientconfig.ReadRemoteConfig(r.config)
- if errors.Cause(err) != remoteclientconfig.ErrNoConfigationFile {
+ if err != nil && errors.Cause(err) != remoteclientconfig.ErrNoConfigationFile {
return nil, err
}
// If the user defines an env variable for podman_varlink_bridge
@@ -68,7 +68,6 @@ func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
if err != nil {
return nil, err
}
-
switch ep.Type {
case DirectConnection:
return varlink.NewConnection(ep.Connection)
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 155454e21..45a9a54a3 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -342,7 +342,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
- if strings.Contains(err.Error(), "permission denied") {
+ if strings.Contains(err.Error(), "permission denied") || strings.Contains(err.Error(), "file not found") {
exitCode = 126
}
return exitCode, err
@@ -539,6 +539,7 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
TargetFile: c.Import,
Name: c.Name,
IgnoreRootfs: c.IgnoreRootfs,
+ IgnoreStaticIP: c.IgnoreStaticIP,
}
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
diff --git a/pkg/adapter/network.go b/pkg/adapter/network.go
new file mode 100644
index 000000000..cf3a1dfdd
--- /dev/null
+++ b/pkg/adapter/network.go
@@ -0,0 +1,147 @@
+// +build !remoteclient
+
+package adapter
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/containernetworking/cni/libcni"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/network"
+ "github.com/pkg/errors"
+)
+
+func getCNIConfDir(r *LocalRuntime) (string, error) {
+ config, err := r.GetConfig()
+ if err != nil {
+ return "", err
+ }
+ configPath := config.CNIConfigDir
+
+ if len(config.CNIConfigDir) < 1 {
+ configPath = network.CNIConfigDir
+ }
+ return configPath, nil
+}
+
+// NetworkList displays summary information about CNI networks
+func (r *LocalRuntime) NetworkList(cli *cliconfig.NetworkListValues) error {
+ cniConfigPath, err := getCNIConfDir(r)
+ if err != nil {
+ return err
+ }
+ networks, err := network.LoadCNIConfsFromDir(cniConfigPath)
+ if err != nil {
+ return err
+ }
+ // quiet means we only print the network names
+ if cli.Quiet {
+ for _, cniNetwork := range networks {
+ fmt.Println(cniNetwork.Name)
+ }
+ return nil
+ }
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
+ if _, err := fmt.Fprintln(w, "NAME\tVERSION\tPLUGINS"); err != nil {
+ return err
+ }
+ for _, cniNetwork := range networks {
+ if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", cniNetwork.Name, cniNetwork.CNIVersion, getCNIPlugins(cniNetwork)); err != nil {
+ return err
+ }
+ }
+ return w.Flush()
+}
+
+// NetworkInspect displays the raw CNI configuration for one
+// or more CNI networks
+func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error {
+ var (
+ rawCNINetworks []map[string]interface{}
+ )
+ cniConfigPath, err := getCNIConfDir(r)
+ if err != nil {
+ return err
+ }
+ for _, name := range cli.InputArgs {
+ b, err := readRawCNIConfByName(name, cniConfigPath)
+ if err != nil {
+ return err
+ }
+ rawList := make(map[string]interface{})
+ if err := json.Unmarshal(b, &rawList); err != nil {
+ return fmt.Errorf("error parsing configuration list: %s", err)
+ }
+ rawCNINetworks = append(rawCNINetworks, rawList)
+ }
+ out, err := json.MarshalIndent(rawCNINetworks, "", "\t")
+ if err != nil {
+ return err
+ }
+ fmt.Printf("%s\n", out)
+ return nil
+}
+
+// NetworkRemove deletes one or more CNI networks
+func (r *LocalRuntime) NetworkRemove(cli *cliconfig.NetworkRmValues) error {
+ cniConfigPath, err := getCNIConfDir(r)
+ if err != nil {
+ return err
+ }
+ for _, name := range cli.InputArgs {
+ cniPath, err := getCNIConfigPathByName(name, cniConfigPath)
+ if err != nil {
+ return err
+ }
+ if err := os.Remove(cniPath); err != nil {
+ return err
+ }
+ fmt.Printf("Deleted: %s\n", name)
+ }
+ return nil
+}
+
+// getCNIConfigPathByName finds a CNI network by name and
+// returns its configuration file path
+func getCNIConfigPathByName(name, cniConfigPath string) (string, error) {
+ files, err := libcni.ConfFiles(cniConfigPath, []string{".conflist"})
+ if err != nil {
+ return "", err
+ }
+ for _, confFile := range files {
+ conf, err := libcni.ConfListFromFile(confFile)
+ if err != nil {
+ return "", err
+ }
+ if conf.Name == name {
+ return confFile, nil
+ }
+ }
+ return "", errors.Errorf("unable to find network configuration for %s", name)
+}
+
+// readRawCNIConfByName reads the raw CNI configuration for a CNI
+// network by name
+func readRawCNIConfByName(name, cniConfigPath string) ([]byte, error) {
+ confFile, err := getCNIConfigPathByName(name, cniConfigPath)
+ if err != nil {
+ return nil, err
+ }
+ b, err := ioutil.ReadFile(confFile)
+ return b, err
+}
+
+// getCNIPlugins returns a list of plugins that a given network
+// has in the form of a string
+func getCNIPlugins(list *libcni.NetworkConfigList) string {
+ var plugins []string
+ for _, plug := range list.Plugins {
+ plugins = append(plugins, plug.Network.Type)
+ }
+ return strings.Join(plugins, ",")
+}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index e25238956..ded805de2 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -19,6 +19,7 @@ import (
"github.com/containers/libpod/pkg/adapter/shortcuts"
ns "github.com/containers/libpod/pkg/namespaces"
createconfig "github.com/containers/libpod/pkg/spec"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/ghodss/yaml"
@@ -255,6 +256,10 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa
options = append(options, libpod.WithPodName(cli.Name))
}
+ if cli.Flag("hostname").Changed {
+ options = append(options, libpod.WithPodHostname(cli.Hostname))
+ }
+
if cli.Infra {
options = append(options, libpod.WithInfraContainer())
nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ","))
@@ -475,6 +480,12 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
podOptions = append(podOptions, libpod.WithPodName(podName))
// TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
+ hostname := podYAML.Spec.Hostname
+ if hostname == "" {
+ hostname = podName
+ }
+ podOptions = append(podOptions, libpod.WithPodHostname(hostname))
+
nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ","))
if err != nil {
return nil, err
@@ -578,7 +589,7 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
}
for _, container := range podYAML.Spec.Containers {
- newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, false, nil)
+ newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageMissing)
if err != nil {
return nil, err
}
@@ -707,6 +718,8 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name)
}
+ containerConfig.UserCommand = containerConfig.Command
+
containerConfig.StopSignal = 15
// If the user does not pass in ID mappings, just set to basics
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 452d0159f..7d4f97b28 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/formats"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
@@ -23,6 +24,7 @@ import (
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
"k8s.io/api/core/v1"
@@ -131,8 +133,8 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type
}
// New calls into local storage to look for an image in local storage or to pull it
-func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
- img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull, label)
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, label *string, pullType util.PullType) (*ContainerImage, error) {
+ img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, label, pullType)
if err != nil {
return nil, err
}
@@ -297,9 +299,12 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti
options.CommonBuildOpts = commonOpts
options.SystemContext = systemContext
- if c.Flag("runtime").Changed {
+ if c.GlobalFlags.Runtime != "" {
+ options.Runtime = c.GlobalFlags.Runtime
+ } else {
options.Runtime = r.GetOCIRuntimePath()
}
+
if c.Quiet {
options.ReportWriter = ioutil.Discard
}
@@ -360,9 +365,13 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
fromStart bool
eventsError error
)
- tmpl, err := template.New("events").Parse(c.Format)
- if err != nil {
- return err
+ var tmpl *template.Template
+ if c.Format != formats.JSONString {
+ template, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+ tmpl = template
}
if len(c.Since) > 0 || len(c.Until) > 0 {
fromStart = true
@@ -378,7 +387,15 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
}
w := bufio.NewWriter(os.Stdout)
for event := range eventChannel {
- if len(c.Format) > 0 {
+ if c.Format == formats.JSONString {
+ jsonStr, err := event.ToJSONString()
+ if err != nil {
+ return errors.Wrapf(err, "unable to format json")
+ }
+ if _, err := w.Write([]byte(jsonStr)); err != nil {
+ return err
+ }
+ } else if len(c.Format) > 0 {
if err := tmpl.Execute(w, event); err != nil {
return err
}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 92478aa0f..f4eb926c9 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -10,13 +10,13 @@ import (
"io"
"io/ioutil"
"os"
+ "path/filepath"
"strings"
"text/template"
"time"
- v1 "k8s.io/api/core/v1"
-
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/formats"
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
@@ -26,12 +26,14 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/containers/storage/pkg/archive"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/varlink/go/varlink"
+ v1 "k8s.io/api/core/v1"
)
// ImageRuntime is wrapper for image runtime
@@ -68,6 +70,12 @@ func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime,
cmd: c.GlobalFlags,
}
configPath := remoteclientconfig.GetConfigFilePath()
+ // Check if the basedir for configPath exists and if not, create it.
+ if _, err := os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) {
+ if mkdirErr := os.MkdirAll(filepath.Dir(configPath), 0750); mkdirErr != nil {
+ return nil, mkdirErr
+ }
+ }
if len(c.GlobalFlags.RemoteConfigFilePath) > 0 {
configPath = c.GlobalFlags.RemoteConfigFilePath
customConfig = true
@@ -265,7 +273,7 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type
}
// New calls into local storage to look for an image in local storage or to pull it
-func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, label *string, pullType util.PullType) (*ContainerImage, error) {
var iid string
if label != nil {
return nil, errors.New("the remote client function does not support checking a remote image for a label")
@@ -819,9 +827,13 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
}
w := bufio.NewWriter(os.Stdout)
- tmpl, err := template.New("events").Parse(c.Format)
- if err != nil {
- return err
+ var tmpl *template.Template
+ if c.Format != formats.JSONString {
+ template, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+ tmpl = template
}
for {
@@ -855,7 +867,15 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
Time: eTime,
Type: eType,
}
- if len(c.Format) > 0 {
+ if c.Format == formats.JSONString {
+ jsonStr, err := event.ToJSONString()
+ if err != nil {
+ return errors.Wrapf(err, "unable to format json")
+ }
+ if _, err := w.Write([]byte(jsonStr)); err != nil {
+ return err
+ }
+ } else if len(c.Format) > 0 {
if err := tmpl.Execute(w, event); err != nil {
return err
}
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index f2c6b548e..085718855 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -10,6 +10,8 @@ import (
"strconv"
"strings"
+ systemdDbus "github.com/coreos/go-systemd/dbus"
+ "github.com/godbus/dbus"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -352,7 +354,56 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error {
if !c.systemd {
return fmt.Errorf("the cgroup controller is not using systemd")
}
- return systemdCreate(path)
+
+ conn, err := systemdDbus.New()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ return systemdCreate(path, conn)
+}
+
+// GetUserConnection returns an user connection to D-BUS
+func GetUserConnection(uid int) (*systemdDbus.Conn, error) {
+ return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
+ return dbusAuthConnection(uid, dbus.SessionBusPrivate)
+ })
+}
+
+// CreateSystemdUserUnit creates the systemd cgroup for the specified user
+func (c *CgroupControl) CreateSystemdUserUnit(path string, uid int) error {
+ if !c.systemd {
+ return fmt.Errorf("the cgroup controller is not using systemd")
+ }
+
+ conn, err := GetUserConnection(uid)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ return systemdCreate(path, conn)
+}
+
+func dbusAuthConnection(uid int, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
+ conn, err := createBus()
+ if err != nil {
+ return nil, err
+ }
+
+ methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))}
+
+ err = conn.Auth(methods)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ if err := conn.Hello(); err != nil {
+ return nil, err
+ }
+
+ return conn, nil
}
// Delete cleans a cgroup
@@ -386,10 +437,11 @@ func rmDirRecursively(path string) error {
return nil
}
-// DeleteByPath deletes the specified cgroup path
-func (c *CgroupControl) DeleteByPath(path string) error {
+// DeleteByPathConn deletes the specified cgroup path using the specified
+// dbus connection if needed.
+func (c *CgroupControl) DeleteByPathConn(path string, conn *systemdDbus.Conn) error {
if c.systemd {
- return systemdDestroy(path)
+ return systemdDestroyConn(path, conn)
}
if c.cgroup2 {
return rmDirRecursively(filepath.Join(cgroupRoot, c.path))
@@ -413,6 +465,19 @@ func (c *CgroupControl) DeleteByPath(path string) error {
return lastError
}
+// DeleteByPath deletes the specified cgroup path
+func (c *CgroupControl) DeleteByPath(path string) error {
+ if c.systemd {
+ conn, err := systemdDbus.New()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return c.DeleteByPathConn(path, conn)
+ }
+ return c.DeleteByPathConn(path, nil)
+}
+
// Update updates the cgroups
func (c *CgroupControl) Update(resources *spec.LinuxResources) error {
for _, h := range handlers {
diff --git a/pkg/cgroups/systemd.go b/pkg/cgroups/systemd.go
index e72e456bc..b8e6db156 100644
--- a/pkg/cgroups/systemd.go
+++ b/pkg/cgroups/systemd.go
@@ -9,13 +9,7 @@ import (
"github.com/godbus/dbus"
)
-func systemdCreate(path string) error {
- c, err := systemdDbus.New()
- if err != nil {
- return err
- }
- defer c.Close()
-
+func systemdCreate(path string, c *systemdDbus.Conn) error {
slice, name := filepath.Split(path)
slice = strings.TrimSuffix(slice, "/")
@@ -43,7 +37,7 @@ func systemdCreate(path string) error {
}
ch := make(chan string)
- _, err = c.StartTransientUnit(name, "replace", properties, ch)
+ _, err := c.StartTransientUnit(name, "replace", properties, ch)
if err != nil {
lastError = err
continue
@@ -55,7 +49,7 @@ func systemdCreate(path string) error {
}
/*
- systemdDestroy is copied from containerd/cgroups/systemd.go file, that
+ systemdDestroyConn is copied from containerd/cgroups/systemd.go file, that
has the following license:
Copyright The containerd Authors.
@@ -72,18 +66,11 @@ func systemdCreate(path string) error {
See the License for the specific language governing permissions and
limitations under the License.
*/
-
-func systemdDestroy(path string) error {
- c, err := systemdDbus.New()
- if err != nil {
- return err
- }
- defer c.Close()
-
+func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
name := filepath.Base(path)
ch := make(chan string)
- _, err = c.StopUnit(name, "replace", ch)
+ _, err := c.StopUnit(name, "replace", ch)
if err != nil {
return err
}
diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go
index b962ffa5c..0d26bf4af 100644
--- a/pkg/hooks/hooks.go
+++ b/pkg/hooks/hooks.go
@@ -4,6 +4,7 @@ package hooks
import (
"context"
"fmt"
+ "os"
"sort"
"strings"
"sync"
@@ -56,7 +57,7 @@ func New(ctx context.Context, directories []string, extensionStages []string) (m
for _, dir := range directories {
err = ReadDir(dir, manager.extensionStages, manager.hooks)
- if err != nil {
+ if err != nil && !os.IsNotExist(err) {
return nil, err
}
}
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
index 35298796f..9d1033b93 100644
--- a/pkg/namespaces/namespaces.go
+++ b/pkg/namespaces/namespaces.go
@@ -4,17 +4,30 @@ import (
"strings"
)
+const (
+ bridgeType = "bridge"
+ containerType = "container"
+ defaultType = "default"
+ hostType = "host"
+ noneType = "none"
+ nsType = "ns"
+ podType = "pod"
+ privateType = "private"
+ shareableType = "shareable"
+ slirpType = "slirp4netns"
+)
+
// CgroupMode represents cgroup mode in the container.
type CgroupMode string
// IsHost indicates whether the container uses the host's cgroup.
func (n CgroupMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsNS indicates a cgroup namespace passed in by path (ns:<path>)
func (n CgroupMode) IsNS() bool {
- return strings.HasPrefix(string(n), "ns:")
+ return strings.HasPrefix(string(n), nsType)
}
// NS gets the path associated with a ns:<path> cgroup ns
@@ -29,13 +42,13 @@ func (n CgroupMode) NS() string {
// IsContainer indicates whether the container uses a new cgroup namespace.
func (n CgroupMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container returns the name of the container whose cgroup namespace is going to be used.
func (n CgroupMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -43,15 +56,15 @@ func (n CgroupMode) Container() string {
// IsPrivate indicates whether the container uses the a private cgroup.
func (n CgroupMode) IsPrivate() bool {
- return n == "private"
+ return n == privateType
}
// Valid indicates whether the Cgroup namespace is valid.
func (n CgroupMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host", "private", "ns":
- case "container":
+ case "", hostType, privateType, nsType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -66,7 +79,7 @@ type UsernsMode string
// IsHost indicates whether the container uses the host's userns.
func (n UsernsMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is lept inside of the namespace.
@@ -83,8 +96,8 @@ func (n UsernsMode) IsPrivate() bool {
func (n UsernsMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host", "keep-id", "ns":
- case "container":
+ case "", hostType, "keep-id", nsType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -111,13 +124,13 @@ func (n UsernsMode) NS() string {
// IsContainer indicates whether container uses a container userns.
func (n UsernsMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container is the id of the container which network this container is connected to.
func (n UsernsMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -133,19 +146,19 @@ func (n UTSMode) IsPrivate() bool {
// IsHost indicates whether the container uses the host's UTS namespace.
func (n UTSMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsContainer indicates whether the container uses a container's UTS namespace.
func (n UTSMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container returns the name of the container whose uts namespace is going to be used.
func (n UTSMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -155,8 +168,8 @@ func (n UTSMode) Container() string {
func (n UTSMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host":
- case "container":
+ case "", hostType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -171,28 +184,28 @@ type IpcMode string
// IsPrivate indicates whether the container uses its own private ipc namespace which cannot be shared.
func (n IpcMode) IsPrivate() bool {
- return n == "private"
+ return n == privateType
}
// IsHost indicates whether the container shares the host's ipc namespace.
func (n IpcMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsShareable indicates whether the container's ipc namespace can be shared with another container.
func (n IpcMode) IsShareable() bool {
- return n == "shareable"
+ return n == shareableType
}
// IsContainer indicates whether the container uses another container's ipc namespace.
func (n IpcMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// IsNone indicates whether container IpcMode is set to "none".
func (n IpcMode) IsNone() bool {
- return n == "none"
+ return n == noneType
}
// IsEmpty indicates whether container IpcMode is empty
@@ -208,7 +221,7 @@ func (n IpcMode) Valid() bool {
// Container returns the name of the container ipc stack is going to be used.
func (n IpcMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 && parts[0] == "container" {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -224,21 +237,21 @@ func (n PidMode) IsPrivate() bool {
// IsHost indicates whether the container uses the host's pid namespace.
func (n PidMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsContainer indicates whether the container uses a container's pid namespace.
func (n PidMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Valid indicates whether the pid namespace is valid.
func (n PidMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host":
- case "container":
+ case "", hostType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -251,7 +264,7 @@ func (n PidMode) Valid() bool {
// Container returns the name of the container whose pid namespace is going to be used.
func (n PidMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -262,17 +275,17 @@ type NetworkMode string
// IsNone indicates whether container isn't using a network stack.
func (n NetworkMode) IsNone() bool {
- return n == "none"
+ return n == noneType
}
// IsHost indicates whether the container uses the host's network stack.
func (n NetworkMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsDefault indicates whether container uses the default network stack.
func (n NetworkMode) IsDefault() bool {
- return n == "default"
+ return n == defaultType
}
// IsPrivate indicates whether container uses its private network stack.
@@ -283,13 +296,13 @@ func (n NetworkMode) IsPrivate() bool {
// IsContainer indicates whether container uses a container network stack.
func (n NetworkMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container is the id of the container which network this container is connected to.
func (n NetworkMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -305,17 +318,17 @@ func (n NetworkMode) UserDefined() string {
// IsBridge indicates whether container uses the bridge network stack
func (n NetworkMode) IsBridge() bool {
- return n == "bridge"
+ return n == bridgeType
}
// IsSlirp4netns indicates if we are running a rootless network stack
func (n NetworkMode) IsSlirp4netns() bool {
- return n == "slirp4netns"
+ return n == slirpType
}
// IsNS indicates a network namespace passed in by path (ns:<path>)
func (n NetworkMode) IsNS() bool {
- return strings.HasPrefix(string(n), "ns:")
+ return strings.HasPrefix(string(n), nsType)
}
// NS gets the path associated with a ns:<path> network ns
@@ -329,7 +342,7 @@ func (n NetworkMode) NS() string {
// IsPod returns whether the network refers to pod networking
func (n NetworkMode) IsPod() bool {
- return n == "pod"
+ return n == podType
}
// IsUserDefined indicates user-created network
diff --git a/pkg/network/config.go b/pkg/network/config.go
new file mode 100644
index 000000000..d282f66b6
--- /dev/null
+++ b/pkg/network/config.go
@@ -0,0 +1,4 @@
+package network
+
+// CNIConfigDir is the path where CNI config files exist
+const CNIConfigDir = "/etc/cni/net.d"
diff --git a/pkg/network/network.go b/pkg/network/network.go
new file mode 100644
index 000000000..9d04340a3
--- /dev/null
+++ b/pkg/network/network.go
@@ -0,0 +1,26 @@
+package network
+
+import (
+ "sort"
+
+ "github.com/containernetworking/cni/libcni"
+)
+
+// LoadCNIConfsFromDir loads all the CNI configurations from a dir
+func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
+ var configs []*libcni.NetworkConfigList
+ files, err := libcni.ConfFiles(dir, []string{".conflist"})
+ if err != nil {
+ return nil, err
+ }
+ sort.Strings(files)
+
+ for _, confFile := range files {
+ conf, err := libcni.ConfListFromFile(confFile)
+ if err != nil {
+ return nil, err
+ }
+ configs = append(configs, conf)
+ }
+ return configs, nil
+}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 19b76f387..94933ddd0 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -137,7 +137,7 @@ get_cmd_line_args (pid_t pid)
{
allocated += 512;
char *tmp = realloc (buffer, allocated);
- if (buffer == NULL)
+ if (tmp == NULL)
{
free (buffer);
return NULL;
@@ -276,7 +276,7 @@ static void __attribute__((constructor)) init()
return;
}
- r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf)));
+ r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1));
close (fd);
if (r < 0)
{
@@ -457,6 +457,11 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
}
r = TEMP_FAILURE_RETRY (write (p[1], "0", 1));
+ if (r < 0)
+ {
+ fprintf (stderr, "cannot write to pipe: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
close (p[1]);
_exit (EXIT_SUCCESS);
@@ -811,6 +816,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
}
ret = TEMP_FAILURE_RETRY (write (ready, "0", 1));
+ if (ret < 0)
+ {
+ fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
close (ready);
if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0)
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index f21ae2831..3f70e5935 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -64,8 +64,9 @@ type CreateConfig struct {
CidFile string
ConmonPidFile string
Cgroupns string
- CgroupParent string // cgroup-parent
- Command []string
+ CgroupParent string // cgroup-parent
+ Command []string // Full command that will be used
+ UserCommand []string // User-entered command (or image CMD)
Detach bool // detach
Devices []string // device
DNSOpt []string //dns-opt
@@ -230,8 +231,8 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
options = append(options, libpod.WithNamedVolumes(namedVolumes))
}
- if len(c.Command) != 0 {
- options = append(options, libpod.WithCommand(c.Command))
+ if len(c.UserCommand) != 0 {
+ options = append(options, libpod.WithCommand(c.UserCommand))
}
// Add entrypoint unconditionally
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index c94746767..156d6849d 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -174,10 +174,20 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
}
hostname := config.Hostname
- if hostname == "" && (config.NetMode.IsHost() || config.UtsMode.IsHost()) {
- hostname, err = os.Hostname()
- if err != nil {
- return nil, errors.Wrap(err, "unable to retrieve hostname")
+ if hostname == "" {
+ if utsCtrID := config.UtsMode.Container(); utsCtrID != "" {
+ utsCtr, err := runtime.GetContainer(utsCtrID)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
+ }
+ hostname = utsCtr.Hostname()
+ } else if config.NetMode.IsHost() || config.UtsMode.IsHost() {
+ hostname, err = os.Hostname()
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to retrieve hostname of the host")
+ }
+ } else {
+ logrus.Debug("No hostname set; container's hostname will default to runtime default")
}
}
g.RemoveHostname()
@@ -541,8 +551,8 @@ func addPidNS(config *CreateConfig, g *generate.Generator) error {
if pidMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
}
- if pidMode.IsContainer() {
- logrus.Debug("using container pidmode")
+ if pidCtr := pidMode.Container(); pidCtr != "" {
+ logrus.Debugf("using container %s pidmode", pidCtr)
}
if IsPod(string(pidMode)) {
logrus.Debug("using pod pidmode")
@@ -579,8 +589,8 @@ func addNetNS(config *CreateConfig, g *generate.Generator) error {
} else if netMode.IsBridge() {
logrus.Debug("Using bridge netmode")
return nil
- } else if netMode.IsContainer() {
- logrus.Debug("Using container netmode")
+ } else if netCtr := netMode.Container(); netCtr != "" {
+ logrus.Debugf("using container %s netmode", netCtr)
return nil
} else if IsNS(string(netMode)) {
logrus.Debug("Using ns netmode")
@@ -606,6 +616,9 @@ func addUTSNS(config *CreateConfig, g *generate.Generator) error {
if utsMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
}
+ if utsCtr := utsMode.Container(); utsCtr != "" {
+ logrus.Debugf("using container %s utsmode", utsCtr)
+ }
return nil
}
@@ -617,8 +630,8 @@ func addIpcNS(config *CreateConfig, g *generate.Generator) error {
if ipcMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
}
- if ipcMode.IsContainer() {
- logrus.Debug("Using container ipcmode")
+ if ipcCtr := ipcMode.Container(); ipcCtr != "" {
+ logrus.Debugf("Using container %s ipcmode", ipcCtr)
}
return nil
@@ -635,8 +648,8 @@ func addCgroupNS(config *CreateConfig, g *generate.Generator) error {
if cgroupMode.IsPrivate() {
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
}
- if cgroupMode.IsContainer() {
- logrus.Debug("Using container cgroup mode")
+ if cgCtr := cgroupMode.Container(); cgCtr != "" {
+ logrus.Debugf("Using container %s cgroup mode", cgCtr)
}
return nil
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index ac7a2c30f..b634f4cac 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -168,14 +168,14 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
"/run": false,
}
if config.ReadOnlyRootfs && config.ReadOnlyTmpfs {
- options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup", "size=65536k"}
+ options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
for dest := range readonlyTmpfs {
if _, ok := baseMounts[dest]; ok {
continue
}
localOpts := options
if dest == "/run" {
- localOpts = append(localOpts, "noexec")
+ localOpts = append(localOpts, "noexec", "size=65536k")
}
baseMounts[dest] = spec.Mount{
Destination: dest,
@@ -238,11 +238,6 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
// Conflicts are resolved simply - the last container specified wins.
// Container names may be suffixed by mount options after a colon.
func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
- // TODO: This can probably be disabled now
- if os.Geteuid() != 0 {
- return nil, nil, nil
- }
-
// 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)
@@ -410,13 +405,42 @@ func getBindMount(args []string) (spec.Mount, error) {
setSource := false
setDest := false
+ setRORW := false
for _, val := range args {
kv := strings.Split(val, "=")
switch kv[0] {
case "bind-nonrecursive":
newMount.Options = append(newMount.Options, "bind")
- case "ro", "nosuid", "nodev", "noexec":
+ 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]
+ if len(kv) == 1 {
+ newMount.Options = append(newMount.Options, kv[0])
+ } else if len(kv) == 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])
+ }
+ } else {
+ return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
+ }
+ case "nosuid", "nodev", "noexec":
// TODO: detect duplication of these options.
// (Is this necessary?)
newMount.Options = append(newMount.Options, kv[0])
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index 40c99384d..9b2c734c0 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -92,9 +92,6 @@ func ProcessTmpfsOptions(options []string) ([]string, error) {
if !foundWrite {
baseOpts = append(baseOpts, "rw")
}
- if !foundSize {
- baseOpts = append(baseOpts, "size=65536k")
- }
if !foundProp {
baseOpts = append(baseOpts, "rprivate")
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index fba34a337..3f73639e7 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -239,8 +239,10 @@ func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []strin
}
var (
- rootlessRuntimeDirOnce sync.Once
- rootlessRuntimeDir string
+ rootlessConfigHomeDirOnce sync.Once
+ rootlessConfigHomeDir string
+ rootlessRuntimeDirOnce sync.Once
+ rootlessRuntimeDir string
)
type tomlOptionsConfig struct {
@@ -354,3 +356,32 @@ func OpenExclusiveFile(path string) (*os.File, error) {
}
return os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
}
+
+// PullType whether to pull new image
+type PullType int
+
+const (
+ // PullImageAlways always try to pull new image when create or run
+ PullImageAlways PullType = iota
+ // PullImageMissing pulls image if it is not locally
+ PullImageMissing
+ // PullImageNever will never pull new image
+ PullImageNever
+)
+
+// ValidatePullType check if the pullType from CLI is valid and returns the valid enum type
+// if the value from CLI is invalid returns the error
+func ValidatePullType(pullType string) (PullType, error) {
+ switch pullType {
+ case "always":
+ return PullImageAlways, nil
+ case "missing":
+ return PullImageMissing, nil
+ case "never":
+ return PullImageNever, nil
+ case "":
+ return PullImageMissing, nil
+ default:
+ return PullImageMissing, errors.Errorf("invalid pull type %q", pullType)
+ }
+}
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index af55689a6..c7c8787a0 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -26,7 +26,7 @@ func GetRootlessRuntimeDir() (string, error) {
if runtimeDir == "" {
tmpDir := filepath.Join("/run", "user", uid)
if err := os.MkdirAll(tmpDir, 0700); err != nil {
- logrus.Errorf("unable to make temp dir %s", tmpDir)
+ logrus.Debugf("unable to make temp dir %s", tmpDir)
}
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
@@ -36,7 +36,7 @@ func GetRootlessRuntimeDir() (string, error) {
if runtimeDir == "" {
tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("run-%s", uid))
if err := os.MkdirAll(tmpDir, 0700); err != nil {
- logrus.Errorf("unable to make temp dir %s", tmpDir)
+ logrus.Debugf("unable to make temp dir %s", tmpDir)
}
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
@@ -65,6 +65,38 @@ func GetRootlessRuntimeDir() (string, error) {
return rootlessRuntimeDir, nil
}
+// GetRootlessConfigHomeDir returns the config home directory when running as non root
+func GetRootlessConfigHomeDir() (string, error) {
+ var rootlessConfigHomeDirError error
+
+ rootlessConfigHomeDirOnce.Do(func() {
+ cfgHomeDir := os.Getenv("XDG_CONFIG_HOME")
+ if cfgHomeDir == "" {
+ home := os.Getenv("HOME")
+ resolvedHome, err := filepath.EvalSymlinks(home)
+ if err != nil {
+ rootlessConfigHomeDirError = errors.Wrapf(err, "cannot resolve %s", home)
+ return
+ }
+ tmpDir := filepath.Join(resolvedHome, ".config")
+ if err := os.MkdirAll(tmpDir, 0755); err != nil {
+ logrus.Errorf("unable to make temp dir %s", tmpDir)
+ }
+ st, err := os.Stat(tmpDir)
+ if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0755 {
+ cfgHomeDir = tmpDir
+ }
+ }
+ rootlessConfigHomeDir = cfgHomeDir
+ })
+
+ if rootlessConfigHomeDirError != nil {
+ return "", rootlessConfigHomeDirError
+ }
+
+ return rootlessConfigHomeDir, nil
+}
+
// GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for
// the pause process
func GetRootlessPauseProcessPidPath() (string, error) {
diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go
index 635558bf7..e781e6717 100644
--- a/pkg/util/utils_windows.go
+++ b/pkg/util/utils_windows.go
@@ -6,24 +6,31 @@ import (
"github.com/pkg/errors"
)
+var errNotImplemented = errors.New("not yet implemented")
+
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode.
func IsCgroup2UnifiedMode() (bool, error) {
- return false, errors.New("this function is not implemented for windows")
+ return false, errors.Wrap(errNotImplemented, "IsCgroup2Unified")
}
// GetContainerPidInformationDescriptors returns a string slice of all supported
// format descriptors of GetContainerPidInformation.
func GetContainerPidInformationDescriptors() ([]string, error) {
- return nil, errors.New("this function is not implemented for windows")
+ return nil, errors.Wrap(errNotImplemented, "GetContainerPidInformationDescriptors")
}
// GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for
// the pause process
func GetRootlessPauseProcessPidPath() (string, error) {
- return "", errors.New("this function is not implemented for windows")
+ return "", errors.Wrap(errNotImplemented, "GetRootlessPauseProcessPidPath")
}
// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir() (string, error) {
- return "", errors.New("this function is not implemented for windows")
+ return "", errors.Wrap(errNotImplemented, "GetRootlessRuntimeDir")
+}
+
+// GetRootlessConfigHomeDir returns the config home directory when running as non root
+func GetRootlessConfigHomeDir() (string, error) {
+ return "", errors.Wrap(errNotImplemented, "GetRootlessConfigHomeDir")
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index bb66ff962..c7aa5233f 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -19,6 +19,8 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/adapter/shortcuts"
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/varlinkapi/virtwriter"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
@@ -317,6 +319,13 @@ func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath str
// GetContainerStats ...
func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error {
+ cgroupv2, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if rootless.IsRootless() && !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())
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 338499bd4..fe7f11b4d 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -198,6 +198,8 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
if call.WantsMore() {
call.Continues = true
+ } else {
+ return call.ReplyErrorOccurred("endpoint requires a more connection")
}
var newPathDockerFiles []string
@@ -642,6 +644,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
defer close(c)
go func() {
+ var foundError bool
if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
srcRef, err := alltransports.ParseImageName(name)
if err != nil {
@@ -649,19 +652,23 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
}
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, false, nil)
+ 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()
}
}
- c <- nil
+ if !foundError {
+ c <- nil
+ }
}()
var log []string
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 9b5b3a5b1..2de785b79 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -61,6 +61,7 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error {
Kernel: host["kernel"].(string),
Os: host["os"].(string),
Uptime: host["uptime"].(string),
+ Eventlogger: host["eventlogger"].(string),
}
podmanInfo.Host = infoHost
store := info[1].Data
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 0261acbd9..1caefd299 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -364,8 +364,8 @@ var _ = Describe("Podman checkpoint", func() {
// This test does the same steps which are necessary for migrating
// a container from one host to another
It("podman checkpoint container with export (migration)", func() {
- // CRIU does not work with seccomp correctly on RHEL7
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{"--rm", ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
@@ -375,25 +375,28 @@ var _ = Describe("Podman checkpoint", func() {
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
result.WaitWithDefaultTimeout()
+ // As the container has been started with '--rm' it will be completely
+ // cleaned up after checkpointing.
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
- Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
-
- // Remove all containers to simulate migration
- result = podmanTest.Podman([]string{"rm", "-fa"})
- result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
- Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
- result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
+ // Restore container the first time with different name.
+ // Using '--ignore-static-ip' as for parallel test runs
+ // each containers gets a random IP address via '--ip'.
+ // '--ignore-static-ip' tells the restore to use the next
+ // available IP address.
+ // First restore the container with a new name/ID to make
+ // sure nothing in the restored container depends on the
+ // original container.
+ result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again", "--ignore-static-ip"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
- // Restore container a second time with different name
- result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again"})
+ result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -404,6 +407,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
// Remove exported checkpoint
os.Remove(fileName)
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index b6dd1ecd1..4e9881d59 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -538,7 +538,7 @@ func (p *PodmanTestIntegration) RunHealthCheck(cid string) error {
return nil
}
// Restart container if it's not running
- ps := p.Podman([]string{"ps", "--no-trunc", "--q", "--filter", fmt.Sprintf("id=%s", cid)})
+ ps := p.Podman([]string{"ps", "--no-trunc", "--quiet", "--filter", fmt.Sprintf("id=%s", cid)})
ps.WaitWithDefaultTimeout()
if ps.ExitCode() == 0 {
if !strings.Contains(ps.OutputToString(), cid) {
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index 5e98e73eb..edd9c70c6 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -209,4 +209,40 @@ var _ = Describe("Podman cp", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
+
+ It("podman cp from ctr chown ", func() {
+ setup := podmanTest.RunTopContainer("testctr")
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"exec", "testctr", "adduser", "-S", "testuser"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"exec", "-u", "testuser", "testctr", "touch", "testfile"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"cp", "testctr:testfile", "testfile1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // owner of the file copied to local machine is not testuser
+ cmd := exec.Command("ls", "-l", "testfile1")
+ cmdRet, err := cmd.Output()
+ Expect(err).To(BeNil())
+ Expect(strings.Contains(string(cmdRet), "testuser")).To(BeFalse())
+
+ session = podmanTest.Podman([]string{"cp", "testfile1", "testctr:testfile2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // owner of the file copied to a container is the root user
+ session = podmanTest.Podman([]string{"exec", "-it", "testctr", "ls", "-l", "testfile2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("root"))
+
+ os.Remove("testfile1")
+ })
})
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index e2b4a7cf4..2918cce78 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -218,4 +218,27 @@ var _ = Describe("Podman create", func() {
match, _ := check.GrepString("foobar")
Expect(match).To(BeTrue())
})
+
+ It("podman run entrypoint and cmd test", func() {
+ name := "test101"
+ create := podmanTest.Podman([]string{"create", "--name", name, redis})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ ctrJSON := podmanTest.InspectContainer(name)
+ Expect(len(ctrJSON)).To(Equal(1))
+ Expect(len(ctrJSON[0].Config.Cmd)).To(Equal(1))
+ Expect(ctrJSON[0].Config.Cmd[0]).To(Equal("redis-server"))
+ Expect(ctrJSON[0].Config.Entrypoint).To(Equal("docker-entrypoint.sh"))
+ })
+
+ It("podman create --pull", func() {
+ session := podmanTest.PodmanNoCache([]string{"create", "--pull", "never", "--name=foo", "nginx"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+
+ session = podmanTest.PodmanNoCache([]string{"create", "--pull", "always", "--name=foo", "nginx"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To((Equal(0)))
+ })
})
diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go
index c5eedda3c..0636af74c 100644
--- a/test/e2e/events_test.go
+++ b/test/e2e/events_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "encoding/json"
"fmt"
"os"
"strings"
@@ -116,4 +117,25 @@ var _ = Describe("Podman events", func() {
Expect(result.ExitCode()).To(BeZero())
})
+ It("podman events format", func() {
+ info := GetHostDistributionInfo()
+ if info.Distribution != "fedora" {
+ Skip("need to verify images have correct packages for journald")
+ }
+ _, ec, _ := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+ test := podmanTest.Podman([]string{"events", "--stream=false", "--format", "json"})
+ test.WaitWithDefaultTimeout()
+ fmt.Println(test.OutputToStringArray())
+ jsonArr := test.OutputToStringArray()
+ Expect(len(jsonArr)).To(Not(BeZero()))
+ eventsMap := make(map[string]string)
+ err := json.Unmarshal([]byte(jsonArr[0]), &eventsMap)
+ if err != nil {
+ os.Exit(1)
+ }
+ _, exist := eventsMap["Status"]
+ Expect(exist).To(BeTrue())
+ Expect(test.ExitCode()).To(BeZero())
+ })
})
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index 6cf78a25c..3f9639fda 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -179,6 +179,8 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec cannot be invoked", func() {
+ SkipIfNotRunc()
+
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -189,6 +191,8 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec command not found", func() {
+ SkipIfNotRunc()
+
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go
index 7f33fec87..a6cedfc58 100644
--- a/test/e2e/libpod_suite_remoteclient_test.go
+++ b/test/e2e/libpod_suite_remoteclient_test.go
@@ -28,6 +28,13 @@ func SkipIfRootless() {
}
}
+func SkipIfNotRunc() {
+ runtime := os.Getenv("OCI_RUNTIME")
+ if runtime != "" && filepath.Base(runtime) != "runc" {
+ ginkgo.Skip("Not using runc as runtime")
+ }
+}
+
// Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
podmanSession := p.PodmanBase(args, false, false)
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index 1df59dbe3..22cc14d6b 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -21,6 +21,13 @@ func SkipIfRootless() {
}
}
+func SkipIfNotRunc() {
+ runtime := os.Getenv("OCI_RUNTIME")
+ if runtime != "" && filepath.Base(runtime) != "runc" {
+ ginkgo.Skip("Not using runc as runtime")
+ }
+}
+
// Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
podmanSession := p.PodmanBase(args, false, false)
diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go
index d64340248..4d476e05f 100644
--- a/test/e2e/login_logout_test.go
+++ b/test/e2e/login_logout_test.go
@@ -127,6 +127,10 @@ var _ = Describe("Podman login and logout", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"run", "--authfile", authFile, testImg})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
session = podmanTest.Podman([]string{"logout", "--authfile", authFile, server})
})
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
new file mode 100644
index 000000000..9aed5351a
--- /dev/null
+++ b/test/e2e/network_test.go
@@ -0,0 +1,158 @@
+// +build !remoteclient
+
+package integration
+
+import (
+ "fmt"
+ . "github.com/containers/libpod/test/utils"
+ "github.com/containers/storage/pkg/stringid"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+func writeConf(conf []byte, confPath string) {
+ if err := ioutil.WriteFile(confPath, conf, 777); err != nil {
+ fmt.Println(err)
+ }
+}
+func removeConf(confPath string) {
+ if err := os.Remove(confPath); err != nil {
+ fmt.Println(err)
+ }
+}
+
+var _ = Describe("Podman network", 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)
+
+ })
+
+ var (
+ secondConf = `{
+ "cniVersion": "0.3.0",
+ "name": "podman-integrationtest",
+ "plugins": [
+ {
+ "type": "bridge",
+ "bridge": "cni1",
+ "isGateway": true,
+ "ipMasq": true,
+ "ipam": {
+ "type": "host-local",
+ "subnet": "10.99.0.0/16",
+ "routes": [
+ { "dst": "0.0.0.0/0" }
+ ]
+ }
+ },
+ {
+ "type": "portmap",
+ "capabilities": {
+ "portMappings": true
+ }
+ }
+ ]
+}`
+ cniPath = "/etc/cni/net.d"
+ )
+
+ It("podman network list", func() {
+ SkipIfRootless()
+ // Setup, use uuid to prevent conflict with other tests
+ uuid := stringid.GenerateNonCryptoID()
+ secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid))
+ writeConf([]byte(secondConf), secondPath)
+ defer removeConf(secondPath)
+
+ session := podmanTest.Podman([]string{"network", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue())
+ })
+
+ It("podman network list -q", func() {
+ SkipIfRootless()
+ // Setup, use uuid to prevent conflict with other tests
+ uuid := stringid.GenerateNonCryptoID()
+ secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid))
+ writeConf([]byte(secondConf), secondPath)
+ defer removeConf(secondPath)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue())
+ })
+
+ It("podman network rm no args", func() {
+ SkipIfRootless()
+ session := podmanTest.Podman([]string{"network", "rm"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).ToNot(BeZero())
+ })
+
+ It("podman network rm", func() {
+ SkipIfRootless()
+ // Setup, use uuid to prevent conflict with other tests
+ uuid := stringid.GenerateNonCryptoID()
+ secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid))
+ writeConf([]byte(secondConf), secondPath)
+ defer removeConf(secondPath)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue())
+
+ rm := podmanTest.Podman([]string{"network", "rm", "podman-integrationtest"})
+ rm.WaitWithDefaultTimeout()
+ Expect(rm.ExitCode()).To(BeZero())
+
+ results := podmanTest.Podman([]string{"network", "ls", "--quiet"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ Expect(results.LineInOutputContains("podman-integrationtest")).To(BeFalse())
+ })
+
+ It("podman network inspect no args", func() {
+ SkipIfRootless()
+ session := podmanTest.Podman([]string{"network", "inspect"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).ToNot(BeZero())
+ })
+
+ It("podman network inspect", func() {
+ SkipIfRootless()
+ // Setup, use uuid to prevent conflict with other tests
+ uuid := stringid.GenerateNonCryptoID()
+ secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid))
+ writeConf([]byte(secondConf), secondPath)
+ defer removeConf(secondPath)
+
+ session := podmanTest.Podman([]string{"network", "inspect", "podman-integrationtest", "podman"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.IsJSONOutputValid()).To(BeTrue())
+ })
+
+})
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index 455f60937..c61131078 100644
--- a/test/e2e/pause_test.go
+++ b/test/e2e/pause_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
+ "github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -25,6 +26,17 @@ var _ = Describe("Podman pause", func() {
if err != nil {
os.Exit(1)
}
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ _, err := os.Stat("/sys/fs/cgroup/cgroup.freeze")
+ if err != nil {
+ Skip("freezer controller not available on the current kernel")
+ }
+ }
+
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
podmanTest.SeedImages()
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 331412a39..af3cab379 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -21,6 +21,7 @@ metadata:
app: {{ .Name }}
name: {{ .Name }}
spec:
+ hostname: {{ .Hostname }}
containers:
{{ with .Containers }}
{{ range . }}
@@ -66,6 +67,7 @@ status: {}
type Pod struct {
Name string
+ Hostname string
Containers []Container
}
@@ -78,13 +80,13 @@ type Container struct {
CapDrop []string
}
-func generateKubeYaml(ctrs []Container, fileName string) error {
+func generateKubeYaml(name string, hostname string, ctrs []Container, fileName string) error {
f, err := os.Create(fileName)
if err != nil {
return err
}
defer f.Close()
- testPod := Pod{"test", ctrs}
+ testPod := Pod{name, hostname, ctrs}
t, err := template.New("pod").Parse(yamlTemplate)
if err != nil {
@@ -127,7 +129,7 @@ var _ = Describe("Podman generate kube", func() {
testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil}
tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
- err := generateKubeYaml([]Container{testContainer}, tempFile)
+ err := generateKubeYaml("test", "", []Container{testContainer}, tempFile)
Expect(err).To(BeNil())
kube := podmanTest.Podman([]string{"play", "kube", tempFile})
@@ -140,6 +142,70 @@ var _ = Describe("Podman generate kube", func() {
Expect(inspect.OutputToString()).To(ContainSubstring(ctrCmd[0]))
})
+ It("podman play kube test correct output", func() {
+ ctrName := "testCtr"
+ ctrCmd := []string{"echo", "hello"}
+ testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil}
+ tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
+
+ err := generateKubeYaml("test", "", []Container{testContainer}, tempFile)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", tempFile})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ logs := podmanTest.Podman([]string{"logs", ctrName})
+ logs.WaitWithDefaultTimeout()
+ Expect(logs.ExitCode()).To(Equal(0))
+ Expect(logs.OutputToString()).To(ContainSubstring("hello"))
+
+ inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "'{{ .Config.Cmd }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring("hello"))
+ })
+
+ It("podman play kube test hostname", func() {
+ podName := "test"
+ ctrName := "testCtr"
+ ctrCmd := []string{"top"}
+ testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil}
+ tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
+
+ err := generateKubeYaml(podName, "", []Container{testContainer}, tempFile)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", tempFile})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "{{ .Config.Hostname }}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(Equal(podName))
+ })
+
+ It("podman play kube test with customized hostname", func() {
+ hostname := "myhostname"
+ ctrName := "testCtr"
+ ctrCmd := []string{"top"}
+ testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil}
+ tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
+
+ err := generateKubeYaml("test", hostname, []Container{testContainer}, tempFile)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", tempFile})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "{{ .Config.Hostname }}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(Equal(hostname))
+ })
+
It("podman play kube cap add", func() {
ctrName := "testCtr"
ctrCmd := []string{"cat", "/proc/self/status"}
@@ -147,7 +213,7 @@ var _ = Describe("Podman generate kube", func() {
testContainer := Container{ctrCmd, ALPINE, ctrName, true, []string{capAdd}, nil}
tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
- err := generateKubeYaml([]Container{testContainer}, tempFile)
+ err := generateKubeYaml("test", "", []Container{testContainer}, tempFile)
Expect(err).To(BeNil())
kube := podmanTest.Podman([]string{"play", "kube", tempFile})
@@ -167,7 +233,7 @@ var _ = Describe("Podman generate kube", func() {
testContainer := Container{ctrCmd, ALPINE, ctrName, true, []string{capDrop}, nil}
tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml")
- err := generateKubeYaml([]Container{testContainer}, tempFile)
+ err := generateKubeYaml("test", "", []Container{testContainer}, tempFile)
Expect(err).To(BeNil())
kube := podmanTest.Podman([]string{"play", "kube", tempFile})
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index c8763de9f..3897aa851 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -383,4 +383,24 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
+
+ It("podman run hostname is shared", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ // verify we can add a host to the infra's /etc/hosts
+ session = podmanTest.Podman([]string{"run", "--pod", podID, ALPINE, "hostname"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ hostname := session.OutputToString()
+
+ infraName := podID[:12] + "-infra"
+ // verify we can see the other hosts of infra's /etc/hosts
+ session = podmanTest.Podman([]string{"inspect", infraName})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring(hostname))
+ })
})
diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go
index 26c5fd7d0..b15d8e133 100644
--- a/test/e2e/port_test.go
+++ b/test/e2e/port_test.go
@@ -105,4 +105,42 @@ var _ = Describe("Podman port", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
+
+ It("podman port nginx by name", func() {
+ session, cid := podmanTest.RunNginxWithHealthCheck("portcheck")
+ Expect(session.ExitCode()).To(Equal(0))
+
+ if err := podmanTest.RunHealthCheck(cid); err != nil {
+ Fail(err.Error())
+ }
+
+ result := podmanTest.Podman([]string{"port", "portcheck"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ result.LineInOuputStartsWith("80/tcp -> 0.0.0.0:")
+ })
+
+ It("podman port multiple ports", func() {
+ // Acquire and release locks
+ lock1 := GetPortLock("5000")
+ defer lock1.Unlock()
+ lock2 := GetPortLock("5001")
+ defer lock2.Unlock()
+
+ setup := podmanTest.Podman([]string{"run", "-dt", "-p", "5000:5000", "-p", "5001:5001", ALPINE, "top"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(BeZero())
+
+ // Check that the first port was honored
+ result1 := podmanTest.Podman([]string{"port", "-l", "5000"})
+ result1.WaitWithDefaultTimeout()
+ Expect(result1.ExitCode()).To(BeZero())
+ Expect(result1.LineInOuputStartsWith("0.0.0.0:5000"))
+
+ // Check that the second port was honored
+ result2 := podmanTest.Podman([]string{"port", "-l", "5001"})
+ result2.WaitWithDefaultTimeout()
+ Expect(result2.ExitCode()).To(BeZero())
+ Expect(result2.LineInOuputStartsWith("0.0.0.0:5001"))
+ })
})
diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go
index 87f89b1dd..4be9da3d2 100644
--- a/test/e2e/run_cpu_test.go
+++ b/test/e2e/run_cpu_test.go
@@ -3,8 +3,10 @@
package integration
import (
+ "io/ioutil"
"os"
+ "github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -22,6 +24,16 @@ var _ = Describe("Podman run cpu", func() {
if err != nil {
os.Exit(1)
}
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ if err := ioutil.WriteFile("/sys/fs/cgroup/cgroup.subtree_control", []byte("+cpuset"), 0644); err != nil {
+ Skip("cpuset controller not available on the current kernel")
+ }
+ }
+
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
podmanTest.SeedImages()
@@ -36,44 +48,96 @@ var _ = Describe("Podman run cpu", func() {
It("podman run cpu-period", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var result *PodmanSessionIntegration
+ if cgroupsv2 {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"})
+ } else {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"})
+ }
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(Equal("5000"))
+ Expect(result.LineInOutputContains("5000"))
})
It("podman run cpu-quota", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var result *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"})
+ } else {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
+ }
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(Equal("5000"))
+ Expect(result.LineInOutputContains("5000"))
})
It("podman run cpus", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"})
- result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(Equal("100000"))
- result = podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
- result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(Equal("50000"))
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(Equal("5000 100000"))
+ } else {
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(Equal("100000"))
+
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(Equal("50000"))
+ }
})
It("podman run cpu-shares", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=2", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.shares"})
- result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(Equal("2"))
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ // [2-262144] is mapped to [1-10000]
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=262144", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.weight"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(Equal("10000"))
+ } else {
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=2", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.shares"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(Equal("2"))
+ }
})
It("podman run cpuset-cpus", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.cpus"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var result *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpuset.cpus.effective"})
+ } else {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.cpus"})
+ }
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(result.OutputToString()).To(Equal("0"))
@@ -81,7 +145,17 @@ var _ = Describe("Podman run cpu", func() {
It("podman run cpuset-mems", func() {
SkipIfRootless()
- result := podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.mems"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var result *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpuset.mems.effective"})
+ } else {
+ result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.mems"})
+ }
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(result.OutputToString()).To(Equal("0"))
diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go
index 081fab3fd..dc0f4a8fb 100644
--- a/test/e2e/run_dns_test.go
+++ b/test/e2e/run_dns_test.go
@@ -41,6 +41,13 @@ var _ = Describe("Podman run dns", func() {
session.LineInOuputStartsWith("search foobar.com")
})
+ It("podman run remove all search domain", func() {
+ session := podmanTest.Podman([]string{"run", "--dns-search=.", ALPINE, "cat", "/etc/resolv.conf"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOuputStartsWith("search")).To(BeFalse())
+ })
+
It("podman run add bad dns server", func() {
session := podmanTest.Podman([]string{"run", "--dns=foobar", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go
index 861d6b3b7..b05849ddb 100644
--- a/test/e2e/run_exit_test.go
+++ b/test/e2e/run_exit_test.go
@@ -41,12 +41,16 @@ var _ = Describe("Podman run exit", func() {
})
It("podman run exit 126", func() {
+ SkipIfNotRunc()
+
result := podmanTest.Podman([]string{"run", ALPINE, "/etc"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(126))
})
It("podman run exit 127", func() {
+ SkipIfNotRunc()
+
result := podmanTest.Podman([]string{"run", ALPINE, "foobar"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(127))
diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go
index 8fe90c8d8..a45735a8a 100644
--- a/test/e2e/run_memory_test.go
+++ b/test/e2e/run_memory_test.go
@@ -5,6 +5,7 @@ package integration
import (
"os"
+ "github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -36,7 +37,16 @@ var _ = Describe("Podman run memory", func() {
})
It("podman run memory test", func() {
- session := podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"})
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.max"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"})
+ }
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("41943040"))
@@ -46,13 +56,31 @@ var _ = Describe("Podman run memory", func() {
if podmanTest.Host.Distribution == "ubuntu" {
Skip("Unable to perform test on Ubuntu distributions due to memory management")
}
- session := podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.high"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"})
+ }
+
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("41943040"))
})
It("podman run memory-swappiness test", func() {
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ Skip("Memory swappiness not supported on cgroups v2")
+ }
+
session := podmanTest.Podman([]string{"run", "--memory-swappiness=15", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.swappiness"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -60,6 +88,12 @@ var _ = Describe("Podman run memory", func() {
})
It("podman run kernel-memory test", func() {
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if cgroupsv2 {
+ Skip("Kernel memory not supported on cgroups v2")
+ }
session := podmanTest.Podman([]string{"run", "--kernel-memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go
index a2228411e..dfe71531a 100644
--- a/test/e2e/run_selinux_test.go
+++ b/test/e2e/run_selinux_test.go
@@ -153,4 +153,16 @@ var _ = Describe("Podman run", func() {
Expect(match).Should(BeTrue())
})
+ It("podman run selinux file type setup test", func() {
+ session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "label=type:spc_t", "--security-opt", "label=filetype:container_var_lib_t", fedoraMinimal, "ls", "-Z", "/dev"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ := session.GrepString("container_var_lib_t")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "-it", "--security-opt", "label=type:spc_t", "--security-opt", "label=filetype:foobar", fedoraMinimal, "ls", "-Z", "/dev"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(127))
+ })
+
})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index f66d1d2fa..ce2044a72 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -13,6 +13,7 @@ import (
"syscall"
"time"
+ "github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
"github.com/containers/storage/pkg/stringid"
"github.com/mrunalp/fileutils"
@@ -263,9 +264,15 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("1024"))
- session = podmanTest.Podman([]string{"run", "--rm", "--oom-kill-disable=true", fedoraMinimal, "echo", "memory-hog"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if !cgroupsv2 {
+ // --oom-kill-disable not supported on cgroups v2.
+ session = podmanTest.Podman([]string{"run", "--rm", "--oom-kill-disable=true", fedoraMinimal, "echo", "memory-hog"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ }
session = podmanTest.Podman([]string{"run", "--rm", "--oom-score-adj=100", fedoraMinimal, "cat", "/proc/self/oom_score_adj"})
session.WaitWithDefaultTimeout()
@@ -310,18 +317,43 @@ var _ = Describe("Podman run", func() {
It("podman run blkio-weight test", func() {
SkipIfRootless()
- if _, err := os.Stat("/sys/fs/cgroup/blkio/blkio.weight"); os.IsNotExist(err) {
- Skip("Kernel does not support blkio.weight")
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ if !cgroupsv2 {
+ if _, err := os.Stat("/sys/fs/cgroup/blkio/blkio.weight"); os.IsNotExist(err) {
+ Skip("Kernel does not support blkio.weight")
+ }
+ }
+
+ if cgroupsv2 {
+ // convert linearly from [10-1000] to [1-10000]
+ session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.bfq.weight"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("51"))
+ } else {
+ session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.weight"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("15"))
}
- session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.weight"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(ContainSubstring("15"))
})
It("podman run device-read-bps test", func() {
SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"})
+ }
+
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("1048576"))
@@ -329,7 +361,17 @@ var _ = Describe("Podman run", func() {
It("podman run device-write-bps test", func() {
SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device"})
+ }
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("1048576"))
@@ -337,7 +379,18 @@ var _ = Describe("Podman run", func() {
It("podman run device-read-iops test", func() {
SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device"})
+ }
+
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("100"))
@@ -345,7 +398,18 @@ var _ = Describe("Podman run", func() {
It("podman run device-write-iops test", func() {
SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device"})
+
+ cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
+ Expect(err).To(BeNil())
+
+ var session *PodmanSessionIntegration
+
+ if cgroupsv2 {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"})
+ } else {
+ session = podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device"})
+ }
+
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("100"))
@@ -353,6 +417,8 @@ var _ = Describe("Podman run", func() {
It("podman run notify_socket", func() {
SkipIfRemote()
+ SkipIfNotRunc()
+
host := GetHostDistributionInfo()
if host.Distribution != "rhel" && host.Distribution != "centos" && host.Distribution != "fedora" {
Skip("this test requires a working runc")
@@ -563,6 +629,7 @@ var _ = Describe("Podman run", func() {
})
It("podman run exit code on failure to exec", func() {
+ SkipIfNotRunc()
session := podmanTest.Podman([]string{"run", ALPINE, "/etc"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(126))
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 9e160e73c..1e0b84310 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -136,4 +136,22 @@ var _ = Describe("Podman run with volumes", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
+
+ It("podman run with mount flag and boolean options", func() {
+ mountPath := filepath.Join(podmanTest.TempDir, "secrets")
+ os.Mkdir(mountPath, 0755)
+ session := podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,ro=false", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("/run/test rw"))
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,ro=true", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("/run/test ro"))
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,ro=true,rw=false", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
})
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index fc1203ed1..2dbb9545b 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -101,6 +101,8 @@ var _ = Describe("Podman start", func() {
})
It("podman failed to start with --rm should delete the container", func() {
+ SkipIfNotRunc()
+
session := podmanTest.Podman([]string{"create", "-it", "--rm", ALPINE, "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -114,6 +116,8 @@ var _ = Describe("Podman start", func() {
})
It("podman failed to start without --rm should NOT delete the container", func() {
+ SkipIfNotRunc()
+
session := podmanTest.Podman([]string{"create", "-it", ALPINE, "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats
index 85b9bc1ca..5fc07acfb 100644
--- a/test/system/001-basic.bats
+++ b/test/system/001-basic.bats
@@ -13,6 +13,14 @@ function setup() {
@test "podman version emits reasonable output" {
run_podman version
+ # First line of podman-remote is "Client:<blank>".
+ # Just delete it (i.e. remove the first entry from the 'lines' array)
+ if is_remote; then
+ if expr "${lines[0]}" : "Client:" >/dev/null; then
+ lines=("${lines[@]:1}")
+ fi
+ fi
+
is "${lines[0]}" "Version:[ ]\+[1-9][0-9.]\+" "Version line 1"
is "$output" ".*Go Version: \+" "'Go Version' in output"
is "$output" ".*RemoteAPI Version: \+" "API version in output"
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index cefff0e2c..9e609b434 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -43,4 +43,17 @@ echo $rand | 0 | $rand
is "$output" "" "unwanted /sys/kernel in 'mount' output (with --net=host)"
}
+# 'run --rm' goes through different code paths and may lose exit status.
+# See https://github.com/containers/libpod/issues/3795
+@test "podman run --rm" {
+ skip_if_remote "podman-remote does not handle exit codes"
+
+ run_podman 0 run --rm $IMAGE /bin/true
+ run_podman 1 run --rm $IMAGE /bin/false
+
+ # Believe it or not, 'sh -c' resulted in different behavior
+ run_podman 0 run --rm $IMAGE sh -c /bin/true
+ run_podman 1 run --rm $IMAGE sh -c /bin/false
+}
+
# vim: filetype=sh
diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats
new file mode 100644
index 000000000..c13c8c52e
--- /dev/null
+++ b/test/system/055-rm.bats
@@ -0,0 +1,42 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# tests for podman rm
+#
+
+load helpers
+
+@test "podman rm" {
+ rand=$(random_string 30)
+ run_podman run --name $rand $IMAGE /bin/true
+
+ # Don't care about output, just check exit status (it should exist)
+ run_podman 0 inspect $rand
+
+ # container should be in output of 'ps -a'
+ run_podman ps -a
+ is "$output" ".* $IMAGE .*/true .* $rand" "Container present in 'ps -a'"
+
+ # Remove container; now 'inspect' should fail
+ run_podman rm $rand
+ run_podman 125 inspect $rand
+}
+
+# I'm sorry! This test takes 13 seconds. There's not much I can do about it,
+# please know that I think it's justified: podman 1.5.0 had a strange bug
+# in with exit status was not preserved on some code paths with 'rm -f'
+# or 'podman run --rm' (see also 030-run.bats). The test below is a bit
+# kludgy: what we care about is the exit status of the killed container,
+# not 'podman rm', but BATS has no provision (that I know of) for forking,
+# so what we do is start the 'rm' beforehand and monitor the exit status
+# of the 'sleep' container.
+#
+# See https://github.com/containers/libpod/issues/3795
+@test "podman rm -f" {
+ skip_if_remote "podman-remote does not handle exit codes"
+
+ rand=$(random_string 30)
+ ( sleep 3; run_podman rm -f $rand ) &
+ run_podman 137 run --name $rand $IMAGE sleep 30
+}
+
+# vim: filetype=sh
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index c1e7c7ec4..5ef84e9b8 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -6,10 +6,8 @@
load helpers
@test "podman build - basic test" {
- if [[ "$PODMAN" =~ -remote ]]; then
- if [ "$(id -u)" -ne 0 ]; then
- skip "unreliable with podman-remote and rootless; #2972"
- fi
+ if is_remote && is_rootless; then
+ skip "unreliable with podman-remote and rootless; #2972"
fi
rand_filename=$(random_string 20)
diff --git a/test/system/200-pod-top.bats b/test/system/200-pod-top.bats
index 08f495fb1..bba1e8d14 100644
--- a/test/system/200-pod-top.bats
+++ b/test/system/200-pod-top.bats
@@ -3,7 +3,7 @@
load helpers
@test "podman pod top - containers in different PID namespaces" {
- skip "this test is not reliable. Reenable once pod-top is fixed."
+ skip_if_remote "podman-pod does not work with podman-remote"
# With infra=false, we don't get a /pause container (we also
# don't pull k8s.gcr.io/pause )
@@ -28,9 +28,6 @@ load helpers
# By default (podman pod create w/ default --infra) there should be
# a /pause container.
- # FIXME: sometimes there is, sometimes there isn't. If anyone ever
- # actually figures this out, please either reenable this line or
- # remove it entirely.
if [ -z "$no_infra" ]; then
is "$output" ".*0 \+1 \+0 \+[0-9. ?s]\+/pause" "there is a /pause container"
fi
diff --git a/test/system/README.md b/test/system/README.md
index d98b1c0fe..fe6d1ed52 100644
--- a/test/system/README.md
+++ b/test/system/README.md
@@ -28,6 +28,8 @@ on failure.
* `skip_if_rootless` - if rootless, skip this test with a helpful message.
+* `skip_if_remote` - like the above, but skip if testing `podman-remote`
+
* `random_string` - returns a pseudorandom alphanumeric string
Test files are of the form `NNN-name.bats` where NNN is a three-digit
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index fe0a25b37..3d607f4bd 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -216,26 +216,31 @@ function wait_for_ready {
###############################################################################
# BEGIN miscellaneous tools
+# Shortcuts for common needs:
+function is_rootless() {
+ [ "$(id -u)" -ne 0 ]
+}
+
+function is_remote() {
+ [[ "$PODMAN" =~ -remote ]]
+}
+
######################
# skip_if_rootless # ...with an optional message
######################
function skip_if_rootless() {
- if [ "$(id -u)" -eq 0 ]; then
- return
+ if is_rootless; then
+ skip "${1:-not applicable under rootless podman}"
fi
-
- skip "${1:-not applicable under rootless podman}"
}
####################
# skip_if_remote # ...with an optional message
####################
function skip_if_remote() {
- if [[ ! "$PODMAN" =~ -remote ]]; then
- return
+ if is_remote; then
+ skip "${1:-test does not work with podman-remote}"
fi
-
- skip "${1:-test does not work with podman-remote}"
}
#########################
diff --git a/troubleshooting.md b/troubleshooting.md
index 64aec475e..b88940dc8 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -298,7 +298,33 @@ tells SELinux to apply the labels to the actual content.
Now all new content created in these directories will automatically be created
with the correct label.
-### 12) Running Podman inside a container causes container crashes and inconsistent states
+### 12) Anonymous image pull fails with 'invalid username/password'
+
+Pulling an anonymous image that doesn't require authentication can result in an
+`invalid username/password` error.
+
+#### Symptom
+
+If you pull an anonymous image, one that should not require credentials, you can receive
+and `invalid username/password` error if you have credentials established in the
+authentication file for the target container registry that are no longer valid.
+
+```
+podman run -it --rm docker://docker.io/library/alpine:latest ls
+Trying to pull docker://docker.io/library/alpine:latest...ERRO[0000] Error pulling image ref //alpine:latest: Error determining manifest MIME type for docker://alpine:latest: unable to retrieve auth token: invalid username/password
+Failed
+Error: unable to pull docker://docker.io/library/alpine:latest: unable to pull image: Error determining manifest MIME type for docker://alpine:latest: unable to retrieve auth token: invalid username/password
+```
+
+This can happen if the authentication file is modified 'by hand' or if the credentials
+are established locally and then the password is updated later in the container registry.
+
+#### Solution
+
+Depending upon which container tool was used to establish the credentials, use `podman logout`
+or `docker logout` to remove the credentials from the authentication file.
+
+### 13) Running Podman inside a container causes container crashes and inconsistent states
Running Podman in a container and forwarding some, but not all, of the required host directories can cause inconsistent container behavior.
@@ -315,3 +341,53 @@ Not doing this will cause Podman in the container to detect that temporary files
This can cause Podman to reset container states and lose track of running containers.
For running containers on the host from inside a container, we also recommend the [Podman remote client](remote_client.md), which only requires a single socket to be mounted into the container.
+
+### 14) Rootless 'podman build' fails EPERM on NFS:
+
+NFS enforces file creation on different UIDs on the server side and does not understand user namespace, which rootless Podman requires.
+When a container root process like YUM attempts to create a file owned by a different UID, NFS Server denies the creation.
+NFS is also a problem for the file locks when the storage is on it. Other distributed file systems (for example: Lustre, Spectrum Scale, the General Parallel File System (GPFS)) are also not supported when running in rootless mode as these file systems do not understand user namespace.
+
+#### Symptom
+```console
+$ podman build .
+ERRO[0014] Error while applying layer: ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+error creating build container: Error committing the finished image: error adding layer with blob "sha256:a02a4930cb5d36f3290eb84f4bfa30668ef2e9fe3a1fb73ec015fc58b9958b17": ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+```
+
+#### Solution
+Choose one of the following:
+ * Setup containers/storage in a different directory, not on an NFS share.
+ * Create a directory on a local file system.
+ * Edit `~/.config/containers/libpod.conf` and point the `volume_path` option to that local directory.
+ * Otherwise just run podman as root, via `sudo podman`
+
+### 15) Rootless 'podman build' fails when using OverlayFS:
+
+The Overlay file system (OverlayFS) requires the ability to call the `mknod` command when creating whiteout files
+when extracting an image. However, a rootless user does not have the privileges to use `mknod` in this capacity.
+
+#### Symptom
+```console
+podman build --storage-driver overlay .
+STEP 1: FROM docker.io/ubuntu:xenial
+Getting image source signatures
+Copying blob edf72af6d627 done
+Copying blob 3e4f86211d23 done
+Copying blob 8d3eac894db4 done
+Copying blob f7277927d38a done
+Copying config 5e13f8dd4c done
+Writing manifest to image destination
+Storing signatures
+Error: error creating build container: Error committing the finished image: error adding layer with blob "sha256:8d3eac894db4dc4154377ad28643dfe6625ff0e54bcfa63e0d04921f1a8ef7f8": Error processing tar file(exit status 1): operation not permitted
+$ podman build .
+ERRO[0014] Error while applying layer: ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+error creating build container: Error committing the finished image: error adding layer with blob "sha256:a02a4930cb5d36f3290eb84f4bfa30668ef2e9fe3a1fb73ec015fc58b9958b17": ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+```
+
+#### Solution
+Choose one of the following:
+ * Complete the build operation as a privileged user.
+ * Install and configure fuse-overlayfs.
+ * Install the fuse-overlayfs package for your Linux Distribution.
+ * Add `mount_program = "/usr/bin/fuse-overlayfs` under `[storage.options]` in your `~/.config/containers/storage.conf` file.
diff --git a/vendor/github.com/containers/buildah/.golangci.yml b/vendor/github.com/containers/buildah/.golangci.yml
index 9a34d03e6..52e9990ed 100644
--- a/vendor/github.com/containers/buildah/.golangci.yml
+++ b/vendor/github.com/containers/buildah/.golangci.yml
@@ -17,6 +17,7 @@ linters:
- errcheck
- gofmt
- goimports
+ - golint
- gosimple
- govet
- ineffassign
@@ -35,7 +36,6 @@ linters:
# - goconst
# - gocritic
# - gocyclo
- # - golint
# - gosec
# - interfacer
# - lll
diff --git a/vendor/github.com/containers/buildah/CHANGELOG.md b/vendor/github.com/containers/buildah/CHANGELOG.md
index 1c59a67ad..ddf6fb1d4 100644
--- a/vendor/github.com/containers/buildah/CHANGELOG.md
+++ b/vendor/github.com/containers/buildah/CHANGELOG.md
@@ -2,6 +2,111 @@
# Changelog
+## v1.10.0 (2019-08-02)
+ vendor github.com/containers/image@v3.0.0
+ Remove GO111MODULE in favor of `-mod=vendor`
+ Vendor in containers/storage v1.12.16
+ Add '-' minus syntax for removal of config values
+ tests: enable overlay tests for rootless
+ rootless, overlay: use fuse-overlayfs
+ vendor github.com/containers/image@v2.0.1
+ Added '-' syntax to remove volume config option
+ delete `successfully pushed` message
+ Add golint linter and apply fixes
+ vendor github.com/containers/storage@v1.12.15
+ Change wait to sleep in buildahimage readme
+ Handle ReadOnly images when deleting images
+ Add support for listing read/only images
+
+## v1.9.2 (2019-07-19)
+ from/import: record the base image's digest, if it has one
+ Fix CNI version retrieval to not require network connection
+ Add misspell linter and apply fixes
+ Add goimports linter and apply fixes
+ Add stylecheck linter and apply fixes
+ Add unconvert linter and apply fixes
+ image: make sure we don't try to use zstd compression
+ run.bats: skip the "z" flag when testing --mount
+ Update to runc v1.0.0-rc8
+ Update to match updated runtime-tools API
+ bump github.com/opencontainers/runtime-tools to v0.9.0
+ Build e2e tests using the proper build tags
+ Add unparam linter and apply fixes
+ Run: correct a typo in the --cap-add help text
+ unshare: add a --mount flag
+ fix push check image name is not empty
+ Bump to v1.9.2-dev
+
+## v1.9.1 (2019-07-12)
+ add: fix slow copy with no excludes
+ Add errcheck linter and fix missing error check
+ Improve tests/tools/Makefile parallelism and abstraction
+ Fix response body not closed resource leak
+ Switch to golangci-lint
+ Add gomod instructions and mailing list links
+ On Masked path, check if /dev/null already mounted before mounting
+ Update to containers/storage v1.12.13
+ Refactor code in package imagebuildah
+ Add rootless podman with NFS issue in documentation
+ Add --mount for buildah run
+ import method ValidateVolumeOpts from libpod
+ Fix typo
+ Makefile: set GO111MODULE=off
+ rootless: add the built-in slirp DNS server
+ Update docker/libnetwork to get rid of outdated sctp package
+ Update buildah-login.md
+ migrate to go modules
+ install.md: mention go modules
+ tests/tools: go module for test binaries
+ fix --volume splits comma delimited option
+ Add bud test for RUN with a priv'd command
+ vendor logrus v1.4.2
+ pkg/cli: panic when flags can't be hidden
+ pkg/unshare: check all errors
+ pull: check error during report write
+ run_linux.go: ignore unchecked errors
+ conformance test: catch copy error
+ chroot/run_test.go: export funcs to actually be executed
+ tests/imgtype: ignore error when shutting down the store
+ testreport: check json error
+ bind/util.go: remove unused func
+ rm chroot/util.go
+ imagebuildah: remove unused `dedupeStringSlice`
+ StageExecutor: EnsureContainerPath: catch error from SecureJoin()
+ imagebuildah/build.go: return <expr> instead of branching
+ rmi: avoid redundant branching
+ conformance tests: nilness: allocate map
+ imagebuildah/build.go: avoid redundant `filepath.Join()`
+ imagebuildah/build.go: avoid redundant `os.Stat()`
+ imagebuildah: omit comparison to bool
+ fix "ineffectual assignment" lint errors
+ docker: ignore "repeats json tag" lint error
+ pkg/unshare: use `...` instead of iterating a slice
+ conformance: bud test: use raw strings for regexes
+ conformance suite: remove unused func/var
+ buildah test suite: remove unused vars/funcs
+ testreport: fix golangci-lint errors
+ util: remove redundant `return` statement
+ chroot: only log clean-up errors
+ images_test: ignore golangci-lint error
+ blobcache: log error when draining the pipe
+ imagebuildah: check errors in deferred calls
+ chroot: fix error handling in deferred funcs
+ cmd: check all errors
+ chroot/run_test.go: check errors
+ chroot/run.go: check errors in deferred calls
+ imagebuildah.Executor: remove unused onbuild field
+ docker/types.go: remove unused struct fields
+ util: use strings.ContainsRune instead of index check
+ Cirrus: Initial implementation
+ Bump to v1.9.1-dev
+
+## v1.9.0 (2019-06-15)
+ buildah-run: fix-out-of-range panic (2)
+ Bump back to v1.9.0-dev
+
+
+
## v1.8.4 (2019-06-13)
Update containers/image to v2.0.0
run: fix hang with run and --isolation=chroot
@@ -32,49 +137,49 @@
Cleanup Overlay Mounts content
## v1.8.3 (2019-06-04)
- * Add support for file secret mounts
- * Add ability to skip secrets in mounts file
- * allow 32bit builds
- * fix tutorial instructions
- * imagebuilder: pass the right contextDir to Add()
- * add: use fileutils.PatternMatcher for .dockerignore
- * bud.bats: add another .dockerignore test
- * unshare: fallback to single usermapping
- * addHelperSymlink: clear the destination on os.IsExist errors
- * bud.bats: test replacing symbolic links
- * imagebuildah: fix handling of destinations that end with '/'
- * bud.bats: test COPY with a final "/" in the destination
- * linux: add check for sysctl before using it
- * unshare: set _CONTAINERS_ROOTLESS_GID
- * Rework buildahimamges
- * build context: support https git repos
- * Add a test for ENV special chars behaviour
- * Check in new Dockerfiles
- * Apply custom SHELL during build time
- * config: expand variables only at the command line
- * SetEnv: we only need to expand v once
- * Add default /root if empty on chroot iso
- * Add support for Overlay volumes into the container.
- * Export buildah validate volume functions so it can share code with libpod
- * Bump baseline test to F30
- * Fix rootless handling of /dev/shm size
- * Avoid fmt.Printf() in the library
- * imagebuildah: tighten cache checking back up
- * Handle WORKDIR with dangling target
- * Default Authfile to proper path
- * Make buildah run --isolation follow BUILDAH_ISOLATION environment
- * Vendor in latest containers/storage and containers/image
- * getParent/getChildren: handle layerless images
- * imagebuildah: recognize cache images for layerless images
- * bud.bats: test scratch images with --layers caching
- * Get CHANGELOG.md updates
- * Add some symlinks to test our .dockerignore logic
- * imagebuildah: addHelper: handle symbolic links
- * commit/push: use an everything-allowed policy
- * Correct manpage formatting in files section
- * Remove must be root statement from buildah doc
- * Change image names to stable, testing and upstream
- * Bump back to v1.9.0-dev
+ Add support for file secret mounts
+ Add ability to skip secrets in mounts file
+ allow 32bit builds
+ fix tutorial instructions
+ imagebuilder: pass the right contextDir to Add()
+ add: use fileutils.PatternMatcher for .dockerignore
+ bud.bats: add another .dockerignore test
+ unshare: fallback to single usermapping
+ addHelperSymlink: clear the destination on os.IsExist errors
+ bud.bats: test replacing symbolic links
+ imagebuildah: fix handling of destinations that end with '/'
+ bud.bats: test COPY with a final "/" in the destination
+ linux: add check for sysctl before using it
+ unshare: set _CONTAINERS_ROOTLESS_GID
+ Rework buildahimamges
+ build context: support https git repos
+ Add a test for ENV special chars behaviour
+ Check in new Dockerfiles
+ Apply custom SHELL during build time
+ config: expand variables only at the command line
+ SetEnv: we only need to expand v once
+ Add default /root if empty on chroot iso
+ Add support for Overlay volumes into the container.
+ Export buildah validate volume functions so it can share code with libpod
+ Bump baseline test to F30
+ Fix rootless handling of /dev/shm size
+ Avoid fmt.Printf() in the library
+ imagebuildah: tighten cache checking back up
+ Handle WORKDIR with dangling target
+ Default Authfile to proper path
+ Make buildah run --isolation follow BUILDAH_ISOLATION environment
+ Vendor in latest containers/storage and containers/image
+ getParent/getChildren: handle layerless images
+ imagebuildah: recognize cache images for layerless images
+ bud.bats: test scratch images with --layers caching
+ Get CHANGELOG.md updates
+ Add some symlinks to test our .dockerignore logic
+ imagebuildah: addHelper: handle symbolic links
+ commit/push: use an everything-allowed policy
+ Correct manpage formatting in files section
+ Remove must be root statement from buildah doc
+ Change image names to stable, testing and upstream
+ Bump back to v1.9.0-dev
## v1.8.2 (2019-05-02)
Vendor Storage 1.12.6
diff --git a/vendor/github.com/containers/buildah/Makefile b/vendor/github.com/containers/buildah/Makefile
index 42ab36a3c..f8e079cbf 100644
--- a/vendor/github.com/containers/buildah/Makefile
+++ b/vendor/github.com/containers/buildah/Makefile
@@ -1,8 +1,7 @@
-export GO111MODULE=off
-
SELINUXTAG := $(shell ./selinux_tag.sh)
+APPARMORTAG := $(shell hack/apparmor_tag.sh)
STORAGETAGS := $(shell ./btrfs_tag.sh) $(shell ./btrfs_installed_tag.sh) $(shell ./libdm_tag.sh) $(shell ./ostree_tag.sh)
-SECURITYTAGS ?= seccomp $(SELINUXTAG)
+SECURITYTAGS ?= seccomp $(SELINUXTAG) $(APPARMORTAG)
TAGS ?= $(SECURITYTAGS) $(STORAGETAGS)
BUILDTAGS += $(TAGS)
PREFIX := /usr/local
@@ -10,9 +9,17 @@ BINDIR := $(PREFIX)/bin
BASHINSTALLDIR = $(PREFIX)/share/bash-completion/completions
BUILDFLAGS := -tags "$(BUILDTAGS)"
BUILDAH := buildah
+
GO := go
GO110 := 1.10
GOVERSION := $(findstring $(GO110),$(shell go version))
+# test for go module support
+ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true)
+export GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
+else
+export GO_BUILD=$(GO) build
+endif
+
GIT_COMMIT ?= $(if $(shell git rev-parse --short HEAD),$(shell git rev-parse --short HEAD),$(error "git failed"))
BUILD_INFO := $(if $(shell date +%s),$(shell date +%s),$(error "date failed"))
STATIC_STORAGETAGS = "containers_image_ostree_stub containers_image_openpgp exclude_graphdriver_devicemapper $(STORAGE_TAGS)"
@@ -33,15 +40,15 @@ static: $(SOURCES)
.PHONY: binary
binary: $(SOURCES)
- $(GO) build $(LDFLAGS) -o $(BUILDAH) $(BUILDFLAGS) ./cmd/buildah
+ $(GO_BUILD) $(LDFLAGS) -o $(BUILDAH) $(BUILDFLAGS) ./cmd/buildah
buildah: binary
darwin:
- GOOS=darwin $(GO) build $(LDFLAGS) -o buildah.darwin -tags "containers_image_openpgp" ./cmd/buildah
+ GOOS=darwin $(GO_BUILD) $(LDFLAGS) -o buildah.darwin -tags "containers_image_openpgp" ./cmd/buildah
imgtype: *.go docker/*.go util/*.go tests/imgtype/imgtype.go
- $(GO) build $(LDFLAGS) -o imgtype $(BUILDFLAGS) ./tests/imgtype/imgtype.go
+ $(GO_BUILD) $(LDFLAGS) -o imgtype $(BUILDFLAGS) ./tests/imgtype/imgtype.go
.PHONY: clean
clean:
@@ -121,7 +128,7 @@ test-integration: install.tools
cd tests; ./test_runner.sh
tests/testreport/testreport: tests/testreport/testreport.go
- $(GO) build -ldflags "-linkmode external -extldflags -static" -tags "$(STORAGETAGS) $(SECURITYTAGS)" -o tests/testreport/testreport ./tests/testreport
+ $(GO_BUILD) -ldflags "-linkmode external -extldflags -static" -tags "$(STORAGETAGS) $(SECURITYTAGS)" -o tests/testreport/testreport ./tests/testreport
.PHONY: test-unit
test-unit: tests/testreport/testreport
diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go
index ba5a1c77e..cd0d48566 100644
--- a/vendor/github.com/containers/buildah/buildah.go
+++ b/vendor/github.com/containers/buildah/buildah.go
@@ -26,7 +26,7 @@ const (
Package = "buildah"
// Version for the Package. Bump version in contrib/rpm/buildah.spec
// too.
- Version = "1.9.2"
+ Version = "1.10.1"
// 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/changelog.txt b/vendor/github.com/containers/buildah/changelog.txt
index 9f64f903b..48c67d842 100644
--- a/vendor/github.com/containers/buildah/changelog.txt
+++ b/vendor/github.com/containers/buildah/changelog.txt
@@ -1,3 +1,29 @@
+- Changelog for v1.10.1 (2019-08-08)
+ * Bump containers/image to v3.0.2 to fix keyring issue
+ * Bug fix for volume minus syntax
+ * Bump container/storage v1.13.1 and containers/image v3.0.1
+ * bump github.com/containernetworking/cni to v0.7.1
+ * Add overlayfs to fuse-overlayfs tip
+ * Add automatic apparmor tag discovery
+ * Fix bug whereby --get-login has no effect
+ * Bump to v1.11.0-dev
+
+- Changelog for v1.10.0 (2019-08-02)
+ * vendor github.com/containers/image@v3.0.0
+ * Remove GO111MODULE in favor of `-mod=vendor`
+ * Vendor in containers/storage v1.12.16
+ * Add '-' minus syntax for removal of config values
+ * tests: enable overlay tests for rootless
+ * rootless, overlay: use fuse-overlayfs
+ * vendor github.com/containers/image@v2.0.1
+ * Added '-' syntax to remove volume config option
+ * delete `successfully pushed` message
+ * Add golint linter and apply fixes
+ * vendor github.com/containers/storage@v1.12.15
+ * Change wait to sleep in buildahimage readme
+ * Handle ReadOnly images when deleting images
+ * Add support for listing read/only images
+
- Changelog for v1.9.2 (2019-07-19)
* from/import: record the base image's digest, if it has one
* Fix CNI version retrieval to not require network connection
diff --git a/vendor/github.com/containers/buildah/chroot/run.go b/vendor/github.com/containers/buildah/chroot/run.go
index db8a4ff06..b224fb367 100644
--- a/vendor/github.com/containers/buildah/chroot/run.go
+++ b/vendor/github.com/containers/buildah/chroot/run.go
@@ -205,13 +205,13 @@ func runUsingChrootMain() {
}
// Prepare to shuttle stdio back and forth.
- rootUid32, rootGid32, err := util.GetHostRootIDs(options.Spec)
+ rootUID32, rootGID32, err := util.GetHostRootIDs(options.Spec)
if err != nil {
logrus.Errorf("error determining ownership for container stdio")
os.Exit(1)
}
- rootUid := int(rootUid32)
- rootGid := int(rootGid32)
+ rootUID := int(rootUID32)
+ rootGID := int(rootGID32)
relays := make(map[int]int)
closeOnceRunning := []*os.File{}
var ctty *os.File
@@ -288,7 +288,7 @@ func runUsingChrootMain() {
// Open an *os.File object that we can pass to our child.
ctty = os.NewFile(ptyFd, "/dev/tty")
// Set ownership for the PTY.
- if err = ctty.Chown(rootUid, rootGid); err != nil {
+ if err = ctty.Chown(rootUID, rootGID); err != nil {
var cttyInfo unix.Stat_t
err2 := unix.Fstat(int(ptyFd), &cttyInfo)
from := ""
@@ -297,7 +297,7 @@ func runUsingChrootMain() {
op = "changing"
from = fmt.Sprintf("from %d/%d ", cttyInfo.Uid, cttyInfo.Gid)
}
- logrus.Warnf("error %s ownership of container PTY %sto %d/%d: %v", op, from, rootUid, rootGid, err)
+ logrus.Warnf("error %s ownership of container PTY %sto %d/%d: %v", op, from, rootUID, rootGID, err)
}
// Set permissions on the PTY.
if err = ctty.Chmod(0620); err != nil {
@@ -336,15 +336,15 @@ func runUsingChrootMain() {
fdDesc[unix.Stdout] = "stdout"
fdDesc[unix.Stderr] = "stderr"
// Set ownership for the pipes.
- if err = stdinRead.Chown(rootUid, rootGid); err != nil {
+ if err = stdinRead.Chown(rootUID, rootGID); err != nil {
logrus.Errorf("error setting ownership of container stdin pipe: %v", err)
os.Exit(1)
}
- if err = stdoutWrite.Chown(rootUid, rootGid); err != nil {
+ if err = stdoutWrite.Chown(rootUID, rootGID); err != nil {
logrus.Errorf("error setting ownership of container stdout pipe: %v", err)
os.Exit(1)
}
- if err = stderrWrite.Chown(rootUid, rootGid); err != nil {
+ if err = stderrWrite.Chown(rootUID, rootGID); err != nil {
logrus.Errorf("error setting ownership of container stderr pipe: %v", err)
os.Exit(1)
}
diff --git a/vendor/github.com/containers/buildah/config.go b/vendor/github.com/containers/buildah/config.go
index 8665e4143..0292ea43c 100644
--- a/vendor/github.com/containers/buildah/config.go
+++ b/vendor/github.com/containers/buildah/config.go
@@ -422,6 +422,16 @@ func (b *Builder) Volumes() []string {
return nil
}
+// CheckVolume returns True if the location exists in the image's list of locations
+// which should be mounted from outside of the container when a container
+// based on an image built from this container is run
+
+func (b *Builder) CheckVolume(v string) bool {
+ _, OCIv1Volume := b.OCIv1.Config.Volumes[v]
+ _, DockerVolume := b.Docker.Config.Volumes[v]
+ return OCIv1Volume || DockerVolume
+}
+
// AddVolume adds a location to the image's list of locations which should be
// mounted from outside of the container when a container based on an image
// built from this container is run.
diff --git a/vendor/github.com/containers/buildah/go.mod b/vendor/github.com/containers/buildah/go.mod
index 7e80b0a83..197db35da 100644
--- a/vendor/github.com/containers/buildah/go.mod
+++ b/vendor/github.com/containers/buildah/go.mod
@@ -3,19 +3,16 @@ module github.com/containers/buildah
go 1.12
require (
- github.com/BurntSushi/toml v0.2.0 // indirect
- github.com/DataDog/zstd v1.4.0 // indirect
- github.com/Microsoft/hcsshim v0.8.3 // indirect
github.com/VividCortex/ewma v1.1.1 // indirect
github.com/blang/semver v3.5.0+incompatible // indirect
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect
- github.com/containernetworking/cni v0.7.0-rc2
- github.com/containers/image v2.0.0+incompatible
- github.com/containers/storage v1.12.13
+ github.com/containernetworking/cni v0.7.1
+ github.com/containers/image v3.0.2+incompatible
+ github.com/containers/storage v1.13.1
github.com/cyphar/filepath-securejoin v0.2.1
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65
github.com/docker/docker-credential-helpers v0.6.1 // indirect
- github.com/docker/go-units v0.3.3
+ github.com/docker/go-units v0.4.0
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/etcd-io/bbolt v1.3.2
@@ -26,12 +23,8 @@ require (
github.com/imdario/mergo v0.3.6 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111 // indirect
- github.com/klauspost/compress v1.4.1 // indirect
- github.com/klauspost/cpuid v1.2.0 // indirect
- github.com/klauspost/pgzip v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
- github.com/mattn/go-shellwords v1.0.3
- github.com/mistifyio/go-zfs v2.1.1+incompatible // indirect
+ github.com/mattn/go-shellwords v1.0.5
github.com/moby/moby v0.0.0-20171005181806-f8806b18b4b9 // indirect
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c // indirect
github.com/onsi/ginkgo v1.6.0
@@ -43,26 +36,21 @@ require (
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.2.2
github.com/openshift/imagebuilder v1.1.0
- github.com/ostreedev/ostree-go v0.0.0-20181112201119-9ab99253d365 // indirect
github.com/pkg/errors v0.8.1
- github.com/pquerna/ffjson v0.0.0-20171002144729-d49c2bc1aa13 // indirect
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4
github.com/seccomp/libseccomp-golang v0.9.0
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
- github.com/tchap/go-patricia v2.2.6+incompatible // indirect
github.com/ulikunitz/xz v0.5.5 // indirect
- github.com/vbatts/tar-split v0.10.2 // indirect
- github.com/vbauerster/mpb v3.3.4+incompatible // indirect
+ github.com/vbauerster/mpb v3.4.0+incompatible // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.1.0 // indirect
- golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc
- golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 // indirect
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
- golang.org/x/sys v0.0.0-20190422165155-953cdadca894
+ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb
gopkg.in/yaml.v2 v2.2.2 // indirect
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083 // indirect
)
diff --git a/vendor/github.com/containers/buildah/go.sum b/vendor/github.com/containers/buildah/go.sum
index d8e8f983f..1016bcbea 100644
--- a/vendor/github.com/containers/buildah/go.sum
+++ b/vendor/github.com/containers/buildah/go.sum
@@ -2,12 +2,18 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.2.0 h1:OthAm9ZSUx4uAmn3WbPwc06nowWrByRwBsYRhbmFjBs=
github.com/BurntSushi/toml v0.2.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/zstd v1.4.0 h1:vhoV+DUHnRZdKW1i5UMjAk2G4JY8wN4ayRfYDNdEhwo=
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
+github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/hcsshim v0.8.3 h1:KWCdVGOju81E0RL4ndn9/E6I4qMBi6kuPw1W4yBYlCw=
github.com/Microsoft/hcsshim v0.8.3/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
@@ -19,15 +25,37 @@ github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882b
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containernetworking/cni v0.7.0-rc2 h1:2GGDhbwdWPY53iT7LXy+LBP76Ch2D/hnw1U2zVFfGbk=
github.com/containernetworking/cni v0.7.0-rc2/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containers/image v2.0.0+incompatible h1:FTr6Br7jlIKNCKMjSOMbAxKp2keQ0//jzJaYNTVhauk=
github.com/containers/image v2.0.0+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/image v2.0.1+incompatible h1:w39mlElA/aSFZ6moFa5N+A4MWu9c8hgdMiMMYnH94Hs=
+github.com/containers/image v2.0.1+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/image v3.0.0+incompatible h1:pdUHY//H+3jYNnoTt+rqY8NsStX4ZBLKzPTlMC+XvnU=
+github.com/containers/image v3.0.0+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/image v3.0.1+incompatible h1:VlNEQUI1JHa1SJfJ4jz/GBt7gpk+aRYGR6TUKsxXMkU=
+github.com/containers/image v3.0.1+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/image v3.0.2+incompatible h1:B1lqAE8MUPCrsBLE86J0gnXleeRq8zJnQryhiiGQNyE=
+github.com/containers/image v3.0.2+incompatible/go.mod h1:8Vtij257IWSanUQKe1tAeNOm2sRVkSqQTVQ1IlwI3+M=
+github.com/containers/storage v1.12.10-0.20190725063046-8038df61d6f6 h1:c7Fq9bbRl0Ua6swRHAH8rkrK2fSt6K+ZBrXHD50kDR4=
+github.com/containers/storage v1.12.10-0.20190725063046-8038df61d6f6/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
github.com/containers/storage v1.12.13 h1:GtaLCY8p1Drlk1Oew581jGvB137UaO+kpz0HII67T0A=
github.com/containers/storage v1.12.13/go.mod h1:+RirK6VQAqskQlaTBrOG6ulDvn4si2QjFE1NZCn06MM=
+github.com/containers/storage v1.12.14 h1:S1QGlC15gj5JOvB73W5tpVBApS4I7b/6rvxfflBAg+Q=
+github.com/containers/storage v1.12.14/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
+github.com/containers/storage v1.12.15 h1:nN/RxtEe4ejasGVJqzy+y5++pIYp54XPXzRO46xXnns=
+github.com/containers/storage v1.12.15/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
+github.com/containers/storage v1.12.16 h1:zePYS1GiG8CuRqLCeA0ufx4X27K06HcJLV50DdojL+Y=
+github.com/containers/storage v1.12.16/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
+github.com/containers/storage v1.13.1 h1:rjVirLS9fCGkUFlLDZEoGDDUugtIf46DufWvJu08wxQ=
+github.com/containers/storage v1.13.1/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/cyphar/filepath-securejoin v0.2.1 h1:5DPkzz/0MwUpvR4fxASKzgApeq2OMFY5FfYtrX28Coo=
github.com/cyphar/filepath-securejoin v0.2.1/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65 h1:4zlOyrJUbYnrvlzChJ+jP2J3i77Jbhm336NEuCv7kZo=
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23 h1:mJtkfC9RUrUWHMk0cFDNhVoc9U3k2FRAzEZ+5pqSIHo=
github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g=
@@ -36,6 +64,8 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libnetwork v0.8.0-dev.2.0.20180608203834-19279f049241/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8=
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316 h1:moehPjPiGUaWdwgOl92xRyFHJyaqXDHcCyW9M6nmCK4=
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8=
@@ -71,8 +101,12 @@ github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111 h1:NAAiV9ass6VRe
github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.7.2 h1:liMOoeIvFpr9kEvalrZ7VVBA4wGf7zfOgwBjzz/5g2Y=
+github.com/klauspost/compress v1.7.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
+github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
@@ -81,6 +115,8 @@ github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-shellwords v1.0.3 h1:K/VxK7SZ+cvuPgFSLKi5QPI9Vr/ipOf4C1gN+ntueUk=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9wIsXc=
+github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/moby/moby v0.0.0-20171005181806-f8806b18b4b9/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
@@ -108,12 +144,16 @@ github.com/openshift/imagebuilder v1.1.0 h1:oT704SkwMEzmIMU/+Uv1Wmvt+p10q3v2WuYM
github.com/openshift/imagebuilder v1.1.0/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/ostreedev/ostree-go v0.0.0-20181112201119-9ab99253d365 h1:5DKEDlc/DLftia3h4tk5K0KBiqBXogCc6EarWTlD3fM=
github.com/ostreedev/ostree-go v0.0.0-20181112201119-9ab99253d365/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
+github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
+github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/ffjson v0.0.0-20171002144729-d49c2bc1aa13 h1:AUK/hm/tPsiNNASdb3J8fySVRZoI7fnK5mlOvdFD43o=
github.com/pquerna/ffjson v0.0.0-20171002144729-d49c2bc1aa13/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
+github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 h1:gGBSHPOU7g8YjTbhwn+lvFm2VDEhhA+PwDIlstkgSxE=
+github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4 h1:rOG9oHVIndNR14f3HRyBy9UPQYmIPniWqTU1TDdHhq4=
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4/go.mod h1:f/98/SnvAzhAEFQJ3u836FePXvcbE8BS0YGMQNn4mhA=
github.com/seccomp/libseccomp-golang v0.9.0 h1:S1pmhdFh5spQtVojA+4GUdWBqvI8ydYHxrx8iR6xN8o=
@@ -125,20 +165,30 @@ github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.2.6+incompatible h1:JvoDL7JSoIP2HDE8AbDH3zC8QBPxmzYe32HHy5yQ+Ck=
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
+github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/vbatts/tar-split v0.10.2 h1:CXd7HEKGkTLjBMinpObcJZU5Hm8EKlor2a1JtX6msXQ=
github.com/vbatts/tar-split v0.10.2/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
+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 v3.3.4+incompatible h1:DDIhnwmgTQIDZo+SWlEr5d6mJBxkOLBwCXPzunhEfJ4=
github.com/vbauerster/mpb v3.3.4+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
+github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tLAD8IceomUCNw=
+github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vrothberg/storage v0.0.0-20190724065215-a1e42fd78930 h1:/LeIxi2kj5UYTJR9W35t5Pq2gqz03ZNoTURchTH3vc0=
+github.com/vrothberg/storage v0.0.0-20190724065215-a1e42fd78930/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@@ -148,19 +198,27 @@ github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4m
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8=
golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
@@ -171,6 +229,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083 h1:+Qf/nITucAbm09aIdxvoA+7X0BwaXmQGVoR8k7Ynk9o=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md
index 6ff2f327a..463f4ebc9 100644
--- a/vendor/github.com/containers/buildah/install.md
+++ b/vendor/github.com/containers/buildah/install.md
@@ -378,7 +378,7 @@ cat /etc/containers/policy.json
## Vendoring
Buildah uses Go Modules for vendoring purposes. If you need to update or add a vendored package into Buildah, please follow this proceedure:
- * Enter into your sandbox `src/github.com/containers/buildah` and ensure that he GOPATH variable is set to the directory prior as noted above.
+ * Enter into your sandbox `src/github.com/containers/buildah` and ensure that the GOPATH variable is set to the directory prior as noted above.
* `export GO111MODULE=on`
* Assuming you want to 'bump' the `github.com/containers/storage` package to version 1.12.13, use this command: `go get github.com/containers/storage@v1.12.13`
* `make vendor`
diff --git a/vendor/github.com/containers/buildah/new.go b/vendor/github.com/containers/buildah/new.go
index 72d53dd99..5642ef916 100644
--- a/vendor/github.com/containers/buildah/new.go
+++ b/vendor/github.com/containers/buildah/new.go
@@ -8,7 +8,7 @@ import (
"github.com/containers/buildah/util"
"github.com/containers/image/manifest"
- "github.com/containers/image/pkg/sysregistries"
+ "github.com/containers/image/pkg/sysregistriesv2"
is "github.com/containers/image/storage"
"github.com/containers/image/transports"
"github.com/containers/image/transports/alltransports"
@@ -186,7 +186,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
return nil, "", nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures)
}
- registriesConfPath := sysregistries.RegistriesConfPath(systemContext)
+ registriesConfPath := sysregistriesv2.ConfigPath(systemContext)
switch len(failures) {
case 0:
if searchRegistriesWereUsedButEmpty {
diff --git a/vendor/github.com/containers/buildah/ostree_tag.sh b/vendor/github.com/containers/buildah/ostree_tag.sh
index bae9d5108..6a2f2e38b 100644
--- a/vendor/github.com/containers/buildah/ostree_tag.sh
+++ b/vendor/github.com/containers/buildah/ostree_tag.sh
@@ -1,6 +1,6 @@
#!/bin/bash
if pkg-config ostree-1 2> /dev/null ; then
- echo ostree
+ echo containers_image_ostree
else
echo containers_image_ostree_stub
fi
diff --git a/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go b/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
index f2f2cac79..53e6ec44b 100644
--- a/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
+++ b/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
@@ -414,8 +414,8 @@ func saveStream(wg *sync.WaitGroup, decompressReader io.ReadCloser, tempFile *os
}
}
-func (s *blobCacheDestination) HasThreadSafePutBlob() bool {
- return s.destination.HasThreadSafePutBlob()
+func (d *blobCacheDestination) HasThreadSafePutBlob() bool {
+ return d.destination.HasThreadSafePutBlob()
}
func (d *blobCacheDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go
index 81f3e8f32..d3c071555 100644
--- a/vendor/github.com/containers/buildah/pkg/cli/common.go
+++ b/vendor/github.com/containers/buildah/pkg/cli/common.go
@@ -71,7 +71,7 @@ type BudResults struct {
Squash bool
Tag []string
Target string
- TlsVerify bool
+ TLSVerify bool
}
// FromAndBugResults represents the results for common flags
@@ -90,7 +90,7 @@ type FromAndBudResults struct {
DNSSearch []string
DNSServers []string
DNSOptions []string
- HttpProxy bool
+ HTTPProxy bool
Isolation string
Memory string
MemorySwap string
@@ -166,7 +166,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer.")
fs.StringArrayVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image")
fs.StringVar(&flags.Target, "target", "", "set the target build stage to build")
- fs.BoolVar(&flags.TlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
+ fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
return fs
}
@@ -188,7 +188,7 @@ func GetFromAndBudFlags(flags *FromAndBudResults, usernsResults *UserNSResults,
fs.StringSliceVar(&flags.DNSSearch, "dns-search", []string{}, "Set custom DNS search domains")
fs.StringSliceVar(&flags.DNSServers, "dns", []string{}, "Set custom DNS servers")
fs.StringSliceVar(&flags.DNSOptions, "dns-option", []string{}, "Set custom DNS options")
- fs.BoolVar(&flags.HttpProxy, "http-proxy", true, "pass thru HTTP Proxy environment variables")
+ fs.BoolVar(&flags.HTTPProxy, "http-proxy", true, "pass thru HTTP Proxy environment variables")
fs.StringVar(&flags.Isolation, "isolation", DefaultIsolation(), "`type` of process isolation to use. Use BUILDAH_ISOLATION environment variable to override.")
fs.StringVarP(&flags.Memory, "memory", "m", "", "memory limit (format: <number>[<unit>], where unit = b, k, m or g)")
fs.StringVar(&flags.MemorySwap, "memory-swap", "", "swap limit equal to memory plus swap: '-1' to enable unlimited swap")
diff --git a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
index 14d29a25b..ae1c63148 100644
--- a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
+++ b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
@@ -4,21 +4,24 @@ import (
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"strings"
+ "github.com/containers/buildah/pkg/unshare"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
+ "golang.org/x/sys/unix"
)
// MountTemp creates a subdir of the contentDir based on the source directory
-// from the source system. It then mounds up the source directory on to the
+// from the source system. It then mounts up the source directory on to the
// generated mount point and returns the mount point to the caller.
-func MountTemp(store storage.Store, containerId, source, dest string, rootUID, rootGID int) (mount specs.Mount, contentDir string, Err error) {
+func MountTemp(store storage.Store, containerID, source, dest string, rootUID, rootGID int) (mount specs.Mount, contentDir string, Err error) {
- containerDir, err := store.ContainerDirectory(containerId)
+ containerDir, err := store.ContainerDirectory(containerID)
if err != nil {
return mount, "", err
}
@@ -46,10 +49,55 @@ func MountTemp(store storage.Store, containerId, source, dest string, rootUID, r
return mount, "", errors.Wrapf(err, "failed to create the overlay %s directory", workDir)
}
+ overlayOptions := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s,private", source, upperDir, workDir)
+
+ if unshare.IsRootless() {
+ mountProgram := ""
+
+ mountMap := map[string]bool{
+ ".mount_program": true,
+ "overlay.mount_program": true,
+ "overlay2.mount_program": true,
+ }
+
+ for _, i := range store.GraphOptions() {
+ s := strings.SplitN(i, "=", 2)
+ if len(s) != 2 {
+ continue
+ }
+ k := s[0]
+ v := s[1]
+ if mountMap[k] {
+ mountProgram = v
+ break
+ }
+ }
+ if mountProgram != "" {
+ mergeDir := filepath.Join(contentDir, "merge")
+
+ if err := idtools.MkdirAllAs(mergeDir, 0700, rootUID, rootGID); err != nil {
+ return mount, "", errors.Wrapf(err, "failed to create the overlay %s directory", mergeDir)
+ }
+
+ cmd := exec.Command(mountProgram, "-o", overlayOptions, mergeDir)
+
+ if err := cmd.Run(); err != nil {
+ return mount, "", errors.Wrapf(err, "exec %s", mountProgram)
+ }
+
+ mount.Source = mergeDir
+ mount.Destination = dest
+ mount.Type = "bind"
+ mount.Options = []string{"bind", "slave"}
+ return mount, contentDir, nil
+ }
+ /* If a mount_program is not specified, fallback to try mount native overlay. */
+ }
+
mount.Source = "overlay"
mount.Destination = dest
mount.Type = "overlay"
- mount.Options = strings.Split(fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s,private", source, upperDir, workDir), ",")
+ mount.Options = strings.Split(overlayOptions, ",")
return mount, contentDir, nil
}
@@ -57,6 +105,14 @@ func MountTemp(store storage.Store, containerId, source, dest string, rootUID, r
// RemoveTemp removes temporary mountpoint and all content from its parent
// directory
func RemoveTemp(contentDir string) error {
+ if unshare.IsRootless() {
+ mergeDir := filepath.Join(contentDir, "merge")
+ if err := unix.Unmount(mergeDir, 0); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "unmount overlay %s", mergeDir)
+ }
+ }
+ }
return os.RemoveAll(contentDir)
}
@@ -64,6 +120,15 @@ func RemoveTemp(contentDir string) error {
// directory
func CleanupContent(containerDir string) (Err error) {
contentDir := filepath.Join(containerDir, "overlay")
+
+ if unshare.IsRootless() {
+ mergeDir := filepath.Join(contentDir, "merge")
+ if err := unix.Unmount(mergeDir, 0); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "unmount overlay %s", mergeDir)
+ }
+ }
+ }
if err := os.RemoveAll(contentDir); err != nil && !os.IsNotExist(err) {
return errors.Wrapf(err, "failed to cleanup overlay %s directory", contentDir)
}
diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go
index 78cbee746..0ab449c1e 100644
--- a/vendor/github.com/containers/buildah/pkg/parse/parse.go
+++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go
@@ -14,7 +14,6 @@ import (
"unicode"
"github.com/containers/buildah"
- "github.com/containers/buildah/pkg/unshare"
"github.com/containers/image/types"
"github.com/containers/storage/pkg/idtools"
"github.com/docker/go-units"
@@ -104,7 +103,7 @@ func CommonBuildOptions(c *cobra.Command) (*buildah.CommonBuildOptions, error) {
return nil, errors.Wrapf(err, "invalid --shm-size")
}
volumes, _ := c.Flags().GetStringSlice("volume")
- if err := ParseVolumes(volumes); err != nil {
+ if err := Volumes(volumes); err != nil {
return nil, err
}
cpuPeriod, _ := c.Flags().GetUint64("cpu-period")
@@ -179,8 +178,8 @@ func parseSecurityOpts(securityOpts []string, commonOpts *buildah.CommonBuildOpt
return nil
}
-// ParseVolume parses the input of --volume
-func ParseVolume(volume string) (specs.Mount, error) {
+// Volume parses the input of --volume
+func Volume(volume string) (specs.Mount, error) {
mount := specs.Mount{}
arr := strings.SplitN(volume, ":", 3)
if len(arr) < 2 {
@@ -207,13 +206,13 @@ func ParseVolume(volume string) (specs.Mount, error) {
return mount, nil
}
-// ParseVolumes validates the host and container paths passed in to the --volume flag
-func ParseVolumes(volumes []string) error {
+// Volumes validates the host and container paths passed in to the --volume flag
+func Volumes(volumes []string) error {
if len(volumes) == 0 {
return nil
}
for _, volume := range volumes {
- if _, err := ParseVolume(volume); err != nil {
+ if _, err := Volume(volume); err != nil {
return err
}
}
@@ -224,7 +223,7 @@ func getVolumeMounts(volumes []string) (map[string]specs.Mount, error) {
finalVolumeMounts := make(map[string]specs.Mount)
for _, volume := range volumes {
- volumeMount, err := ParseVolume(volume)
+ volumeMount, err := Volume(volume)
if err != nil {
return nil, err
}
@@ -473,9 +472,6 @@ func ValidateVolumeOpts(options []string) ([]string, error) {
}
foundRWRO++
case "z", "Z", "O":
- if opt == "O" && unshare.IsRootless() {
- return nil, errors.Errorf("invalid options %q, overlay mounts not supported in rootless mode", strings.Join(options, ", "))
- }
if foundLabelChange > 1 {
return nil, errors.Errorf("invalid options %q, can only specify 1 'z', 'Z', or 'O' option", strings.Join(options, ", "))
}
diff --git a/vendor/github.com/containers/buildah/troubleshooting.md b/vendor/github.com/containers/buildah/troubleshooting.md
index 3e292a6b2..96fa403f0 100644
--- a/vendor/github.com/containers/buildah/troubleshooting.md
+++ b/vendor/github.com/containers/buildah/troubleshooting.md
@@ -112,9 +112,7 @@ lstat /home/myusername/~: no such file or directory
---
### 5) Rootless buildah bud fails EPERM on NFS:
-NFS enforces file creation on different UIDs on the server side and does not understand User Namespace.
-When a container root process like YUM attempts to create a file owned by a different UID, NFS Server denies the creation.
-NFS is also a problem for the file locks when the storage is on it.
+NFS enforces file creation on different UIDs on the server side and does not understand user namespace, which rootless Podman requires. When a container root process like YUM attempts to create a file owned by a different UID, NFS Server denies the creation. NFS is also a problem for the file locks when the storage is on it. Other distributed file systems (for example: Lustre, Spectrum Scale, the General Parallel File System (GPFS)) are also not supported when running in rootless mode as these file systems do not understand user namespace.
#### Symptom
```console
@@ -127,4 +125,34 @@ error creating build container: Error committing the finished image: error addin
Choose one of the following:
* Setup containers/storage in a different directory, not on an NFS share.
* Otherwise just run buildah as root, via `sudo buildah`
---- \ No newline at end of file
+---
+### 6) Rootless buildah bud fails when using OverlayFS:
+
+The Overlay file system (OverlayFS) requires the ability to call the `mknod` command when creating whiteout files
+when extracting an image. However, a rootless user does not have the privileges to use `mknod` in this capacity.
+
+#### Symptom
+```console
+buildah bud --storage-driver overlay .
+STEP 1: FROM docker.io/ubuntu:xenial
+Getting image source signatures
+Copying blob edf72af6d627 done
+Copying blob 3e4f86211d23 done
+Copying blob 8d3eac894db4 done
+Copying blob f7277927d38a done
+Copying config 5e13f8dd4c done
+Writing manifest to image destination
+Storing signatures
+Error: error creating build container: Error committing the finished image: error adding layer with blob "sha256:8d3eac894db4dc4154377ad28643dfe6625ff0e54bcfa63e0d04921f1a8ef7f8": Error processing tar file(exit status 1): operation not permitted
+$ buildah bud .
+ERRO[0014] Error while applying layer: ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+error creating build container: Error committing the finished image: error adding layer with blob "sha256:a02a4930cb5d36f3290eb84f4bfa30668ef2e9fe3a1fb73ec015fc58b9958b17": ApplyLayer exit status 1 stdout: stderr: open /root/.bash_logout: permission denied
+```
+
+#### Solution
+Choose one of the following:
+ * Complete the build operation as a privileged user.
+ * Install and configure fuse-overlayfs.
+ * Install the fuse-overlayfs package for your Linux Distribution.
+ * Add `mount_program = "/usr/bin/fuse-overlayfs` under `[storage.options]` in your `~/.config/containers/storage.conf` file.
+---
diff --git a/vendor/github.com/containers/buildah/util.go b/vendor/github.com/containers/buildah/util.go
index 71505f19e..a44165921 100644
--- a/vendor/github.com/containers/buildah/util.go
+++ b/vendor/github.com/containers/buildah/util.go
@@ -8,7 +8,6 @@ import (
"github.com/containers/buildah/util"
"github.com/containers/image/docker/reference"
- "github.com/containers/image/pkg/sysregistries"
"github.com/containers/image/pkg/sysregistriesv2"
"github.com/containers/image/types"
"github.com/containers/storage"
@@ -279,17 +278,17 @@ func (b *Builder) untar(chownOpts *idtools.IDPair, hasher io.Writer) func(tarArc
func isRegistryBlocked(registry string, sc *types.SystemContext) (bool, error) {
reginfo, err := sysregistriesv2.FindRegistry(sc, registry)
if err != nil {
- return false, errors.Wrapf(err, "unable to parse the registries configuration (%s)", sysregistries.RegistriesConfPath(sc))
+ return false, errors.Wrapf(err, "unable to parse the registries configuration (%s)", sysregistriesv2.ConfigPath(sc))
}
if reginfo != nil {
if reginfo.Blocked {
- logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistries.RegistriesConfPath(sc))
+ logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc))
} else {
- logrus.Debugf("registry %q is not marked as blocked in registries configuration %q", registry, sysregistries.RegistriesConfPath(sc))
+ logrus.Debugf("registry %q is not marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc))
}
return reginfo.Blocked, nil
}
- logrus.Debugf("registry %q is not listed in registries configuration %q, assuming it's not blocked", registry, sysregistries.RegistriesConfPath(sc))
+ logrus.Debugf("registry %q is not listed in registries configuration %q, assuming it's not blocked", registry, sysregistriesv2.ConfigPath(sc))
return false, nil
}
diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go
index 81a43e0fa..48427f3d3 100644
--- a/vendor/github.com/containers/image/docker/docker_client.go
+++ b/vendor/github.com/containers/image/docker/docker_client.go
@@ -254,6 +254,9 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
return nil, errors.Wrapf(err, "error loading registries")
}
if reg != nil {
+ if reg.Blocked {
+ return nil, fmt.Errorf("registry %s is blocked in %s", reg.Prefix, sysregistriesv2.ConfigPath(sys))
+ }
skipVerify = reg.Insecure
}
tlsClientConfig.InsecureSkipVerify = skipVerify
@@ -523,11 +526,7 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
authReq.SetBasicAuth(c.username, c.password)
}
logrus.Debugf("%s %s", authReq.Method, authReq.URL.String())
- tr := tlsclientconfig.NewTransport()
- // TODO(runcom): insecure for now to contact the external token service
- tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
- client := &http.Client{Transport: tr}
- res, err := client.Do(authReq)
+ res, err := c.client.Do(authReq)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/ostree/ostree_src.go b/vendor/github.com/containers/image/ostree/ostree_src.go
index dc52ccb6e..43d8f6837 100644
--- a/vendor/github.com/containers/image/ostree/ostree_src.go
+++ b/vendor/github.com/containers/image/ostree/ostree_src.go
@@ -59,9 +59,15 @@ func (s *ostreeImageSource) Close() error {
return nil
}
-func (s *ostreeImageSource) getLayerSize(blob string) (int64, error) {
+func (s *ostreeImageSource) getBlobUncompressedSize(blob string, isCompressed bool) (int64, error) {
+ var metadataKey string
+ if isCompressed {
+ metadataKey = "docker.uncompressed_size"
+ } else {
+ metadataKey = "docker.size"
+ }
b := fmt.Sprintf("ociimage/%s", blob)
- found, data, err := readMetadata(s.repo, b, "docker.size")
+ found, data, err := readMetadata(s.repo, b, metadataKey)
if err != nil || !found {
return 0, err
}
@@ -275,8 +281,8 @@ func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
}
}
- compressedBlob, found := s.compressed[info.Digest]
- if found {
+ compressedBlob, isCompressed := s.compressed[info.Digest]
+ if isCompressed {
blob = compressedBlob.Hex()
}
branch := fmt.Sprintf("ociimage/%s", blob)
@@ -289,7 +295,7 @@ func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
s.repo = repo
}
- layerSize, err := s.getLayerSize(blob)
+ layerSize, err := s.getBlobUncompressedSize(blob, isCompressed)
if err != nil {
return nil, 0, err
}
diff --git a/vendor/github.com/containers/image/pkg/docker/config/config.go b/vendor/github.com/containers/image/pkg/docker/config/config.go
index 2e6bb378f..eef629d5c 100644
--- a/vendor/github.com/containers/image/pkg/docker/config/config.go
+++ b/vendor/github.com/containers/image/pkg/docker/config/config.go
@@ -32,9 +32,13 @@ var (
dockerHomePath = filepath.FromSlash(".docker/config.json")
dockerLegacyHomePath = ".dockercfg"
+ enableKeyring = false
+
// ErrNotLoggedIn is returned for users not logged into a registry
// that they are trying to logout of
ErrNotLoggedIn = errors.New("not logged in")
+ // ErrNotSupported is returned for unsupported methods
+ ErrNotSupported = errors.New("not supported")
)
// SetAuthentication stores the username and password in the auth.json file
@@ -44,6 +48,18 @@ func SetAuthentication(sys *types.SystemContext, registry, username, password st
return false, setAuthToCredHelper(ch, registry, username, password)
}
+ // Set the credentials to kernel keyring if enableKeyring is true.
+ // The keyring might not work in all environments (e.g., missing capability) and isn't supported on all platforms.
+ // Hence, we want to fall-back to using the authfile in case the keyring failed.
+ // However, if the enableKeyring is false, we want adhere to the user specification and not use the keyring.
+ if enableKeyring {
+ err := setAuthToKernelKeyring(registry, username, password)
+ if err == nil {
+ logrus.Debugf("credentials for (%s, %s) were stored in the kernel keyring\n", registry, username)
+ return false, nil
+ }
+ logrus.Debugf("failed to authenticate with the kernel keyring, falling back to authfiles. %v", err)
+ }
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
newCreds := dockerAuthConfig{Auth: creds}
auths.AuthConfigs[registry] = newCreds
@@ -60,6 +76,14 @@ func GetAuthentication(sys *types.SystemContext, registry string) (string, strin
return sys.DockerAuthConfig.Username, sys.DockerAuthConfig.Password, nil
}
+ if enableKeyring {
+ username, password, err := getAuthFromKernelKeyring(registry)
+ if err == nil {
+ logrus.Debug("returning credentials from kernel keyring")
+ return username, password, nil
+ }
+ }
+
dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyHomePath)
var paths []string
pathToAuth, err := getPathToAuth(sys)
@@ -97,6 +121,16 @@ func RemoveAuthentication(sys *types.SystemContext, registry string) error {
return false, deleteAuthFromCredHelper(ch, registry)
}
+ // Next if keyring is enabled try kernel keyring
+ if enableKeyring {
+ err := deleteAuthFromKernelKeyring(registry)
+ if err == nil {
+ logrus.Debugf("credentials for %s were deleted from the kernel keyring", registry)
+ return false, nil
+ }
+ logrus.Debugf("failed to delete credentials from the kernel keyring, falling back to authfiles")
+ }
+
if _, ok := auths.AuthConfigs[registry]; ok {
delete(auths.AuthConfigs, registry)
} else if _, ok := auths.AuthConfigs[normalizeRegistry(registry)]; ok {
diff --git a/vendor/github.com/containers/image/pkg/docker/config/config_linux.go b/vendor/github.com/containers/image/pkg/docker/config/config_linux.go
new file mode 100644
index 000000000..4d66a50df
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/docker/config/config_linux.go
@@ -0,0 +1,79 @@
+package config
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/containers/image/pkg/keyctl"
+ "github.com/pkg/errors"
+)
+
+func getAuthFromKernelKeyring(registry string) (string, string, error) {
+ userkeyring, err := keyctl.UserKeyring()
+ if err != nil {
+ return "", "", err
+ }
+ key, err := userkeyring.Search(genDescription(registry))
+ if err != nil {
+ return "", "", err
+ }
+ authData, err := key.Get()
+ if err != nil {
+ return "", "", err
+ }
+ parts := strings.SplitN(string(authData), "\x00", 2)
+ if len(parts) != 2 {
+ return "", "", nil
+ }
+ return parts[0], parts[1], nil
+}
+
+func deleteAuthFromKernelKeyring(registry string) error {
+ userkeyring, err := keyctl.UserKeyring()
+
+ if err != nil {
+ return err
+ }
+ key, err := userkeyring.Search(genDescription(registry))
+ if err != nil {
+ return err
+ }
+ return key.Unlink()
+}
+
+func setAuthToKernelKeyring(registry, username, password string) error {
+ keyring, err := keyctl.SessionKeyring()
+ if err != nil {
+ return err
+ }
+ id, err := keyring.Add(genDescription(registry), []byte(fmt.Sprintf("%s\x00%s", username, password)))
+ if err != nil {
+ return err
+ }
+
+ // sets all permission(view,read,write,search,link,set attribute) for current user
+ // it enables the user to search the key after it linked to user keyring and unlinked from session keyring
+ err = keyctl.SetPerm(id, keyctl.PermUserAll)
+ if err != nil {
+ return err
+ }
+ // link the key to userKeyring
+ userKeyring, err := keyctl.UserKeyring()
+ if err != nil {
+ return errors.Wrapf(err, "error getting user keyring")
+ }
+ err = keyctl.Link(userKeyring, id)
+ if err != nil {
+ return errors.Wrapf(err, "error linking the key to user keyring")
+ }
+ // unlink the key from session keyring
+ err = keyctl.Unlink(keyring, id)
+ if err != nil {
+ return errors.Wrapf(err, "error unlinking the key from session keyring")
+ }
+ return nil
+}
+
+func genDescription(registry string) string {
+ return fmt.Sprintf("container-registry-login:%s", registry)
+}
diff --git a/vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go b/vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
new file mode 100644
index 000000000..1c1a02511
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
@@ -0,0 +1,16 @@
+// +build !linux
+// +build !386 !amd64
+
+package config
+
+func getAuthFromKernelKeyring(registry string) (string, string, error) {
+ return "", "", ErrNotSupported
+}
+
+func deleteAuthFromKernelKeyring(registry string) error {
+ return ErrNotSupported
+}
+
+func setAuthToKernelKeyring(registry, username, password string) error {
+ return ErrNotSupported
+}
diff --git a/vendor/github.com/containers/image/pkg/keyctl/key.go b/vendor/github.com/containers/image/pkg/keyctl/key.go
new file mode 100644
index 000000000..e4396a9df
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/keyctl/key.go
@@ -0,0 +1,64 @@
+// Copyright 2015 Jesse Sipprell. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package keyctl
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// Key represents a single key linked to one or more kernel keyrings.
+type Key struct {
+ Name string
+
+ id, ring keyID
+ size int
+}
+
+// ID returns the 32-bit kernel identifier for a specific key
+func (k *Key) ID() int32 {
+ return int32(k.id)
+}
+
+// Get the key's value as a byte slice
+func (k *Key) Get() ([]byte, error) {
+ var (
+ b []byte
+ err error
+ sizeRead int
+ )
+
+ if k.size == 0 {
+ k.size = 512
+ }
+
+ size := k.size
+
+ b = make([]byte, int(size))
+ sizeRead = size + 1
+ for sizeRead > size {
+ r1, err := unix.KeyctlBuffer(unix.KEYCTL_READ, int(k.id), b, size)
+ if err != nil {
+ return nil, err
+ }
+
+ if sizeRead = int(r1); sizeRead > size {
+ b = make([]byte, sizeRead)
+ size = sizeRead
+ sizeRead = size + 1
+ } else {
+ k.size = sizeRead
+ }
+ }
+ return b[:k.size], err
+}
+
+// Unlink a key from the keyring it was loaded from (or added to). If the key
+// is not linked to any other keyrings, it is destroyed.
+func (k *Key) Unlink() error {
+ _, err := unix.KeyctlInt(unix.KEYCTL_UNLINK, int(k.id), int(k.ring), 0, 0)
+ return err
+}
diff --git a/vendor/github.com/containers/image/pkg/keyctl/keyring.go b/vendor/github.com/containers/image/pkg/keyctl/keyring.go
new file mode 100644
index 000000000..6e029c923
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/keyctl/keyring.go
@@ -0,0 +1,79 @@
+// Copyright 2015 Jesse Sipprell. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+// Package keyctl is a Go interface to linux kernel keyrings (keyctl interface)
+//
+// Deprecated: Most callers should use either golang.org/x/sys/unix directly,
+// or the original (and more extensive) github.com/jsipprell/keyctl .
+package keyctl
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// Keyring is the basic interface to a linux keyctl keyring.
+type Keyring interface {
+ ID
+ Add(string, []byte) (*Key, error)
+ Search(string) (*Key, error)
+}
+
+type keyring struct {
+ id keyID
+}
+
+// ID is unique 32-bit serial number identifiers for all Keys and Keyrings have.
+type ID interface {
+ ID() int32
+}
+
+// Add a new key to a keyring. The key can be searched for later by name.
+func (kr *keyring) Add(name string, key []byte) (*Key, error) {
+ r, err := unix.AddKey("user", name, key, int(kr.id))
+ if err == nil {
+ key := &Key{Name: name, id: keyID(r), ring: kr.id}
+ return key, nil
+ }
+ return nil, err
+}
+
+// Search for a key by name, this also searches child keyrings linked to this
+// one. The key, if found, is linked to the top keyring that Search() was called
+// from.
+func (kr *keyring) Search(name string) (*Key, error) {
+ id, err := unix.KeyctlSearch(int(kr.id), "user", name, 0)
+ if err == nil {
+ return &Key{Name: name, id: keyID(id), ring: kr.id}, nil
+ }
+ return nil, err
+}
+
+// ID returns the 32-bit kernel identifier of a keyring
+func (kr *keyring) ID() int32 {
+ return int32(kr.id)
+}
+
+// SessionKeyring returns the current login session keyring
+func SessionKeyring() (Keyring, error) {
+ return newKeyring(unix.KEY_SPEC_SESSION_KEYRING)
+}
+
+// UserKeyring returns the keyring specific to the current user.
+func UserKeyring() (Keyring, error) {
+ return newKeyring(unix.KEY_SPEC_USER_KEYRING)
+}
+
+// Unlink an object from a keyring
+func Unlink(parent Keyring, child ID) error {
+ _, err := unix.KeyctlInt(unix.KEYCTL_UNLINK, int(child.ID()), int(parent.ID()), 0, 0)
+ return err
+}
+
+// Link a key into a keyring
+func Link(parent Keyring, child ID) error {
+ _, err := unix.KeyctlInt(unix.KEYCTL_LINK, int(child.ID()), int(parent.ID()), 0, 0)
+ return err
+}
diff --git a/vendor/github.com/containers/image/pkg/keyctl/perm.go b/vendor/github.com/containers/image/pkg/keyctl/perm.go
new file mode 100644
index 000000000..ae9697149
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/keyctl/perm.go
@@ -0,0 +1,33 @@
+// Copyright 2015 Jesse Sipprell. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package keyctl
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// KeyPerm represents in-kernel access control permission to keys and keyrings
+// as a 32-bit integer broken up into four permission sets, one per byte.
+// In MSB order, the perms are: Processor, User, Group, Other.
+type KeyPerm uint32
+
+const (
+ // PermOtherAll sets all permission for Other
+ PermOtherAll KeyPerm = 0x3f << (8 * iota)
+ // PermGroupAll sets all permission for Group
+ PermGroupAll
+ // PermUserAll sets all permission for User
+ PermUserAll
+ // PermProcessAll sets all permission for Processor
+ PermProcessAll
+)
+
+// SetPerm sets the permissions on a key or keyring.
+func SetPerm(k ID, p KeyPerm) error {
+ err := unix.KeyctlSetperm(int(k.ID()), uint32(p))
+ return err
+}
diff --git a/vendor/github.com/containers/image/pkg/keyctl/sys_linux.go b/vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
new file mode 100644
index 000000000..196c82760
--- /dev/null
+++ b/vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
@@ -0,0 +1,25 @@
+// Copyright 2015 Jesse Sipprell. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package keyctl
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+type keyID int32
+
+func newKeyring(id keyID) (*keyring, error) {
+ r1, err := unix.KeyctlGetKeyringID(int(id), true)
+ if err != nil {
+ return nil, err
+ }
+
+ if id < 0 {
+ r1 = int(id)
+ }
+ return &keyring{id: keyID(r1)}, nil
+}
diff --git a/vendor/github.com/containers/image/pkg/sysregistries/system_registries.go b/vendor/github.com/containers/image/pkg/sysregistries/system_registries.go
deleted file mode 100644
index 09b419cc8..000000000
--- a/vendor/github.com/containers/image/pkg/sysregistries/system_registries.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package sysregistries
-
-import (
- "strings"
-
- "github.com/BurntSushi/toml"
- "github.com/containers/image/types"
- "io/ioutil"
- "path/filepath"
-)
-
-// systemRegistriesConfPath is the path to the system-wide registry configuration file
-// and is used to add/subtract potential registries for obtaining images.
-// You can override this at build time with
-// -ldflags '-X github.com/containers/image/sysregistries.systemRegistriesConfPath=$your_path'
-var systemRegistriesConfPath = builtinRegistriesConfPath
-
-// builtinRegistriesConfPath is the path to registry configuration file
-// DO NOT change this, instead see systemRegistriesConfPath above.
-const builtinRegistriesConfPath = "/etc/containers/registries.conf"
-
-type registries struct {
- Registries []string `toml:"registries"`
-}
-
-type tomlConfig struct {
- Registries struct {
- Search registries `toml:"search"`
- Insecure registries `toml:"insecure"`
- Block registries `toml:"block"`
- } `toml:"registries"`
-}
-
-// normalizeRegistries removes trailing slashes from registries, which is a
-// common pitfall when configuring registries (e.g., "docker.io/library/).
-func normalizeRegistries(regs *registries) {
- for i := range regs.Registries {
- regs.Registries[i] = strings.TrimRight(regs.Registries[i], "/")
- }
-}
-
-// Reads the global registry file from the filesystem. Returns
-// a byte array
-func readRegistryConf(sys *types.SystemContext) ([]byte, error) {
- return ioutil.ReadFile(RegistriesConfPath(sys))
-}
-
-// For mocking in unittests
-var readConf = readRegistryConf
-
-// Loads the registry configuration file from the filesystem and
-// then unmarshals it. Returns the unmarshalled object.
-func loadRegistryConf(sys *types.SystemContext) (*tomlConfig, error) {
- config := &tomlConfig{}
-
- configBytes, err := readConf(sys)
- if err != nil {
- return nil, err
- }
-
- err = toml.Unmarshal(configBytes, &config)
- normalizeRegistries(&config.Registries.Search)
- normalizeRegistries(&config.Registries.Insecure)
- normalizeRegistries(&config.Registries.Block)
- return config, err
-}
-
-// GetRegistries returns an array of strings that contain the names
-// of the registries as defined in the system-wide
-// registries file. it returns an empty array if none are
-// defined
-func GetRegistries(sys *types.SystemContext) ([]string, error) {
- config, err := loadRegistryConf(sys)
- if err != nil {
- return nil, err
- }
- return config.Registries.Search.Registries, nil
-}
-
-// GetInsecureRegistries returns an array of strings that contain the names
-// of the insecure registries as defined in the system-wide
-// registries file. it returns an empty array if none are
-// defined
-func GetInsecureRegistries(sys *types.SystemContext) ([]string, error) {
- config, err := loadRegistryConf(sys)
- if err != nil {
- return nil, err
- }
- return config.Registries.Insecure.Registries, nil
-}
-
-// RegistriesConfPath is the path to the system-wide registry configuration file
-func RegistriesConfPath(ctx *types.SystemContext) string {
- path := systemRegistriesConfPath
- if ctx != nil {
- if ctx.SystemRegistriesConfPath != "" {
- path = ctx.SystemRegistriesConfPath
- } else if ctx.RootForImplicitAbsolutePaths != "" {
- path = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfPath)
- }
- }
- return path
-}
diff --git a/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go b/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
index 0c13913ed..bed92cb90 100644
--- a/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
+++ b/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
@@ -303,9 +303,8 @@ func (config *V2RegistriesConf) postProcess() error {
return nil
}
-// getConfigPath returns the system-registries config path if specified.
-// Otherwise, systemRegistriesConfPath is returned.
-func getConfigPath(ctx *types.SystemContext) string {
+// ConfigPath returns the path to the system-wide registry configuration file.
+func ConfigPath(ctx *types.SystemContext) string {
confPath := systemRegistriesConfPath
if ctx != nil {
if ctx.SystemRegistriesConfPath != "" {
@@ -336,14 +335,27 @@ func InvalidateCache() {
// getConfig returns the config object corresponding to ctx, loading it if it is not yet cached.
func getConfig(ctx *types.SystemContext) (*V2RegistriesConf, error) {
- configPath := getConfigPath(ctx)
+ configPath := ConfigPath(ctx)
configMutex.Lock()
- defer configMutex.Unlock()
// if the config has already been loaded, return the cached registries
if config, inCache := configCache[configPath]; inCache {
+ configMutex.Unlock()
return config, nil
}
+ configMutex.Unlock()
+
+ return TryUpdatingCache(ctx)
+}
+
+// TryUpdatingCache loads the configuration from the provided `SystemContext`
+// without using the internal cache. On success, the loaded configuration will
+// be added into the internal registry cache.
+func TryUpdatingCache(ctx *types.SystemContext) (*V2RegistriesConf, error) {
+ configPath := ConfigPath(ctx)
+
+ configMutex.Lock()
+ defer configMutex.Unlock()
// load the config
config, err := loadRegistryConf(configPath)
diff --git a/vendor/github.com/containers/image/signature/policy_types.go b/vendor/github.com/containers/image/signature/policy_types.go
index 4cd770f11..d3b33bb7a 100644
--- a/vendor/github.com/containers/image/signature/policy_types.go
+++ b/vendor/github.com/containers/image/signature/policy_types.go
@@ -6,7 +6,7 @@
package signature
-// NOTE: Keep this in sync with docs/policy.json.md!
+// NOTE: Keep this in sync with docs/containers-policy.json.5.md!
// Policy defines requirements for considering a signature, or an image, valid.
type Policy struct {
diff --git a/vendor/github.com/containers/image/transports/alltransports/alltransports.go b/vendor/github.com/containers/image/transports/alltransports/alltransports.go
index 2335c567f..3a988f3f8 100644
--- a/vendor/github.com/containers/image/transports/alltransports/alltransports.go
+++ b/vendor/github.com/containers/image/transports/alltransports/alltransports.go
@@ -4,7 +4,7 @@ import (
"strings"
// register all known transports
- // NOTE: Make sure docs/policy.json.md is updated when adding or updating
+ // NOTE: Make sure docs/containers-policy.json.5.md is updated when adding or updating
// a transport.
_ "github.com/containers/image/directory"
_ "github.com/containers/image/docker"
diff --git a/vendor/github.com/containers/image/version/version.go b/vendor/github.com/containers/image/version/version.go
index 807daf7a2..f1e795d9b 100644
--- a/vendor/github.com/containers/image/version/version.go
+++ b/vendor/github.com/containers/image/version/version.go
@@ -4,11 +4,11 @@ import "fmt"
const (
// VersionMajor is for an API incompatible changes
- VersionMajor = 2
+ VersionMajor = 3
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 0
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 1
+ VersionPatch = 2
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""
diff --git a/vendor/github.com/containers/storage/Makefile b/vendor/github.com/containers/storage/Makefile
index de326aeb1..bb1de007b 100644
--- a/vendor/github.com/containers/storage/Makefile
+++ b/vendor/github.com/containers/storage/Makefile
@@ -27,10 +27,16 @@ PACKAGE := github.com/containers/storage
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
EPOCH_TEST_COMMIT := 0418ebf59f9e1f564831c0ba9378b7f8e40a1c73
-NATIVETAGS := exclude_graphdriver_devicemapper exclude_graphdriver_btrfs exclude_graphdriver_overlay
+NATIVETAGS :=
AUTOTAGS := $(shell ./hack/btrfs_tag.sh) $(shell ./hack/libdm_tag.sh) $(shell ./hack/ostree_tag.sh)
BUILDFLAGS := -tags "$(AUTOTAGS) $(TAGS)" $(FLAGS)
-GO := go
+GO ?= go
+
+GO_BUILD=$(GO) build
+# Go module support: set `-mod=vendor` to use the vendored sources
+ifeq ($(shell $(GO) help mod >/dev/null 2>&1 && echo true), true)
+ GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
+endif
RUNINVM := vagrant/runinvm.sh
FFJSON := tests/tools/build/ffjson
@@ -43,7 +49,7 @@ clean: ## remove all built files
sources := $(wildcard *.go cmd/containers-storage/*.go drivers/*.go drivers/*/*.go pkg/*/*.go pkg/*/*/*.go) layers_ffjson.go images_ffjson.go containers_ffjson.go pkg/archive/archive_ffjson.go
containers-storage: $(sources) ## build using gc on the host
- $(GO) build -compiler gc $(BUILDFLAGS) ./cmd/containers-storage
+ $(GO_BUILD) -compiler gc $(BUILDFLAGS) ./cmd/containers-storage
layers_ffjson.go: layers.go
$(RM) $@
@@ -64,15 +70,15 @@ pkg/archive/archive_ffjson.go: pkg/archive/archive.go
binary local-binary: containers-storage
local-gccgo: ## build using gccgo on the host
- GCCGO=$(PWD)/hack/gccgo-wrapper.sh $(GO) build -compiler gccgo $(BUILDFLAGS) -o containers-storage.gccgo ./cmd/containers-storage
+ GCCGO=$(PWD)/hack/gccgo-wrapper.sh $(GO_BUILD) -compiler gccgo $(BUILDFLAGS) -o containers-storage.gccgo ./cmd/containers-storage
local-cross: ## cross build the binaries for arm, darwin, and\nfreebsd
@for target in linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64 linux/ppc64le darwin/amd64 windows/amd64 ; do \
os=`echo $${target} | cut -f1 -d/` ; \
arch=`echo $${target} | cut -f2 -d/` ; \
suffix=$${os}.$${arch} ; \
- echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage ; \
- env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage || exit 1 ; \
+ echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO_BUILD) -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage ; \
+ env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO_BUILD) -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage || exit 1 ; \
done
cross: ## cross build the binaries for arm, darwin, and\nfreebsd using VMs
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index c22268b43..065f9ec4c 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.12.16
+1.13.3-dev
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
index 6f632a98d..1f719fa85 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package btrfs
@@ -645,7 +645,15 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
if err != nil {
return "", err
}
- if len(options.Options) > 0 {
+ switch len(options.Options) {
+ case 0:
+ case 1:
+ if options.Options[0] == "ro" {
+ // ignore "ro" option
+ break
+ }
+ fallthrough
+ default:
return "", fmt.Errorf("btrfs driver does not support mount options")
}
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/version.go b/vendor/github.com/containers/storage/drivers/btrfs/version.go
index 73d90cdd7..edd8bdab8 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/version.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/version.go
@@ -1,4 +1,4 @@
-// +build linux,!btrfs_noversion
+// +build linux,!btrfs_noversion,cgo
package btrfs
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/version_none.go b/vendor/github.com/containers/storage/drivers/btrfs/version_none.go
index f802fbc62..905e834e3 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/version_none.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/version_none.go
@@ -1,4 +1,4 @@
-// +build linux,btrfs_noversion
+// +build !linux btrfs_noversion !cgo
package btrfs
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go b/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
index f63845252..7553a93eb 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
@@ -1,3 +1,5 @@
+// +build linux,cgo
+
package devmapper
import (
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
index b6f22e90a..1ea6cfc36 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package devmapper
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/devmapper_doc.go b/vendor/github.com/containers/storage/drivers/devmapper/devmapper_doc.go
index 9ab3e4f86..418b9e610 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/devmapper_doc.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/devmapper_doc.go
@@ -1,3 +1,5 @@
+// +build linux,cgo
+
package devmapper
// Definition of struct dm_task and sub structures (from lvm2)
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/driver.go b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
index f384a6242..3c044c12e 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/driver.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package devmapper
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/mount.go b/vendor/github.com/containers/storage/drivers/devmapper/mount.go
index 1dc3262d2..41e73faf5 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/mount.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/mount.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package devmapper
diff --git a/vendor/github.com/containers/storage/drivers/fsdiff.go b/vendor/github.com/containers/storage/drivers/fsdiff.go
index d34fdee3b..93743d177 100644
--- a/vendor/github.com/containers/storage/drivers/fsdiff.go
+++ b/vendor/github.com/containers/storage/drivers/fsdiff.go
@@ -82,6 +82,7 @@ func (gdw *NaiveDiffDriver) Diff(id string, idMappings *idtools.IDMappings, pare
}), nil
}
+ options.Options = append(options.Options, "ro")
parentFs, err := driver.Get(parent, options)
if err != nil {
return nil, err
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index d70487ea7..032e5b28a 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -322,7 +322,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
return nil, fmt.Errorf("overlay: ostree_repo specified but support for ostree is missing")
}
o.ostreeRepo = val
- case "overlay2.ignore_chown_errors", "overlay.ignore_chown_errors":
+ case ".ignore_chown_errors", "overlay2.ignore_chown_errors", "overlay.ignore_chown_errors":
logrus.Debugf("overlay: ignore_chown_errors=%s", val)
o.ignoreChownErrors, err = strconv.ParseBool(val)
if err != nil {
@@ -839,8 +839,17 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
if _, err := os.Stat(dir); err != nil {
return "", err
}
+ readWrite := true
+ // fuse-overlayfs doesn't support working without an upperdir.
+ if d.options.mountProgram == "" {
+ for _, o := range options.Options {
+ if o == "ro" {
+ readWrite = false
+ break
+ }
+ }
+ }
- diffDir := path.Join(dir, "diff")
lowers, err := ioutil.ReadFile(path.Join(dir, lowerFile))
if err != nil && !os.IsNotExist(err) {
return "", err
@@ -911,16 +920,32 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
// If the lowers list is still empty, use an empty lower so that we can still force an
// SELinux context for the mount.
+
+ // if we are doing a readOnly mount, and there is only one lower
+ // We should just return the lower directory, no reason to mount.
+ if !readWrite {
+ if len(absLowers) == 0 {
+ return path.Join(dir, "empty"), nil
+ }
+ if len(absLowers) == 1 {
+ return absLowers[0], nil
+ }
+ }
if len(absLowers) == 0 {
absLowers = append(absLowers, path.Join(dir, "empty"))
relLowers = append(relLowers, path.Join(id, "empty"))
}
-
// user namespace requires this to move a directory from lower to upper.
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return "", err
}
+ diffDir := path.Join(dir, "diff")
+ if readWrite {
+ if err := idtools.MkdirAllAs(diffDir, 0755, rootUID, rootGID); err != nil && !os.IsExist(err) {
+ return "", err
+ }
+ }
mergedDir := path.Join(dir, "merged")
// Create the driver merged dir
@@ -940,8 +965,12 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
}
}()
- workDir := path.Join(dir, "work")
- opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), diffDir, workDir)
+ var opts string
+ if readWrite {
+ opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), diffDir, path.Join(dir, "work"))
+ } else {
+ opts = fmt.Sprintf("lowerdir=%s", strings.Join(absLowers, ":"))
+ }
if len(options.Options) > 0 {
opts = fmt.Sprintf("%s,%s", strings.Join(options.Options, ","), opts)
} else if d.options.mountOptions != "" {
@@ -979,7 +1008,12 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
}
} else if len(mountData) > pageSize {
//FIXME: We need to figure out to get this to work with additional stores
- opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(relLowers, ":"), path.Join(id, "diff"), path.Join(id, "work"))
+ if readWrite {
+ diffDir := path.Join(id, "diff")
+ opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(relLowers, ":"), diffDir, path.Join(id, "work"))
+ } else {
+ opts = fmt.Sprintf("lowerdir=%s", strings.Join(absLowers, ":"))
+ }
mountData = label.FormatMountLabel(opts, options.MountLabel)
if len(mountData) > pageSize {
return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
@@ -995,11 +1029,6 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
return "", fmt.Errorf("error creating overlay mount to %s: %v", mountTarget, err)
}
- // chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
- if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil {
- return "", err
- }
-
return mergedDir, nil
}
@@ -1018,7 +1047,7 @@ func (d *Driver) Put(id string) error {
if _, err := ioutil.ReadFile(path.Join(dir, lowerFile)); err != nil && !os.IsNotExist(err) {
return err
}
- if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil {
+ if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil && !os.IsNotExist(err) {
logrus.Debugf("Failed to unmount %s overlay: %s - %v", id, mountpoint, err)
}
diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota.go b/vendor/github.com/containers/storage/drivers/quota/projectquota.go
index 6ef35d8ad..d5aa0f891 100644
--- a/vendor/github.com/containers/storage/drivers/quota/projectquota.go
+++ b/vendor/github.com/containers/storage/drivers/quota/projectquota.go
@@ -1,4 +1,4 @@
-// +build linux,!exclude_disk_quota
+// +build linux,!exclude_disk_quota,cgo
//
// projectquota.go - implements XFS project quota controls
diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go b/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
index b6db1e1d8..be6c75a58 100644
--- a/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
+++ b/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
@@ -1,4 +1,4 @@
-// +build linux,exclude_disk_quota
+// +build !linux exclude_disk_quota !cgo
package quota
diff --git a/vendor/github.com/containers/storage/drivers/register/register_devicemapper.go b/vendor/github.com/containers/storage/drivers/register/register_devicemapper.go
index 08ac984b0..cefe2e8c7 100644
--- a/vendor/github.com/containers/storage/drivers/register/register_devicemapper.go
+++ b/vendor/github.com/containers/storage/drivers/register/register_devicemapper.go
@@ -1,4 +1,4 @@
-// +build !exclude_graphdriver_devicemapper,linux
+// +build !exclude_graphdriver_devicemapper,linux,cgo
package register
diff --git a/vendor/github.com/containers/storage/drivers/register/register_overlay.go b/vendor/github.com/containers/storage/drivers/register/register_overlay.go
index 2d61219bb..30e3b4d74 100644
--- a/vendor/github.com/containers/storage/drivers/register/register_overlay.go
+++ b/vendor/github.com/containers/storage/drivers/register/register_overlay.go
@@ -1,4 +1,4 @@
-// +build !exclude_graphdriver_overlay,linux
+// +build !exclude_graphdriver_overlay,linux,cgo
package register
diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go
index fe02a711e..6c02a45dc 100644
--- a/vendor/github.com/containers/storage/drivers/vfs/driver.go
+++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go
@@ -58,7 +58,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
d.ostreeRepo = val
case "vfs.mountopt":
return nil, fmt.Errorf("vfs driver does not support mount options")
- case "vfs.ignore_chown_errors":
+ case ".ignore_chown_errors", "vfs.ignore_chown_errors":
logrus.Debugf("vfs: ignore_chown_errors=%s", val)
var err error
d.ignoreChownErrors, err = strconv.ParseBool(val)
@@ -226,7 +226,15 @@ func (d *Driver) Remove(id string) error {
// Get returns the directory for the given id.
func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) {
dir := d.dir(id)
- if len(options.Options) > 0 {
+ switch len(options.Options) {
+ case 0:
+ case 1:
+ if options.Options[0] == "ro" {
+ // ignore "ro" option
+ break
+ }
+ fallthrough
+ default:
return "", fmt.Errorf("vfs driver does not support mount options")
}
if st, err := os.Stat(dir); err != nil {
diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go
index 11f1c98b1..c1ab93e1d 100644
--- a/vendor/github.com/containers/storage/drivers/windows/windows.go
+++ b/vendor/github.com/containers/storage/drivers/windows/windows.go
@@ -372,7 +372,15 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, options.MountLabel)
var dir string
- if len(options.Options) > 0 {
+ switch len(options.Options) {
+ case 0:
+ case 1:
+ if options.Options[0] == "ro" {
+ // ignore "ro" option
+ break
+ }
+ fallthrough
+ default:
return "", fmt.Errorf("windows driver does not support mount options")
}
rID, err := d.resolveID(id)
diff --git a/vendor/github.com/containers/storage/ffjson_deps.go b/vendor/github.com/containers/storage/ffjson_deps.go
new file mode 100644
index 000000000..33e5340a5
--- /dev/null
+++ b/vendor/github.com/containers/storage/ffjson_deps.go
@@ -0,0 +1,10 @@
+package storage
+
+// NOTE: this is a hack to trick go modules into vendoring the below
+// dependencies. Those are required during ffjson generation
+// but do NOT end up in the final file.
+
+import (
+ _ "github.com/pquerna/ffjson/inception" // nolint:typecheck
+ _ "github.com/pquerna/ffjson/shared" // nolint:typecheck
+)
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index fed53569d..d8f943d30 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -1,7 +1,5 @@
module github.com/containers/storage
-go 1.12
-
require (
github.com/BurntSushi/toml v0.3.1
github.com/DataDog/zstd v1.4.0 // indirect
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index 4ef567210..d746ba061 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -1,7 +1,6 @@
package storage
import (
- "archive/tar"
"bytes"
"encoding/json"
"fmt"
@@ -27,6 +26,7 @@ import (
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
+ "github.com/vbatts/tar-split/archive/tar"
"github.com/vbatts/tar-split/tar/asm"
"github.com/vbatts/tar-split/tar/storage"
)
diff --git a/vendor/github.com/containers/storage/pkg/idtools/idtools.go b/vendor/github.com/containers/storage/pkg/idtools/idtools.go
index a5c73d311..5105720ba 100644
--- a/vendor/github.com/containers/storage/pkg/idtools/idtools.go
+++ b/vendor/github.com/containers/storage/pkg/idtools/idtools.go
@@ -10,6 +10,7 @@ import (
"strings"
"syscall"
+ "github.com/containers/storage/pkg/system"
"github.com/pkg/errors"
)
@@ -296,9 +297,19 @@ func checkChownErr(err error, name string, uid, gid int) error {
}
func SafeChown(name string, uid, gid int) error {
+ if stat, statErr := system.Stat(name); statErr == nil {
+ if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) {
+ return nil
+ }
+ }
return checkChownErr(os.Chown(name, uid, gid), name, uid, gid)
}
func SafeLchown(name string, uid, gid int) error {
+ if stat, statErr := system.Lstat(name); statErr == nil {
+ if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) {
+ return nil
+ }
+ }
return checkChownErr(os.Lchown(name, uid, gid), name, uid, gid)
}
diff --git a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
index 34c80548d..be8680fbc 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package loopback
diff --git a/vendor/github.com/containers/storage/pkg/loopback/ioctl.go b/vendor/github.com/containers/storage/pkg/loopback/ioctl.go
index 0714eb5f8..ea6841958 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/ioctl.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/ioctl.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package loopback
diff --git a/vendor/github.com/containers/storage/pkg/loopback/loop_wrapper.go b/vendor/github.com/containers/storage/pkg/loopback/loop_wrapper.go
index e1100ce15..a50de7f07 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/loop_wrapper.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/loop_wrapper.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package loopback
diff --git a/vendor/github.com/containers/storage/pkg/loopback/loopback.go b/vendor/github.com/containers/storage/pkg/loopback/loopback.go
index a8ec3c616..05d537dc8 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/loopback.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/loopback.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,cgo
package loopback
diff --git a/vendor/github.com/containers/storage/pkg/loopback/loopback_unsupported.go b/vendor/github.com/containers/storage/pkg/loopback/loopback_unsupported.go
new file mode 100644
index 000000000..460b30709
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/loopback/loopback_unsupported.go
@@ -0,0 +1 @@
+package loopback
diff --git a/vendor/github.com/containers/storage/pkg/ostree/no_ostree.go b/vendor/github.com/containers/storage/pkg/ostree/no_ostree.go
index 0a8e7d679..bf83ccf25 100644
--- a/vendor/github.com/containers/storage/pkg/ostree/no_ostree.go
+++ b/vendor/github.com/containers/storage/pkg/ostree/no_ostree.go
@@ -1,4 +1,4 @@
-// +build !ostree
+// +build !ostree !cgo
package ostree
diff --git a/vendor/github.com/containers/storage/pkg/ostree/ostree.go b/vendor/github.com/containers/storage/pkg/ostree/ostree.go
index e9b57a0fb..7d324f2b2 100644
--- a/vendor/github.com/containers/storage/pkg/ostree/ostree.go
+++ b/vendor/github.com/containers/storage/pkg/ostree/ostree.go
@@ -1,4 +1,4 @@
-// +build ostree
+// +build ostree,cgo
package ostree
diff --git a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
index 8451de01e..98d3ee96a 100644
--- a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
+++ b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
@@ -1,47 +1,69 @@
package tarlog
import (
- "archive/tar"
"io"
- "os"
"sync"
- "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/vbatts/tar-split/archive/tar"
)
type tarLogger struct {
- writer *os.File
- wg sync.WaitGroup
+ writer *io.PipeWriter
+ closeMutex *sync.Mutex
+ stateMutex *sync.Mutex
+ closed bool
}
// NewLogger returns a writer that, when a tar archive is written to it, calls
// `logger` for each file header it encounters in the archive.
func NewLogger(logger func(*tar.Header)) (io.WriteCloser, error) {
- reader, writer, err := os.Pipe()
- if err != nil {
- return nil, errors.Wrapf(err, "error creating pipe for tar logger")
+ reader, writer := io.Pipe()
+ t := &tarLogger{
+ writer: writer,
+ closeMutex: new(sync.Mutex),
+ stateMutex: new(sync.Mutex),
+ closed: false,
}
- t := &tarLogger{writer: writer}
tr := tar.NewReader(reader)
- t.wg.Add(1)
+ tr.RawAccounting = true
+ t.closeMutex.Lock()
go func() {
hdr, err := tr.Next()
for err == nil {
logger(hdr)
hdr, err = tr.Next()
+
+ }
+ // Make sure to avoid writes after the reader has been closed.
+ t.stateMutex.Lock()
+ t.closed = true
+ if err := reader.Close(); err != nil {
+ logrus.Errorf("error closing tarlogger reader: %v", err)
}
- reader.Close()
- t.wg.Done()
+ t.stateMutex.Unlock()
+ // Unblock the Close().
+ t.closeMutex.Unlock()
}()
return t, nil
}
func (t *tarLogger) Write(b []byte) (int, error) {
+ t.stateMutex.Lock()
+ if t.closed {
+ // We cannot use os.Pipe() as this alters the tar's digest. Using
+ // io.Pipe() requires this workaround as it does not allow for writes
+ // after close.
+ t.stateMutex.Unlock()
+ return len(b), nil
+ }
+ t.stateMutex.Unlock()
return t.writer.Write(b)
}
func (t *tarLogger) Close() error {
err := t.writer.Close()
- t.wg.Wait()
+ // Wait for the reader to finish.
+ t.closeMutex.Lock()
return err
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
index 1eb9a6bf2..2730fcf4a 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
@@ -13,11 +13,12 @@ import (
// Valid Label Options
var validOptions = map[string]bool{
- "disable": true,
- "type": true,
- "user": true,
- "role": true,
- "level": true,
+ "disable": true,
+ "type": true,
+ "filetype": true,
+ "user": true,
+ "role": true,
+ "level": true,
}
var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together")
@@ -51,13 +52,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
return "", mountLabel, nil
}
if i := strings.Index(opt, ":"); i == -1 {
- return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
+ return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
}
con := strings.SplitN(opt, ":", 2)
if !validOptions[con[0]] {
- return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0])
+ return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
}
+ if con[0] == "filetype" {
+ mcon["type"] = con[1]
+ }
pcon[con[0]] = con[1]
if con[0] == "level" || con[0] == "user" {
mcon[con[0]] = con[1]
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index d7786c33c..2d4e9f890 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -18,6 +18,7 @@ import (
"strings"
"sync"
"syscall"
+ "golang.org/x/sys/unix"
)
const (
@@ -392,6 +393,14 @@ func SetExecLabel(label string) error {
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label)
}
+/*
+SetTaskLabel sets the SELinux label for the current thread, or an error.
+This requires the dyntransition permission.
+*/
+func SetTaskLabel(label string) error {
+ return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()), label)
+}
+
// SetSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
func SetSocketLabel(label string) error {
@@ -403,6 +412,11 @@ func SocketLabel() (string, error) {
return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()))
}
+// PeerLabel retrieves the label of the client on the other side of a socket
+func PeerLabel(fd uintptr) (string, error) {
+ return unix.GetsockoptString(int(fd), syscall.SOL_SOCKET, syscall.SO_PEERSEC)
+}
+
// SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
func SetKeyLabel(label string) error {
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
index 79b005d19..0c2e1cd38 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
@@ -97,6 +97,14 @@ func SetExecLabel(label string) error {
}
/*
+SetTaskLabel sets the SELinux label for the current thread, or an error.
+This requires the dyntransition permission.
+*/
+func SetTaskLabel(label string) error {
+ return nil
+}
+
+/*
SetSocketLabel sets the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error.
*/
@@ -109,6 +117,11 @@ func SocketLabel() (string, error) {
return "", nil
}
+// PeerLabel retrieves the label of the client on the other side of a socket
+func PeerLabel(fd uintptr) (string, error) {
+ return "", nil
+}
+
// SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
func SetKeyLabel(label string) error {
diff --git a/vendor/github.com/pquerna/ffjson/inception/decoder.go b/vendor/github.com/pquerna/ffjson/inception/decoder.go
new file mode 100644
index 000000000..908347a32
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/decoder.go
@@ -0,0 +1,323 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/pquerna/ffjson/shared"
+)
+
+var validValues []string = []string{
+ "FFTok_left_brace",
+ "FFTok_left_bracket",
+ "FFTok_integer",
+ "FFTok_double",
+ "FFTok_string",
+ "FFTok_bool",
+ "FFTok_null",
+}
+
+func CreateUnmarshalJSON(ic *Inception, si *StructInfo) error {
+ out := ""
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ if len(si.Fields) > 0 {
+ ic.OutputImports[`"bytes"`] = true
+ }
+ ic.OutputImports[`"fmt"`] = true
+
+ out += tplStr(decodeTpl["header"], header{
+ IC: ic,
+ SI: si,
+ })
+
+ out += tplStr(decodeTpl["ujFunc"], ujFunc{
+ SI: si,
+ IC: ic,
+ ValidValues: validValues,
+ ResetFields: ic.ResetFields,
+ })
+
+ ic.OutputFuncs = append(ic.OutputFuncs, out)
+
+ return nil
+}
+
+func handleField(ic *Inception, name string, typ reflect.Type, ptr bool, quoted bool) string {
+ return handleFieldAddr(ic, name, false, typ, ptr, quoted)
+}
+
+func handleFieldAddr(ic *Inception, name string, takeAddr bool, typ reflect.Type, ptr bool, quoted bool) string {
+ out := fmt.Sprintf("/* handler: %s type=%v kind=%v quoted=%t*/\n", name, typ, typ.Kind(), quoted)
+
+ umlx := typ.Implements(unmarshalFasterType) || typeInInception(ic, typ, shared.MustDecoder)
+ umlx = umlx || reflect.PtrTo(typ).Implements(unmarshalFasterType)
+
+ umlstd := typ.Implements(unmarshalerType) || reflect.PtrTo(typ).Implements(unmarshalerType)
+
+ out += tplStr(decodeTpl["handleUnmarshaler"], handleUnmarshaler{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ Ptr: reflect.Ptr,
+ TakeAddr: takeAddr || ptr,
+ UnmarshalJSONFFLexer: umlx,
+ Unmarshaler: umlstd,
+ })
+
+ if umlx || umlstd {
+ return out
+ }
+
+ // TODO(pquerna): generic handling of token type mismatching struct type
+ switch typ.Kind() {
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64:
+
+ allowed := buildTokens(quoted, "FFTok_string", "FFTok_integer", "FFTok_null")
+ out += getAllowTokens(typ.Name(), allowed...)
+
+ out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseInt")
+
+ case reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64:
+
+ allowed := buildTokens(quoted, "FFTok_string", "FFTok_integer", "FFTok_null")
+ out += getAllowTokens(typ.Name(), allowed...)
+
+ out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseUint")
+
+ case reflect.Float32,
+ reflect.Float64:
+
+ allowed := buildTokens(quoted, "FFTok_string", "FFTok_double", "FFTok_integer", "FFTok_null")
+ out += getAllowTokens(typ.Name(), allowed...)
+
+ out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseFloat")
+
+ case reflect.Bool:
+ ic.OutputImports[`"bytes"`] = true
+ ic.OutputImports[`"errors"`] = true
+
+ allowed := buildTokens(quoted, "FFTok_string", "FFTok_bool", "FFTok_null")
+ out += getAllowTokens(typ.Name(), allowed...)
+
+ out += tplStr(decodeTpl["handleBool"], handleBool{
+ Name: name,
+ Typ: typ,
+ TakeAddr: takeAddr || ptr,
+ })
+
+ case reflect.Ptr:
+ out += tplStr(decodeTpl["handlePtr"], handlePtr{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ Quoted: quoted,
+ })
+
+ case reflect.Array,
+ reflect.Slice:
+ out += getArrayHandler(ic, name, typ, ptr)
+
+ case reflect.String:
+ // Is it a json.Number?
+ if typ.PkgPath() == "encoding/json" && typ.Name() == "Number" {
+ // Fall back to json package to rely on the valid number check.
+ // See: https://github.com/golang/go/blob/f05c3aa24d815cd3869153750c9875e35fc48a6e/src/encoding/json/decode.go#L897
+ ic.OutputImports[`"encoding/json"`] = true
+ out += tplStr(decodeTpl["handleFallback"], handleFallback{
+ Name: name,
+ Typ: typ,
+ Kind: typ.Kind(),
+ })
+ } else {
+ out += tplStr(decodeTpl["handleString"], handleString{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ TakeAddr: takeAddr || ptr,
+ Quoted: quoted,
+ })
+ }
+ case reflect.Interface:
+ ic.OutputImports[`"encoding/json"`] = true
+ out += tplStr(decodeTpl["handleFallback"], handleFallback{
+ Name: name,
+ Typ: typ,
+ Kind: typ.Kind(),
+ })
+ case reflect.Map:
+ out += tplStr(decodeTpl["handleObject"], handleObject{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ Ptr: reflect.Ptr,
+ TakeAddr: takeAddr || ptr,
+ })
+ default:
+ ic.OutputImports[`"encoding/json"`] = true
+ out += tplStr(decodeTpl["handleFallback"], handleFallback{
+ Name: name,
+ Typ: typ,
+ Kind: typ.Kind(),
+ })
+ }
+
+ return out
+}
+
+func getArrayHandler(ic *Inception, name string, typ reflect.Type, ptr bool) string {
+ if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
+ ic.OutputImports[`"encoding/base64"`] = true
+ useReflectToSet := false
+ if typ.Elem().Name() != "byte" {
+ ic.OutputImports[`"reflect"`] = true
+ useReflectToSet = true
+ }
+
+ return tplStr(decodeTpl["handleByteSlice"], handleArray{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ Ptr: reflect.Ptr,
+ UseReflectToSet: useReflectToSet,
+ })
+ }
+
+ if typ.Elem().Kind() == reflect.Struct && typ.Elem().Name() != "" {
+ goto sliceOrArray
+ }
+
+ if (typ.Elem().Kind() == reflect.Struct || typ.Elem().Kind() == reflect.Map) ||
+ typ.Elem().Kind() == reflect.Array || typ.Elem().Kind() == reflect.Slice &&
+ typ.Elem().Name() == "" {
+ ic.OutputImports[`"encoding/json"`] = true
+
+ return tplStr(decodeTpl["handleFallback"], handleFallback{
+ Name: name,
+ Typ: typ,
+ Kind: typ.Kind(),
+ })
+ }
+
+sliceOrArray:
+
+ if typ.Kind() == reflect.Array {
+ return tplStr(decodeTpl["handleArray"], handleArray{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ IsPtr: ptr,
+ Ptr: reflect.Ptr,
+ })
+ }
+
+ return tplStr(decodeTpl["handleSlice"], handleArray{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ IsPtr: ptr,
+ Ptr: reflect.Ptr,
+ })
+}
+
+func getAllowTokens(name string, tokens ...string) string {
+ return tplStr(decodeTpl["allowTokens"], allowTokens{
+ Name: name,
+ Tokens: tokens,
+ })
+}
+
+func getNumberHandler(ic *Inception, name string, takeAddr bool, typ reflect.Type, parsefunc string) string {
+ return tplStr(decodeTpl["handlerNumeric"], handlerNumeric{
+ IC: ic,
+ Name: name,
+ ParseFunc: parsefunc,
+ TakeAddr: takeAddr,
+ Typ: typ,
+ })
+}
+
+func getNumberSize(typ reflect.Type) string {
+ return fmt.Sprintf("%d", typ.Bits())
+}
+
+func getType(ic *Inception, name string, typ reflect.Type) string {
+ s := typ.Name()
+
+ if typ.PkgPath() != "" && typ.PkgPath() != ic.PackagePath {
+ path := removeVendor(typ.PkgPath())
+ ic.OutputImports[`"`+path+`"`] = true
+ s = typ.String()
+ }
+
+ if s == "" {
+ return typ.String()
+ }
+
+ return s
+}
+
+// removeVendor removes everything before and including a '/vendor/'
+// substring in the package path.
+// This is needed becuase that full path can't be used in the
+// import statement.
+func removeVendor(path string) string {
+ i := strings.Index(path, "/vendor/")
+ if i == -1 {
+ return path
+ }
+ return path[i+8:]
+}
+
+func buildTokens(containsOptional bool, optional string, required ...string) []string {
+ if containsOptional {
+ return append(required, optional)
+ }
+
+ return required
+}
+
+func unquoteField(quoted bool) string {
+ // The outer quote of a string is already stripped out by
+ // the lexer. We need to check if the inner string is also
+ // quoted. If so, we will decode it as json string. If decoding
+ // fails, we will use the original string
+ if quoted {
+ return `
+ unquoted, ok := fflib.UnquoteBytes(outBuf)
+ if ok {
+ outBuf = unquoted
+ }
+ `
+ }
+ return ""
+}
+
+func getTmpVarFor(name string) string {
+ return "tmp" + strings.Replace(strings.Title(name), ".", "", -1)
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/decoder_tpl.go b/vendor/github.com/pquerna/ffjson/inception/decoder_tpl.go
new file mode 100644
index 000000000..098506122
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/decoder_tpl.go
@@ -0,0 +1,773 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "reflect"
+ "strconv"
+ "text/template"
+)
+
+var decodeTpl map[string]*template.Template
+
+func init() {
+ decodeTpl = make(map[string]*template.Template)
+
+ funcs := map[string]string{
+ "handlerNumeric": handlerNumericTxt,
+ "allowTokens": allowTokensTxt,
+ "handleFallback": handleFallbackTxt,
+ "handleString": handleStringTxt,
+ "handleObject": handleObjectTxt,
+ "handleArray": handleArrayTxt,
+ "handleSlice": handleSliceTxt,
+ "handleByteSlice": handleByteSliceTxt,
+ "handleBool": handleBoolTxt,
+ "handlePtr": handlePtrTxt,
+ "header": headerTxt,
+ "ujFunc": ujFuncTxt,
+ "handleUnmarshaler": handleUnmarshalerTxt,
+ }
+
+ tplFuncs := template.FuncMap{
+ "getAllowTokens": getAllowTokens,
+ "getNumberSize": getNumberSize,
+ "getType": getType,
+ "handleField": handleField,
+ "handleFieldAddr": handleFieldAddr,
+ "unquoteField": unquoteField,
+ "getTmpVarFor": getTmpVarFor,
+ }
+
+ for k, v := range funcs {
+ decodeTpl[k] = template.Must(template.New(k).Funcs(tplFuncs).Parse(v))
+ }
+}
+
+type handlerNumeric struct {
+ IC *Inception
+ Name string
+ ParseFunc string
+ Typ reflect.Type
+ TakeAddr bool
+}
+
+var handlerNumericTxt = `
+{
+ {{$ic := .IC}}
+
+ if tok == fflib.FFTok_null {
+ {{if eq .TakeAddr true}}
+ {{.Name}} = nil
+ {{end}}
+ } else {
+ {{if eq .ParseFunc "ParseFloat" }}
+ tval, err := fflib.{{ .ParseFunc}}(fs.Output.Bytes(), {{getNumberSize .Typ}})
+ {{else}}
+ tval, err := fflib.{{ .ParseFunc}}(fs.Output.Bytes(), 10, {{getNumberSize .Typ}})
+ {{end}}
+
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ {{if eq .TakeAddr true}}
+ ttypval := {{getType $ic .Name .Typ}}(tval)
+ {{.Name}} = &ttypval
+ {{else}}
+ {{.Name}} = {{getType $ic .Name .Typ}}(tval)
+ {{end}}
+ }
+}
+`
+
+type allowTokens struct {
+ Name string
+ Tokens []string
+}
+
+var allowTokensTxt = `
+{
+ if {{range $index, $element := .Tokens}}{{if ne $index 0 }}&&{{end}} tok != fflib.{{$element}}{{end}} {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for {{.Name}}", tok))
+ }
+}
+`
+
+type handleFallback struct {
+ Name string
+ Typ reflect.Type
+ Kind reflect.Kind
+}
+
+var handleFallbackTxt = `
+{
+ /* Falling back. type={{printf "%v" .Typ}} kind={{printf "%v" .Kind}} */
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ err = json.Unmarshal(tbuf, &{{.Name}})
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+}
+`
+
+type handleString struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ TakeAddr bool
+ Quoted bool
+}
+
+var handleStringTxt = `
+{
+ {{$ic := .IC}}
+
+ {{getAllowTokens .Typ.Name "FFTok_string" "FFTok_null"}}
+ if tok == fflib.FFTok_null {
+ {{if eq .TakeAddr true}}
+ {{.Name}} = nil
+ {{end}}
+ } else {
+ {{if eq .TakeAddr true}}
+ var tval {{getType $ic .Name .Typ}}
+ outBuf := fs.Output.Bytes()
+ {{unquoteField .Quoted}}
+ tval = {{getType $ic .Name .Typ}}(string(outBuf))
+ {{.Name}} = &tval
+ {{else}}
+ outBuf := fs.Output.Bytes()
+ {{unquoteField .Quoted}}
+ {{.Name}} = {{getType $ic .Name .Typ}}(string(outBuf))
+ {{end}}
+ }
+}
+`
+
+type handleObject struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ Ptr reflect.Kind
+ TakeAddr bool
+}
+
+var handleObjectTxt = `
+{
+ {{$ic := .IC}}
+ {{getAllowTokens .Typ.Name "FFTok_left_bracket" "FFTok_null"}}
+ if tok == fflib.FFTok_null {
+ {{.Name}} = nil
+ } else {
+
+ {{if eq .TakeAddr true}}
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{if eq .Typ.Key.Kind .Ptr }}
+ var tval = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
+ {{else}}
+ var tval = make(map[{{getType $ic .Name .Typ.Key}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
+ {{end}}
+ {{else}}
+ {{if eq .Typ.Key.Kind .Ptr }}
+ var tval = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]{{getType $ic .Name .Typ.Elem}}, 0)
+ {{else}}
+ var tval = make(map[{{getType $ic .Name .Typ.Key}}]{{getType $ic .Name .Typ.Elem}}, 0)
+ {{end}}
+ {{end}}
+ {{else}}
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{if eq .Typ.Key.Kind .Ptr }}
+ {{.Name}} = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
+ {{else}}
+ {{.Name}} = make(map[{{getType $ic .Name .Typ.Key}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
+ {{end}}
+ {{else}}
+ {{if eq .Typ.Key.Kind .Ptr }}
+ {{.Name}} = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]{{getType $ic .Name .Typ.Elem}}, 0)
+ {{else}}
+ {{.Name}} = make(map[{{getType $ic .Name .Typ.Key}}]{{getType $ic .Name .Typ.Elem}}, 0)
+ {{end}}
+ {{end}}
+ {{end}}
+
+ wantVal := true
+
+ for {
+ {{$keyPtr := false}}
+ {{if eq .Typ.Key.Kind .Ptr }}
+ {{$keyPtr := true}}
+ var k *{{getType $ic .Name .Typ.Key.Elem}}
+ {{else}}
+ var k {{getType $ic .Name .Typ.Key}}
+ {{end}}
+
+ {{$valPtr := false}}
+ {{$tmpVar := getTmpVarFor .Name}}
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{$valPtr := true}}
+ var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
+ {{else}}
+ var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
+ {{end}}
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_bracket {
+ break
+ }
+
+ if tok == fflib.FFTok_comma {
+ if wantVal == true {
+ // TODO(pquerna): this isn't an ideal error message, this handles
+ // things like [,,,] as an array value.
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+ }
+ continue
+ } else {
+ wantVal = true
+ }
+
+ {{handleField .IC "k" .Typ.Key $keyPtr false}}
+
+ // Expect ':' after key
+ tok = fs.Scan()
+ if tok != fflib.FFTok_colon {
+ return fs.WrapErr(fmt.Errorf("wanted colon token, but got token: %v", tok))
+ }
+
+ tok = fs.Scan()
+ {{handleField .IC $tmpVar .Typ.Elem $valPtr false}}
+
+ {{if eq .TakeAddr true}}
+ tval[k] = {{$tmpVar}}
+ {{else}}
+ {{.Name}}[k] = {{$tmpVar}}
+ {{end}}
+ wantVal = false
+ }
+
+ {{if eq .TakeAddr true}}
+ {{.Name}} = &tval
+ {{end}}
+ }
+}
+`
+
+type handleArray struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ Ptr reflect.Kind
+ UseReflectToSet bool
+ IsPtr bool
+}
+
+var handleArrayTxt = `
+{
+ {{$ic := .IC}}
+ {{getAllowTokens .Typ.Name "FFTok_left_brace" "FFTok_null"}}
+ {{if eq .Typ.Elem.Kind .Ptr}}
+ {{.Name}} = [{{.Typ.Len}}]*{{getType $ic .Name .Typ.Elem.Elem}}{}
+ {{else}}
+ {{.Name}} = [{{.Typ.Len}}]{{getType $ic .Name .Typ.Elem}}{}
+ {{end}}
+ if tok != fflib.FFTok_null {
+ wantVal := true
+
+ idx := 0
+ for {
+ {{$ptr := false}}
+ {{$tmpVar := getTmpVarFor .Name}}
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{$ptr := true}}
+ var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
+ {{else}}
+ var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
+ {{end}}
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_brace {
+ break
+ }
+
+ if tok == fflib.FFTok_comma {
+ if wantVal == true {
+ // TODO(pquerna): this isn't an ideal error message, this handles
+ // things like [,,,] as an array value.
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+ }
+ continue
+ } else {
+ wantVal = true
+ }
+
+ {{handleField .IC $tmpVar .Typ.Elem $ptr false}}
+
+ // Standard json.Unmarshal ignores elements out of array bounds,
+ // that what we do as well.
+ if idx < {{.Typ.Len}} {
+ {{.Name}}[idx] = {{$tmpVar}}
+ idx++
+ }
+
+ wantVal = false
+ }
+ }
+}
+`
+
+var handleSliceTxt = `
+{
+ {{$ic := .IC}}
+ {{getAllowTokens .Typ.Name "FFTok_left_brace" "FFTok_null"}}
+ if tok == fflib.FFTok_null {
+ {{.Name}} = nil
+ } else {
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{if eq .IsPtr true}}
+ {{.Name}} = &[]*{{getType $ic .Name .Typ.Elem.Elem}}{}
+ {{else}}
+ {{.Name}} = []*{{getType $ic .Name .Typ.Elem.Elem}}{}
+ {{end}}
+ {{else}}
+ {{if eq .IsPtr true}}
+ {{.Name}} = &[]{{getType $ic .Name .Typ.Elem}}{}
+ {{else}}
+ {{.Name}} = []{{getType $ic .Name .Typ.Elem}}{}
+ {{end}}
+ {{end}}
+
+ wantVal := true
+
+ for {
+ {{$ptr := false}}
+ {{$tmpVar := getTmpVarFor .Name}}
+ {{if eq .Typ.Elem.Kind .Ptr }}
+ {{$ptr := true}}
+ var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
+ {{else}}
+ var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
+ {{end}}
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_brace {
+ break
+ }
+
+ if tok == fflib.FFTok_comma {
+ if wantVal == true {
+ // TODO(pquerna): this isn't an ideal error message, this handles
+ // things like [,,,] as an array value.
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+ }
+ continue
+ } else {
+ wantVal = true
+ }
+
+ {{handleField .IC $tmpVar .Typ.Elem $ptr false}}
+ {{if eq .IsPtr true}}
+ *{{.Name}} = append(*{{.Name}}, {{$tmpVar}})
+ {{else}}
+ {{.Name}} = append({{.Name}}, {{$tmpVar}})
+ {{end}}
+ wantVal = false
+ }
+ }
+}
+`
+
+var handleByteSliceTxt = `
+{
+ {{getAllowTokens .Typ.Name "FFTok_string" "FFTok_null"}}
+ if tok == fflib.FFTok_null {
+ {{.Name}} = nil
+ } else {
+ b := make([]byte, base64.StdEncoding.DecodedLen(fs.Output.Len()))
+ n, err := base64.StdEncoding.Decode(b, fs.Output.Bytes())
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ {{if eq .UseReflectToSet true}}
+ v := reflect.ValueOf(&{{.Name}}).Elem()
+ v.SetBytes(b[0:n])
+ {{else}}
+ {{.Name}} = append([]byte(), b[0:n]...)
+ {{end}}
+ }
+}
+`
+
+type handleBool struct {
+ Name string
+ Typ reflect.Type
+ TakeAddr bool
+}
+
+var handleBoolTxt = `
+{
+ if tok == fflib.FFTok_null {
+ {{if eq .TakeAddr true}}
+ {{.Name}} = nil
+ {{end}}
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ {{if eq .TakeAddr true}}
+ var tval bool
+ {{end}}
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+ {{if eq .TakeAddr true}}
+ tval = true
+ {{else}}
+ {{.Name}} = true
+ {{end}}
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+ {{if eq .TakeAddr true}}
+ tval = false
+ {{else}}
+ {{.Name}} = false
+ {{end}}
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ {{if eq .TakeAddr true}}
+ {{.Name}} = &tval
+ {{end}}
+ }
+}
+`
+
+type handlePtr struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ Quoted bool
+}
+
+var handlePtrTxt = `
+{
+ {{$ic := .IC}}
+
+ if tok == fflib.FFTok_null {
+ {{.Name}} = nil
+ } else {
+ if {{.Name}} == nil {
+ {{.Name}} = new({{getType $ic .Typ.Elem.Name .Typ.Elem}})
+ }
+
+ {{handleFieldAddr .IC .Name true .Typ.Elem false .Quoted}}
+ }
+}
+`
+
+type header struct {
+ IC *Inception
+ SI *StructInfo
+}
+
+var headerTxt = `
+const (
+ ffjt{{.SI.Name}}base = iota
+ ffjt{{.SI.Name}}nosuchkey
+ {{with $si := .SI}}
+ {{range $index, $field := $si.Fields}}
+ {{if ne $field.JsonName "-"}}
+ ffjt{{$si.Name}}{{$field.Name}}
+ {{end}}
+ {{end}}
+ {{end}}
+)
+
+{{with $si := .SI}}
+ {{range $index, $field := $si.Fields}}
+ {{if ne $field.JsonName "-"}}
+var ffjKey{{$si.Name}}{{$field.Name}} = []byte({{$field.JsonName}})
+ {{end}}
+ {{end}}
+{{end}}
+
+`
+
+type ujFunc struct {
+ IC *Inception
+ SI *StructInfo
+ ValidValues []string
+ ResetFields bool
+}
+
+var ujFuncTxt = `
+{{$si := .SI}}
+{{$ic := .IC}}
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *{{.SI.Name}}) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *{{.SI.Name}}) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjt{{.SI.Name}}base
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+ {{if eq .ResetFields true}}
+ {{range $index, $field := $si.Fields}}
+ var ffjSet{{$si.Name}}{{$field.Name}} = false
+ {{end}}
+ {{end}}
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjt{{.SI.Name}}nosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+ {{range $byte, $fields := $si.FieldsByFirstByte}}
+ case '{{$byte}}':
+ {{range $index, $field := $fields}}
+ {{if ne $index 0 }}} else if {{else}}if {{end}} bytes.Equal(ffjKey{{$si.Name}}{{$field.Name}}, kn) {
+ currentKey = ffjt{{$si.Name}}{{$field.Name}}
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ {{end}} }
+ {{end}}
+ }
+ {{range $index, $field := $si.ReverseFields}}
+ if {{$field.FoldFuncName}}(ffjKey{{$si.Name}}{{$field.Name}}, kn) {
+ currentKey = ffjt{{$si.Name}}{{$field.Name}}
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+ {{end}}
+ currentKey = ffjt{{.SI.Name}}nosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if {{range $index, $v := .ValidValues}}{{if ne $index 0 }}||{{end}}tok == fflib.{{$v}}{{end}} {
+ switch currentKey {
+ {{range $index, $field := $si.Fields}}
+ case ffjt{{$si.Name}}{{$field.Name}}:
+ goto handle_{{$field.Name}}
+ {{end}}
+ case ffjt{{$si.Name}}nosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+{{range $index, $field := $si.Fields}}
+handle_{{$field.Name}}:
+ {{with $fieldName := $field.Name | printf "j.%s"}}
+ {{handleField $ic $fieldName $field.Typ $field.Pointer $field.ForceString}}
+ {{if eq $.ResetFields true}}
+ ffjSet{{$si.Name}}{{$field.Name}} = true
+ {{end}}
+ state = fflib.FFParse_after_value
+ goto mainparse
+ {{end}}
+{{end}}
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+{{if eq .ResetFields true}}
+{{range $index, $field := $si.Fields}}
+ if !ffjSet{{$si.Name}}{{$field.Name}} {
+ {{with $fieldName := $field.Name | printf "j.%s"}}
+ {{if eq $field.Pointer true}}
+ {{$fieldName}} = nil
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Interface), 10) + `}}
+ {{$fieldName}} = nil
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Slice), 10) + `}}
+ {{$fieldName}} = nil
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Array), 10) + `}}
+ {{$fieldName}} = [{{$field.Typ.Len}}]{{getType $ic $fieldName $field.Typ.Elem}}{}
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Map), 10) + `}}
+ {{$fieldName}} = nil
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Bool), 10) + `}}
+ {{$fieldName}} = false
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.String), 10) + `}}
+ {{$fieldName}} = ""
+ {{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Struct), 10) + `}}
+ {{$fieldName}} = {{getType $ic $fieldName $field.Typ}}{}
+ {{else}}
+ {{$fieldName}} = {{getType $ic $fieldName $field.Typ}}(0)
+ {{end}}
+ {{end}}
+ }
+{{end}}
+{{end}}
+ return nil
+}
+`
+
+type handleUnmarshaler struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ Ptr reflect.Kind
+ TakeAddr bool
+ UnmarshalJSONFFLexer bool
+ Unmarshaler bool
+}
+
+var handleUnmarshalerTxt = `
+ {{$ic := .IC}}
+
+ {{if eq .UnmarshalJSONFFLexer true}}
+ {
+ if tok == fflib.FFTok_null {
+ {{if eq .Typ.Kind .Ptr }}
+ {{.Name}} = nil
+ {{end}}
+ {{if eq .TakeAddr true }}
+ {{.Name}} = nil
+ {{end}}
+ } else {
+ {{if eq .Typ.Kind .Ptr }}
+ if {{.Name}} == nil {
+ {{.Name}} = new({{getType $ic .Typ.Elem.Name .Typ.Elem}})
+ }
+ {{end}}
+ {{if eq .TakeAddr true }}
+ if {{.Name}} == nil {
+ {{.Name}} = new({{getType $ic .Typ.Name .Typ}})
+ }
+ {{end}}
+ err = {{.Name}}.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key)
+ if err != nil {
+ return err
+ }
+ }
+ state = fflib.FFParse_after_value
+ }
+ {{else}}
+ {{if eq .Unmarshaler true}}
+ {
+ if tok == fflib.FFTok_null {
+ {{if eq .TakeAddr true }}
+ {{.Name}} = nil
+ {{end}}
+ } else {
+
+ tbuf, err := fs.CaptureField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+
+ {{if eq .TakeAddr true }}
+ if {{.Name}} == nil {
+ {{.Name}} = new({{getType $ic .Typ.Name .Typ}})
+ }
+ {{end}}
+ err = {{.Name}}.UnmarshalJSON(tbuf)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ }
+ state = fflib.FFParse_after_value
+ }
+ {{end}}
+ {{end}}
+`
diff --git a/vendor/github.com/pquerna/ffjson/inception/encoder.go b/vendor/github.com/pquerna/ffjson/inception/encoder.go
new file mode 100644
index 000000000..3e37a2814
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/encoder.go
@@ -0,0 +1,544 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/pquerna/ffjson/shared"
+)
+
+func typeInInception(ic *Inception, typ reflect.Type, f shared.Feature) bool {
+ for _, v := range ic.objs {
+ if v.Typ == typ {
+ return v.Options.HasFeature(f)
+ }
+ if typ.Kind() == reflect.Ptr {
+ if v.Typ == typ.Elem() {
+ return v.Options.HasFeature(f)
+ }
+ }
+ }
+
+ return false
+}
+
+func getOmitEmpty(ic *Inception, sf *StructField) string {
+ ptname := "j." + sf.Name
+ if sf.Pointer {
+ ptname = "*" + ptname
+ return "if true {\n"
+ }
+ switch sf.Typ.Kind() {
+
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return "if len(" + ptname + ") != 0 {" + "\n"
+
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Uintptr,
+ reflect.Float32,
+ reflect.Float64:
+ return "if " + ptname + " != 0 {" + "\n"
+
+ case reflect.Bool:
+ return "if " + ptname + " != false {" + "\n"
+
+ case reflect.Interface, reflect.Ptr:
+ return "if " + ptname + " != nil {" + "\n"
+
+ default:
+ // TODO(pquerna): fix types
+ return "if true {" + "\n"
+ }
+}
+
+func getMapValue(ic *Inception, name string, typ reflect.Type, ptr bool, forceString bool) string {
+ var out = ""
+
+ if typ.Key().Kind() != reflect.String {
+ out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind())
+ out += ic.q.Flush()
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ return out
+ }
+
+ var elemKind reflect.Kind
+ elemKind = typ.Elem().Kind()
+
+ switch elemKind {
+ case reflect.String,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
+ reflect.Float32,
+ reflect.Float64,
+ reflect.Bool:
+
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+
+ out += "if " + name + " == nil {" + "\n"
+ ic.q.Write("null")
+ out += ic.q.GetQueued()
+ ic.q.DeleteLast()
+ out += "} else {" + "\n"
+ out += ic.q.WriteFlush("{ ")
+ out += " for key, value := range " + name + " {" + "\n"
+ out += " fflib.WriteJsonString(buf, key)" + "\n"
+ out += " buf.WriteString(`:`)" + "\n"
+ out += getGetInnerValue(ic, "value", typ.Elem(), false, forceString)
+ out += " buf.WriteByte(',')" + "\n"
+ out += " }" + "\n"
+ out += "buf.Rewind(1)" + "\n"
+ out += ic.q.WriteFlush("}")
+ out += "}" + "\n"
+
+ default:
+ out += ic.q.Flush()
+ out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind())
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ }
+ return out
+}
+
+func getGetInnerValue(ic *Inception, name string, typ reflect.Type, ptr bool, forceString bool) string {
+ var out = ""
+
+ // Flush if not bool or maps
+ if typ.Kind() != reflect.Bool && typ.Kind() != reflect.Map && typ.Kind() != reflect.Struct {
+ out += ic.q.Flush()
+ }
+
+ if typ.Implements(marshalerFasterType) ||
+ reflect.PtrTo(typ).Implements(marshalerFasterType) ||
+ typeInInception(ic, typ, shared.MustEncoder) ||
+ typ.Implements(marshalerType) ||
+ reflect.PtrTo(typ).Implements(marshalerType) {
+
+ out += ic.q.Flush()
+ out += tplStr(encodeTpl["handleMarshaler"], handleMarshaler{
+ IC: ic,
+ Name: name,
+ Typ: typ,
+ Ptr: reflect.Ptr,
+ MarshalJSONBuf: typ.Implements(marshalerFasterType) || reflect.PtrTo(typ).Implements(marshalerFasterType) || typeInInception(ic, typ, shared.MustEncoder),
+ Marshaler: typ.Implements(marshalerType) || reflect.PtrTo(typ).Implements(marshalerType),
+ })
+ return out
+ }
+
+ ptname := name
+ if ptr {
+ ptname = "*" + name
+ }
+
+ switch typ.Kind() {
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64:
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ out += "fflib.FormatBits2(buf, uint64(" + ptname + "), 10, " + ptname + " < 0)" + "\n"
+ case reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Uintptr:
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ out += "fflib.FormatBits2(buf, uint64(" + ptname + "), 10, false)" + "\n"
+ case reflect.Float32:
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ out += "fflib.AppendFloat(buf, float64(" + ptname + "), 'g', -1, 32)" + "\n"
+ case reflect.Float64:
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ out += "fflib.AppendFloat(buf, float64(" + ptname + "), 'g', -1, 64)" + "\n"
+ case reflect.Array,
+ reflect.Slice:
+
+ // Arrays cannot be nil
+ if typ.Kind() != reflect.Array {
+ out += "if " + name + "!= nil {" + "\n"
+ }
+ // Array and slice values encode as JSON arrays, except that
+ // []byte encodes as a base64-encoded string, and a nil slice
+ // encodes as the null JSON object.
+ if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
+ ic.OutputImports[`"encoding/base64"`] = true
+
+ out += "buf.WriteString(`\"`)" + "\n"
+ out += `{` + "\n"
+ out += `enc := base64.NewEncoder(base64.StdEncoding, buf)` + "\n"
+ if typ.Elem().Name() != "byte" {
+ ic.OutputImports[`"reflect"`] = true
+ out += `enc.Write(reflect.Indirect(reflect.ValueOf(` + ptname + `)).Bytes())` + "\n"
+
+ } else {
+ out += `enc.Write(` + ptname + `)` + "\n"
+ }
+ out += `enc.Close()` + "\n"
+ out += `}` + "\n"
+ out += "buf.WriteString(`\"`)" + "\n"
+ } else {
+ out += "buf.WriteString(`[`)" + "\n"
+ out += "for i, v := range " + ptname + "{" + "\n"
+ out += "if i != 0 {" + "\n"
+ out += "buf.WriteString(`,`)" + "\n"
+ out += "}" + "\n"
+ out += getGetInnerValue(ic, "v", typ.Elem(), false, false)
+ out += "}" + "\n"
+ out += "buf.WriteString(`]`)" + "\n"
+ }
+ if typ.Kind() != reflect.Array {
+ out += "} else {" + "\n"
+ out += "buf.WriteString(`null`)" + "\n"
+ out += "}" + "\n"
+ }
+ case reflect.String:
+ // Is it a json.Number?
+ if typ.PkgPath() == "encoding/json" && typ.Name() == "Number" {
+ // Fall back to json package to rely on the valid number check.
+ // See: https://github.com/golang/go/blob/92cd6e3af9f423ab4d8ac78f24e7fd81c31a8ce6/src/encoding/json/encode.go#L550
+ out += fmt.Sprintf("/* json.Number */\n")
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ } else {
+ ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
+ if forceString {
+ // Forcestring on strings does double-escaping of the entire value.
+ // We create a temporary buffer, encode to that an re-encode it.
+ out += "{" + "\n"
+ out += "tmpbuf := fflib.Buffer{}" + "\n"
+ out += "tmpbuf.Grow(len(" + ptname + ") + 16)" + "\n"
+ out += "fflib.WriteJsonString(&tmpbuf, string(" + ptname + "))" + "\n"
+ out += "fflib.WriteJsonString(buf, string( tmpbuf.Bytes() " + `))` + "\n"
+ out += "}" + "\n"
+ } else {
+ out += "fflib.WriteJsonString(buf, string(" + ptname + "))" + "\n"
+ }
+ }
+ case reflect.Ptr:
+ out += "if " + name + "!= nil {" + "\n"
+ switch typ.Elem().Kind() {
+ case reflect.Struct:
+ out += getGetInnerValue(ic, name, typ.Elem(), false, false)
+ default:
+ out += getGetInnerValue(ic, "*"+name, typ.Elem(), false, false)
+ }
+ out += "} else {" + "\n"
+ out += "buf.WriteString(`null`)" + "\n"
+ out += "}" + "\n"
+ case reflect.Bool:
+ out += "if " + ptname + " {" + "\n"
+ ic.q.Write("true")
+ out += ic.q.GetQueued()
+ out += "} else {" + "\n"
+ // Delete 'true'
+ ic.q.DeleteLast()
+ out += ic.q.WriteFlush("false")
+ out += "}" + "\n"
+ case reflect.Interface:
+ out += fmt.Sprintf("/* Interface types must use runtime reflection. type=%v kind=%v */\n", typ, typ.Kind())
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ case reflect.Map:
+ out += getMapValue(ic, ptname, typ, ptr, forceString)
+ case reflect.Struct:
+ if typ.Name() == "" {
+ ic.q.Write("{")
+ ic.q.Write(" ")
+ out += fmt.Sprintf("/* Inline struct. type=%v kind=%v */\n", typ, typ.Kind())
+ newV := reflect.Indirect(reflect.New(typ)).Interface()
+ fields := extractFields(newV)
+
+ // Output all fields
+ for _, field := range fields {
+ // Adjust field name
+ field.Name = name + "." + field.Name
+ out += getField(ic, field, "")
+ }
+
+ if lastConditional(fields) {
+ out += ic.q.Flush()
+ out += `buf.Rewind(1)` + "\n"
+ } else {
+ ic.q.DeleteLast()
+ }
+ out += ic.q.WriteFlush("}")
+ } else {
+ out += fmt.Sprintf("/* Struct fall back. type=%v kind=%v */\n", typ, typ.Kind())
+ out += ic.q.Flush()
+ if ptr {
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ } else {
+ // We send pointer to avoid copying entire struct
+ out += "err = buf.Encode(&" + name + ")" + "\n"
+ }
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ }
+ default:
+ out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind())
+ out += "err = buf.Encode(" + name + ")" + "\n"
+ out += "if err != nil {" + "\n"
+ out += " return err" + "\n"
+ out += "}" + "\n"
+ }
+
+ return out
+}
+
+func getValue(ic *Inception, sf *StructField, prefix string) string {
+ closequote := false
+ if sf.ForceString {
+ switch sf.Typ.Kind() {
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Uintptr,
+ reflect.Float32,
+ reflect.Float64,
+ reflect.Bool:
+ ic.q.Write(`"`)
+ closequote = true
+ }
+ }
+ out := getGetInnerValue(ic, prefix+sf.Name, sf.Typ, sf.Pointer, sf.ForceString)
+ if closequote {
+ if sf.Pointer {
+ out += ic.q.WriteFlush(`"`)
+ } else {
+ ic.q.Write(`"`)
+ }
+ }
+
+ return out
+}
+
+func p2(v uint32) uint32 {
+ v--
+ v |= v >> 1
+ v |= v >> 2
+ v |= v >> 4
+ v |= v >> 8
+ v |= v >> 16
+ v++
+ return v
+}
+
+func getTypeSize(t reflect.Type) uint32 {
+ switch t.Kind() {
+ case reflect.String:
+ // TODO: consider runtime analysis.
+ return 32
+ case reflect.Array, reflect.Map, reflect.Slice:
+ // TODO: consider runtime analysis.
+ return 4 * getTypeSize(t.Elem())
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32:
+ return 8
+ case reflect.Int64,
+ reflect.Uint64,
+ reflect.Uintptr:
+ return 16
+ case reflect.Float32,
+ reflect.Float64:
+ return 16
+ case reflect.Bool:
+ return 4
+ case reflect.Ptr:
+ return getTypeSize(t.Elem())
+ default:
+ return 16
+ }
+}
+
+func getTotalSize(si *StructInfo) uint32 {
+ rv := uint32(si.Typ.Size())
+ for _, f := range si.Fields {
+ rv += getTypeSize(f.Typ)
+ }
+ return rv
+}
+
+func getBufGrowSize(si *StructInfo) uint32 {
+
+ // TOOD(pquerna): automatically calc a better grow size based on history
+ // of a struct.
+ return p2(getTotalSize(si))
+}
+
+func isIntish(t reflect.Type) bool {
+ if t.Kind() >= reflect.Int && t.Kind() <= reflect.Uintptr {
+ return true
+ }
+ if t.Kind() == reflect.Array || t.Kind() == reflect.Slice || t.Kind() == reflect.Ptr {
+ if t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
+ // base64 special case.
+ return false
+ } else {
+ return isIntish(t.Elem())
+ }
+ }
+ return false
+}
+
+func getField(ic *Inception, f *StructField, prefix string) string {
+ out := ""
+ if f.OmitEmpty {
+ out += ic.q.Flush()
+ if f.Pointer {
+ out += "if " + prefix + f.Name + " != nil {" + "\n"
+ }
+ out += getOmitEmpty(ic, f)
+ }
+
+ if f.Pointer && !f.OmitEmpty {
+ // Pointer values encode as the value pointed to. A nil pointer encodes as the null JSON object.
+ out += "if " + prefix + f.Name + " != nil {" + "\n"
+ }
+
+ // JsonName is already escaped and quoted.
+ // getInnervalue should flush
+ ic.q.Write(f.JsonName + ":")
+ // We save a copy in case we need it
+ t := ic.q
+
+ out += getValue(ic, f, prefix)
+ ic.q.Write(",")
+
+ if f.Pointer && !f.OmitEmpty {
+ out += "} else {" + "\n"
+ out += t.WriteFlush("null")
+ out += "}" + "\n"
+ }
+
+ if f.OmitEmpty {
+ out += ic.q.Flush()
+ if f.Pointer {
+ out += "}" + "\n"
+ }
+ out += "}" + "\n"
+ }
+ return out
+}
+
+// We check if the last field is conditional.
+func lastConditional(fields []*StructField) bool {
+ if len(fields) > 0 {
+ f := fields[len(fields)-1]
+ return f.OmitEmpty
+ }
+ return false
+}
+
+func CreateMarshalJSON(ic *Inception, si *StructInfo) error {
+ conditionalWrites := lastConditional(si.Fields)
+ out := ""
+
+ out += "// MarshalJSON marshal bytes to json - template\n"
+ out += `func (j *` + si.Name + `) MarshalJSON() ([]byte, error) {` + "\n"
+ out += `var buf fflib.Buffer` + "\n"
+
+ out += `if j == nil {` + "\n"
+ out += ` buf.WriteString("null")` + "\n"
+ out += " return buf.Bytes(), nil" + "\n"
+ out += `}` + "\n"
+
+ out += `err := j.MarshalJSONBuf(&buf)` + "\n"
+ out += `if err != nil {` + "\n"
+ out += " return nil, err" + "\n"
+ out += `}` + "\n"
+ out += `return buf.Bytes(), nil` + "\n"
+ out += `}` + "\n"
+
+ out += "// MarshalJSONBuf marshal buff to json - template\n"
+ out += `func (j *` + si.Name + `) MarshalJSONBuf(buf fflib.EncodingBuffer) (error) {` + "\n"
+ out += ` if j == nil {` + "\n"
+ out += ` buf.WriteString("null")` + "\n"
+ out += " return nil" + "\n"
+ out += ` }` + "\n"
+
+ out += `var err error` + "\n"
+ out += `var obj []byte` + "\n"
+ out += `_ = obj` + "\n"
+ out += `_ = err` + "\n"
+
+ ic.q.Write("{")
+
+ // The extra space is inserted here.
+ // If nothing is written to the field this will be deleted
+ // instead of the last comma.
+ if conditionalWrites || len(si.Fields) == 0 {
+ ic.q.Write(" ")
+ }
+
+ for _, f := range si.Fields {
+ out += getField(ic, f, "j.")
+ }
+
+ // Handling the last comma is tricky.
+ // If the last field has omitempty, conditionalWrites is set.
+ // If something has been written, we delete the last comma,
+ // by backing up the buffer, otherwise it will delete a space.
+ if conditionalWrites {
+ out += ic.q.Flush()
+ out += `buf.Rewind(1)` + "\n"
+ } else {
+ ic.q.DeleteLast()
+ }
+
+ out += ic.q.WriteFlush("}")
+ out += `return nil` + "\n"
+ out += `}` + "\n"
+ ic.OutputFuncs = append(ic.OutputFuncs, out)
+ return nil
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/encoder_tpl.go b/vendor/github.com/pquerna/ffjson/inception/encoder_tpl.go
new file mode 100644
index 000000000..22ab5292e
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/encoder_tpl.go
@@ -0,0 +1,73 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "reflect"
+ "text/template"
+)
+
+var encodeTpl map[string]*template.Template
+
+func init() {
+ encodeTpl = make(map[string]*template.Template)
+
+ funcs := map[string]string{
+ "handleMarshaler": handleMarshalerTxt,
+ }
+ tplFuncs := template.FuncMap{}
+
+ for k, v := range funcs {
+ encodeTpl[k] = template.Must(template.New(k).Funcs(tplFuncs).Parse(v))
+ }
+}
+
+type handleMarshaler struct {
+ IC *Inception
+ Name string
+ Typ reflect.Type
+ Ptr reflect.Kind
+ MarshalJSONBuf bool
+ Marshaler bool
+}
+
+var handleMarshalerTxt = `
+ {
+ {{if eq .Typ.Kind .Ptr}}
+ if {{.Name}} == nil {
+ buf.WriteString("null")
+ } else {
+ {{end}}
+
+ {{if eq .MarshalJSONBuf true}}
+ err = {{.Name}}.MarshalJSONBuf(buf)
+ if err != nil {
+ return err
+ }
+ {{else if eq .Marshaler true}}
+ obj, err = {{.Name}}.MarshalJSON()
+ if err != nil {
+ return err
+ }
+ buf.Write(obj)
+ {{end}}
+ {{if eq .Typ.Kind .Ptr}}
+ }
+ {{end}}
+ }
+`
diff --git a/vendor/github.com/pquerna/ffjson/inception/inception.go b/vendor/github.com/pquerna/ffjson/inception/inception.go
new file mode 100644
index 000000000..10cb2712c
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/inception.go
@@ -0,0 +1,160 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "errors"
+ "fmt"
+ "github.com/pquerna/ffjson/shared"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "sort"
+)
+
+type Inception struct {
+ objs []*StructInfo
+ InputPath string
+ OutputPath string
+ PackageName string
+ PackagePath string
+ OutputImports map[string]bool
+ OutputFuncs []string
+ q ConditionalWrite
+ ResetFields bool
+}
+
+func NewInception(inputPath string, packageName string, outputPath string, resetFields bool) *Inception {
+ return &Inception{
+ objs: make([]*StructInfo, 0),
+ InputPath: inputPath,
+ OutputPath: outputPath,
+ PackageName: packageName,
+ OutputFuncs: make([]string, 0),
+ OutputImports: make(map[string]bool),
+ ResetFields: resetFields,
+ }
+}
+
+func (i *Inception) AddMany(objs []shared.InceptionType) {
+ for _, obj := range objs {
+ i.Add(obj)
+ }
+}
+
+func (i *Inception) Add(obj shared.InceptionType) {
+ i.objs = append(i.objs, NewStructInfo(obj))
+ i.PackagePath = i.objs[0].Typ.PkgPath()
+}
+
+func (i *Inception) wantUnmarshal(si *StructInfo) bool {
+ if si.Options.SkipDecoder {
+ return false
+ }
+ typ := si.Typ
+ umlx := typ.Implements(unmarshalFasterType) || reflect.PtrTo(typ).Implements(unmarshalFasterType)
+ umlstd := typ.Implements(unmarshalerType) || reflect.PtrTo(typ).Implements(unmarshalerType)
+ if umlstd && !umlx {
+ // structure has UnmarshalJSON, but not our faster version -- skip it.
+ return false
+ }
+ return true
+}
+
+func (i *Inception) wantMarshal(si *StructInfo) bool {
+ if si.Options.SkipEncoder {
+ return false
+ }
+ typ := si.Typ
+ mlx := typ.Implements(marshalerFasterType) || reflect.PtrTo(typ).Implements(marshalerFasterType)
+ mlstd := typ.Implements(marshalerType) || reflect.PtrTo(typ).Implements(marshalerType)
+ if mlstd && !mlx {
+ // structure has MarshalJSON, but not our faster version -- skip it.
+ return false
+ }
+ return true
+}
+
+type sortedStructs []*StructInfo
+
+func (p sortedStructs) Len() int { return len(p) }
+func (p sortedStructs) Less(i, j int) bool { return p[i].Name < p[j].Name }
+func (p sortedStructs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortedStructs) Sort() { sort.Sort(p) }
+
+func (i *Inception) generateCode() error {
+ // We sort the structs by name, so output if predictable.
+ sorted := sortedStructs(i.objs)
+ sorted.Sort()
+
+ for _, si := range sorted {
+ if i.wantMarshal(si) {
+ err := CreateMarshalJSON(i, si)
+ if err != nil {
+ return err
+ }
+ }
+
+ if i.wantUnmarshal(si) {
+ err := CreateUnmarshalJSON(i, si)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (i *Inception) handleError(err error) {
+ fmt.Fprintf(os.Stderr, "Error: %s:\n\n", err)
+ os.Exit(1)
+}
+
+func (i *Inception) Execute() {
+ if len(os.Args) != 1 {
+ i.handleError(errors.New(fmt.Sprintf("Internal ffjson error: inception executable takes no args: %v", os.Args)))
+ return
+ }
+
+ err := i.generateCode()
+ if err != nil {
+ i.handleError(err)
+ return
+ }
+
+ data, err := RenderTemplate(i)
+ if err != nil {
+ i.handleError(err)
+ return
+ }
+
+ stat, err := os.Stat(i.InputPath)
+
+ if err != nil {
+ i.handleError(err)
+ return
+ }
+
+ err = ioutil.WriteFile(i.OutputPath, data, stat.Mode())
+
+ if err != nil {
+ i.handleError(err)
+ return
+ }
+
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/reflect.go b/vendor/github.com/pquerna/ffjson/inception/reflect.go
new file mode 100644
index 000000000..8fb0bd5cb
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/reflect.go
@@ -0,0 +1,290 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ fflib "github.com/pquerna/ffjson/fflib/v1"
+ "github.com/pquerna/ffjson/shared"
+
+ "bytes"
+ "encoding/json"
+ "reflect"
+ "unicode/utf8"
+)
+
+type StructField struct {
+ Name string
+ JsonName string
+ FoldFuncName string
+ Typ reflect.Type
+ OmitEmpty bool
+ ForceString bool
+ HasMarshalJSON bool
+ HasUnmarshalJSON bool
+ Pointer bool
+ Tagged bool
+}
+
+type FieldByJsonName []*StructField
+
+func (a FieldByJsonName) Len() int { return len(a) }
+func (a FieldByJsonName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a FieldByJsonName) Less(i, j int) bool { return a[i].JsonName < a[j].JsonName }
+
+type StructInfo struct {
+ Name string
+ Obj interface{}
+ Typ reflect.Type
+ Fields []*StructField
+ Options shared.StructOptions
+}
+
+func NewStructInfo(obj shared.InceptionType) *StructInfo {
+ t := reflect.TypeOf(obj.Obj)
+ return &StructInfo{
+ Obj: obj.Obj,
+ Name: t.Name(),
+ Typ: t,
+ Fields: extractFields(obj.Obj),
+ Options: obj.Options,
+ }
+}
+
+func (si *StructInfo) FieldsByFirstByte() map[string][]*StructField {
+ rv := make(map[string][]*StructField)
+ for _, f := range si.Fields {
+ b := string(f.JsonName[1])
+ rv[b] = append(rv[b], f)
+ }
+ return rv
+}
+
+func (si *StructInfo) ReverseFields() []*StructField {
+ var i int
+ rv := make([]*StructField, 0)
+ for i = len(si.Fields) - 1; i >= 0; i-- {
+ rv = append(rv, si.Fields[i])
+ }
+ return rv
+}
+
+const (
+ caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
+)
+
+func foldFunc(key []byte) string {
+ nonLetter := false
+ special := false // special letter
+ for _, b := range key {
+ if b >= utf8.RuneSelf {
+ return "bytes.EqualFold"
+ }
+ upper := b & caseMask
+ if upper < 'A' || upper > 'Z' {
+ nonLetter = true
+ } else if upper == 'K' || upper == 'S' {
+ // See above for why these letters are special.
+ special = true
+ }
+ }
+ if special {
+ return "fflib.EqualFoldRight"
+ }
+ if nonLetter {
+ return "fflib.AsciiEqualFold"
+ }
+ return "fflib.SimpleLetterEqualFold"
+}
+
+type MarshalerFaster interface {
+ MarshalJSONBuf(buf fflib.EncodingBuffer) error
+}
+
+type UnmarshalFaster interface {
+ UnmarshalJSONFFLexer(l *fflib.FFLexer, state fflib.FFParseState) error
+}
+
+var marshalerType = reflect.TypeOf(new(json.Marshaler)).Elem()
+var marshalerFasterType = reflect.TypeOf(new(MarshalerFaster)).Elem()
+var unmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem()
+var unmarshalFasterType = reflect.TypeOf(new(UnmarshalFaster)).Elem()
+
+// extractFields returns a list of fields that JSON should recognize for the given type.
+// The algorithm is breadth-first search over the set of structs to include - the top struct
+// and then any reachable anonymous structs.
+func extractFields(obj interface{}) []*StructField {
+ t := reflect.TypeOf(obj)
+ // Anonymous fields to explore at the current level and the next.
+ current := []StructField{}
+ next := []StructField{{Typ: t}}
+
+ // Count of queued names for current level and the next.
+ count := map[reflect.Type]int{}
+ nextCount := map[reflect.Type]int{}
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []*StructField
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
+
+ for _, f := range current {
+ if visited[f.Typ] {
+ continue
+ }
+ visited[f.Typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.Typ.NumField(); i++ {
+ sf := f.Typ.Field(i)
+ if sf.PkgPath != "" { // unexported
+ continue
+ }
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ continue
+ }
+ name, opts := parseTag(tag)
+ if !isValidTag(name) {
+ name = ""
+ }
+
+ ft := sf.Type
+ ptr := false
+ if ft.Kind() == reflect.Ptr {
+ ptr = true
+ }
+
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := name != ""
+ if name == "" {
+ name = sf.Name
+ }
+
+ var buf bytes.Buffer
+ fflib.WriteJsonString(&buf, name)
+
+ field := &StructField{
+ Name: sf.Name,
+ JsonName: string(buf.Bytes()),
+ FoldFuncName: foldFunc([]byte(name)),
+ Typ: ft,
+ HasMarshalJSON: ft.Implements(marshalerType),
+ HasUnmarshalJSON: ft.Implements(unmarshalerType),
+ OmitEmpty: opts.Contains("omitempty"),
+ ForceString: opts.Contains("string"),
+ Pointer: ptr,
+ Tagged: tagged,
+ }
+
+ fields = append(fields, field)
+
+ if count[f.Typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ next = append(next, StructField{
+ Name: ft.Name(),
+ Typ: ft,
+ })
+ }
+ }
+ }
+ }
+
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with JSON tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
+ out := fields[:0]
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.JsonName
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.JsonName != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
+ continue
+ }
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
+ }
+ }
+
+ fields = out
+
+ return fields
+}
+
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// JSON tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []*StructField) (*StructField, bool) {
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if f.Tagged {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return nil, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return nil, false
+ }
+ return fields[0], true
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/tags.go b/vendor/github.com/pquerna/ffjson/inception/tags.go
new file mode 100644
index 000000000..ccce101b8
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/tags.go
@@ -0,0 +1,79 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "strings"
+ "unicode"
+)
+
+// from: http://golang.org/src/pkg/encoding/json/tags.go
+
+// tagOptions is the string following a comma in a struct field's "json"
+// tag, or the empty string. It does not include the leading comma.
+type tagOptions string
+
+// parseTag splits a struct field's json tag into its name and
+// comma-separated options.
+func parseTag(tag string) (string, tagOptions) {
+ if idx := strings.Index(tag, ","); idx != -1 {
+ return tag[:idx], tagOptions(tag[idx+1:])
+ }
+ return tag, tagOptions("")
+}
+
+// Contains reports whether a comma-separated list of options
+// contains a particular substr flag. substr must be surrounded by a
+// string boundary or commas.
+func (o tagOptions) Contains(optionName string) bool {
+ if len(o) == 0 {
+ return false
+ }
+ s := string(o)
+ for s != "" {
+ var next string
+ i := strings.Index(s, ",")
+ if i >= 0 {
+ s, next = s[:i], s[i+1:]
+ }
+ if s == optionName {
+ return true
+ }
+ s = next
+ }
+ return false
+}
+
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ switch {
+ case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
+ // Backslash and quote chars are reserved, but
+ // otherwise any punctuation chars are allowed
+ // in a tag name.
+ default:
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/template.go b/vendor/github.com/pquerna/ffjson/inception/template.go
new file mode 100644
index 000000000..121a23dd8
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/template.go
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2014 Paul Querna
+ *
+ * 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.
+ *
+ */
+
+package ffjsoninception
+
+import (
+ "bytes"
+ "go/format"
+ "text/template"
+)
+
+const ffjsonTemplate = `
+// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
+// source: {{.InputPath}}
+
+package {{.PackageName}}
+
+import (
+{{range $k, $v := .OutputImports}}{{$k}}
+{{end}}
+)
+
+{{range .OutputFuncs}}
+{{.}}
+{{end}}
+
+`
+
+func RenderTemplate(ic *Inception) ([]byte, error) {
+ t := template.Must(template.New("ffjson.go").Parse(ffjsonTemplate))
+ buf := new(bytes.Buffer)
+ err := t.Execute(buf, ic)
+ if err != nil {
+ return nil, err
+ }
+ return format.Source(buf.Bytes())
+}
+
+func tplStr(t *template.Template, data interface{}) string {
+ buf := bytes.Buffer{}
+ err := t.Execute(&buf, data)
+ if err != nil {
+ panic(err)
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/pquerna/ffjson/inception/writerstack.go b/vendor/github.com/pquerna/ffjson/inception/writerstack.go
new file mode 100644
index 000000000..1521961c9
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/inception/writerstack.go
@@ -0,0 +1,65 @@
+package ffjsoninception
+
+import "strings"
+
+// ConditionalWrite is a stack containing a number of pending writes
+type ConditionalWrite struct {
+ Queued []string
+}
+
+// Write will add a string to be written
+func (w *ConditionalWrite) Write(s string) {
+ w.Queued = append(w.Queued, s)
+}
+
+// DeleteLast will delete the last added write
+func (w *ConditionalWrite) DeleteLast() {
+ if len(w.Queued) == 0 {
+ return
+ }
+ w.Queued = w.Queued[:len(w.Queued)-1]
+}
+
+// Last will return the last added write
+func (w *ConditionalWrite) Last() string {
+ if len(w.Queued) == 0 {
+ return ""
+ }
+ return w.Queued[len(w.Queued)-1]
+}
+
+// Flush will return all queued writes, and return
+// "" (empty string) in nothing has been queued
+// "buf.WriteByte('" + byte + "')" + '\n' if one bute has been queued.
+// "buf.WriteString(`" + string + "`)" + "\n" if more than one byte has been queued.
+func (w *ConditionalWrite) Flush() string {
+ combined := strings.Join(w.Queued, "")
+ if len(combined) == 0 {
+ return ""
+ }
+
+ w.Queued = nil
+ if len(combined) == 1 {
+ return "buf.WriteByte('" + combined + "')" + "\n"
+ }
+ return "buf.WriteString(`" + combined + "`)" + "\n"
+}
+
+func (w *ConditionalWrite) FlushTo(out string) string {
+ out += w.Flush()
+ return out
+}
+
+// WriteFlush will add a string and return the Flush result for the queue
+func (w *ConditionalWrite) WriteFlush(s string) string {
+ w.Write(s)
+ return w.Flush()
+}
+
+// GetQueued will return the current queued content without flushing.
+func (w *ConditionalWrite) GetQueued() string {
+ t := w.Queued
+ s := w.Flush()
+ w.Queued = t
+ return s
+}
diff --git a/vendor/github.com/pquerna/ffjson/shared/options.go b/vendor/github.com/pquerna/ffjson/shared/options.go
new file mode 100644
index 000000000..d74edc135
--- /dev/null
+++ b/vendor/github.com/pquerna/ffjson/shared/options.go
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2014 Paul Querna, Klaus Post
+ *
+ * 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.
+ *
+ */
+
+package shared
+
+type StructOptions struct {
+ SkipDecoder bool
+ SkipEncoder bool
+}
+
+type InceptionType struct {
+ Obj interface{}
+ Options StructOptions
+}
+type Feature int
+
+const (
+ Nothing Feature = 0
+ MustDecoder = 1 << 1
+ MustEncoder = 1 << 2
+ MustEncDec = MustDecoder | MustEncoder
+)
+
+func (i InceptionType) HasFeature(f Feature) bool {
+ return i.HasFeature(f)
+}
+
+func (s StructOptions) HasFeature(f Feature) bool {
+ hasNeeded := true
+ if f&MustDecoder != 0 && s.SkipDecoder {
+ hasNeeded = false
+ }
+ if f&MustEncoder != 0 && s.SkipEncoder {
+ hasNeeded = false
+ }
+ return hasNeeded
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c02a64463..c4a410be6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -45,7 +45,7 @@ github.com/containernetworking/cni/pkg/version
github.com/containernetworking/cni/pkg/types/020
# github.com/containernetworking/plugins v0.8.1
github.com/containernetworking/plugins/pkg/ns
-# github.com/containers/buildah v1.9.2
+# github.com/containers/buildah v1.10.1
github.com/containers/buildah
github.com/containers/buildah/imagebuildah
github.com/containers/buildah/pkg/chrootuser
@@ -60,7 +60,7 @@ github.com/containers/buildah/docker
github.com/containers/buildah/pkg/blobcache
github.com/containers/buildah/pkg/overlay
github.com/containers/buildah/pkg/unshare
-# github.com/containers/image v2.0.1+incompatible
+# github.com/containers/image v3.0.2+incompatible
github.com/containers/image/directory
github.com/containers/image/docker
github.com/containers/image/docker/archive
@@ -79,12 +79,12 @@ github.com/containers/image/tarball
github.com/containers/image/pkg/sysregistriesv2
github.com/containers/image/image
github.com/containers/image/oci/layout
-github.com/containers/image/pkg/sysregistries
github.com/containers/image/directory/explicitfilepath
github.com/containers/image/docker/policyconfiguration
github.com/containers/image/pkg/blobinfocache/none
github.com/containers/image/pkg/tlsclientconfig
github.com/containers/image/pkg/strslice
+github.com/containers/image/pkg/keyctl
github.com/containers/image/version
github.com/containers/image/docker/daemon
github.com/containers/image/openshift
@@ -103,7 +103,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
github.com/containers/psgo/internal/host
-# github.com/containers/storage v1.12.16
+# github.com/containers/storage v1.13.2
github.com/containers/storage
github.com/containers/storage/pkg/archive
github.com/containers/storage/pkg/chrootarchive
@@ -172,8 +172,8 @@ github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory
github.com/docker/distribution/metrics
# github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16
-github.com/docker/docker/pkg/homedir
github.com/docker/docker/pkg/signal
+github.com/docker/docker/pkg/homedir
github.com/docker/docker/oci/caps
github.com/docker/docker/pkg/namesgenerator
github.com/docker/docker/pkg/term
@@ -365,7 +365,7 @@ github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/filepath
github.com/opencontainers/runtime-tools/specerror
github.com/opencontainers/runtime-tools/error
-# github.com/opencontainers/selinux v1.2.2
+# github.com/opencontainers/selinux v1.3.0
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/go-selinux
# github.com/openshift/imagebuilder v1.1.0
@@ -389,6 +389,8 @@ github.com/pkg/profile
github.com/pmezard/go-difflib/difflib
# github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/pquerna/ffjson/fflib/v1
+github.com/pquerna/ffjson/inception
+github.com/pquerna/ffjson/shared
github.com/pquerna/ffjson/fflib/v1/internal
# github.com/prometheus/client_golang v1.0.0
github.com/prometheus/client_golang/prometheus
@@ -451,9 +453,9 @@ github.com/varlink/go/varlink
github.com/varlink/go/cmd/varlink-go-interface-generator
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
github.com/vbatts/tar-split/tar/storage
-github.com/vbatts/tar-split/archive/tar
# github.com/vbauerster/mpb v3.4.0+incompatible
github.com/vbauerster/mpb
github.com/vbauerster/mpb/decor
diff --git a/version/version.go b/version/version.go
index 286f66093..f0823f260 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,7 +4,7 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "1.4.5-dev"
+const Version = "1.5.2-dev"
// RemoteAPIVersion is the version for the remote
// client API. It is used to determine compatibility